Skip to content

Commit

Permalink
feat: ban deposits client tests (#11504)
Browse files Browse the repository at this point in the history
* feat: first pass at some tests

* fix: removed check

* feat: added a few more tests

* feat: added final tests on spec

* fix: missguiding name

* fix: move gas limit comment to the constant definition

* feat: added qol hardfork config

* fix: remove return and revamped tests

* fix: missing test qol revamp
  • Loading branch information
skeletor-spaceman authored Aug 29, 2024
1 parent f2d8fb8 commit ccf505d
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 34 deletions.
48 changes: 48 additions & 0 deletions op-node/rollup/derive/attributes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,54 @@ func TestPreparePayloadAttributes(t *testing.T) {
require.Equal(t, l1InfoTx, []byte(attrs.Transactions[0]))
require.True(t, attrs.NoTxPool)
})
t.Run("same origin with deposits on post-Isthmus", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
l1Fetcher := &testutils.MockL1Source{}
defer l1Fetcher.AssertExpectations(t)
l2Parent := testutils.RandomL2BlockRef(rng)
l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t)
l1Info := testutils.RandomBlockInfo(rng)
l1Info.InfoParentHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number + 1

receipts, depositTxs, err := makeReceipts(rng, l1Info.InfoHash, cfg.DepositContractAddress, []receiptData{
{goodReceipt: true, DepositLogs: []bool{true, false}},
{goodReceipt: true, DepositLogs: []bool{true}},
{goodReceipt: false, DepositLogs: []bool{true}},
{goodReceipt: false, DepositLogs: []bool{false}},
})
require.NoError(t, err)
usedDepositTxs, err := encodeDeposits(depositTxs)
require.NoError(t, err)

// sets config to post-interop
cfg.AfterHardfork(rollup.Interop, 2)

epoch := l1Info.ID()
l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, 0, l1Info, 0)
require.NoError(t, err)

l2Txs := append(append(make([]eth.Data, 0), l1InfoTx), usedDepositTxs...)

l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, receipts, nil)
attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NoError(t, err)
require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao)
require.Equal(t, predeploys.SequencerFeeVaultAddr, attrs.SuggestedFeeRecipient)
require.Equal(t, len(l2Txs), len(attrs.Transactions), "Expected txs to equal l1 info tx + user deposit txs + DepositsComplete")
require.Equal(t, l2Txs, attrs.Transactions)
require.Equal(t, DepositsCompleteBytes4, attrs.Transactions[1+len(depositTxs)][:4])
require.True(t, attrs.NoTxPool)
depositsCompleteTx, err := DepositsCompleteBytes(l2Parent.SequenceNumber, l1Info)
require.NoError(t, err)
require.Equal(t, l2Txs, append(attrs.Transactions, depositsCompleteTx))
})

// Test that the payload attributes builder changes the deposit format based on L2-time-based regolith activation
t.Run("regolith", func(t *testing.T) {
testCases := []struct {
Expand Down
15 changes: 15 additions & 0 deletions op-node/rollup/derive/deposit_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package derive
import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -34,3 +35,17 @@ func TestEcotone4788ContractSourceHash(t *testing.T) {

assert.Equal(t, expected, actual.Hex())
}

// TestAfterForceIncludeSourceHash
// cast keccak $(cast concat-hex 0x0000000000000000000000000000000000000000000000000000000000000003 $(cast keccak 0x01))
// # 0x8afb1c4a581d0e71ab65334e3365ba5511fb15c13fa212776f9d4dafc6287845
func TestAfterForceIncludeSource(t *testing.T) {
source := AfterForceIncludeSource{
L1BlockHash: common.Hash{0x01},
}

actual := source.SourceHash()
expected := "0x8afb1c4a581d0e71ab65334e3365ba5511fb15c13fa212776f9d4dafc6287845"

assert.Equal(t, expected, actual.Hex())
}
17 changes: 14 additions & 3 deletions op-node/rollup/derive/fuzz_parsers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,26 @@ func FuzzL1InfoEcotoneRoundTrip(f *testing.F) {
}
enc, err := in.marshalBinaryEcotone()
if err != nil {
t.Fatalf("Failed to marshal binary: %v", err)
t.Fatalf("Failed to marshal Ecotone binary: %v", err)
}
var out L1BlockInfo
err = out.unmarshalBinaryEcotone(enc)
if err != nil {
t.Fatalf("Failed to unmarshal binary: %v", err)
t.Fatalf("Failed to unmarshal Ecotone binary: %v", err)
}
if !cmp.Equal(in, out, cmp.Comparer(testutils.BigEqual)) {
t.Fatalf("The data did not round trip correctly. in: %v. out: %v", in, out)
t.Fatalf("The Ecotone data did not round trip correctly. in: %v. out: %v", in, out)
}
enc, err = in.marshalBinaryIsthmus()
if err != nil {
t.Fatalf("Failed to marshal Isthmus binary: %v", err)
}
err = out.unmarshalBinaryIsthmus(enc)
if err != nil {
t.Fatalf("Failed to unmarshal Isthmus binary: %v", err)
}
if !cmp.Equal(in, out, cmp.Comparer(testutils.BigEqual)) {
t.Fatalf("The Isthmus data did not round trip correctly. in: %v. out: %v", in, out)
}

})
Expand Down
21 changes: 11 additions & 10 deletions op-node/rollup/derive/l1_block_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ const (
L1InfoBedrockLen = 4 + 32*L1InfoArguments
L1InfoEcotoneLen = 4 + 32*5 // after Ecotone upgrade, args are packed into 5 32-byte slots
DepositsCompleteLen = 4 // only the selector
// We set the gas limit to 15k to ensure that the DepositsComplete Transaction does not run out of gas.
// GasBenchMark_L1BlockIsthmus_DepositsComplete:test_depositsComplete_benchmark() (gas: 7768)
// GasBenchMark_L1BlockIsthmus_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5768)
// see `test_depositsComplete_benchmark` at: `/packages/contracts-bedrock/test/BenchmarkTest.t.sol`
DepositsCompleteGas = uint64(15_000)
)

var (
Expand Down Expand Up @@ -391,16 +396,12 @@ func DepositsCompleteDeposit(seqNumber uint64, block eth.BlockInfo) (*types.Depo
L1BlockHash: block.Hash(),
}
out := &types.DepositTx{
SourceHash: source.SourceHash(),
From: L1InfoDepositerAddress,
To: &L1BlockAddress,
Mint: nil,
Value: big.NewInt(0),
// We set the gas limit to 15k to ensure that the DepositsComplete Transaction does not run out of gas.
// GasBenchMark_L1BlockIsthmus_DepositsComplete:test_depositsComplete_benchmark() (gas: 7768)
// GasBenchMark_L1BlockIsthmus_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5768)
// see `test_depositsComplete_benchmark` at: `/packages/contracts-bedrock/test/BenchmarkTest.t.sol`
Gas: 15_000,
SourceHash: source.SourceHash(),
From: L1InfoDepositerAddress,
To: &L1BlockAddress,
Mint: nil,
Value: big.NewInt(0),
Gas: DepositsCompleteGas,
IsSystemTransaction: false,
Data: DepositsCompleteBytes4,
}
Expand Down
93 changes: 72 additions & 21 deletions op-node/rollup/derive/l1_block_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) {
randomSeqNr := func(rng *rand.Rand) uint64 {
return rng.Uint64()
}

// Go 1.18 will have native fuzzing for us to use, until then, we cover just the below cases
cases := []infoTest{
{"random", testutils.MakeBlockInfo(nil), randomL1Cfg, randomSeqNr},
Expand Down Expand Up @@ -109,10 +110,8 @@ func TestParseL1InfoDepositTxData(t *testing.T) {
t.Run("regolith", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
zero := uint64(0)
rollupCfg := rollup.Config{
RegolithTime: &zero,
}
rollupCfg := rollup.Config{}
rollupCfg.AtHardfork(rollup.Regolith)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 0)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
Expand All @@ -121,11 +120,8 @@ func TestParseL1InfoDepositTxData(t *testing.T) {
t.Run("ecotone", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
zero := uint64(0)
rollupCfg := rollup.Config{
RegolithTime: &zero,
EcotoneTime: &zero,
}
rollupCfg := rollup.Config{}
rollupCfg.AtHardfork(rollup.Ecotone)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 1)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
Expand All @@ -135,12 +131,8 @@ func TestParseL1InfoDepositTxData(t *testing.T) {
t.Run("first-block ecotone", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
zero := uint64(2)
rollupCfg := rollup.Config{
RegolithTime: &zero,
EcotoneTime: &zero,
BlockTime: 2,
}
rollupCfg := rollup.Config{}
rollupCfg.AfterHardfork(rollup.Ecotone, 2)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 2)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
Expand All @@ -150,16 +142,75 @@ func TestParseL1InfoDepositTxData(t *testing.T) {
t.Run("genesis-block ecotone", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
zero := uint64(0)
rollupCfg := rollup.Config{
RegolithTime: &zero,
EcotoneTime: &zero,
BlockTime: 2,
}
rollupCfg := rollup.Config{}
rollupCfg.AfterHardfork(rollup.Ecotone, 2)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 0)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas))
require.Equal(t, L1InfoEcotoneLen, len(depTx.Data))
})
t.Run("Isthmus", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
rollupCfg := rollup.Config{}
rollupCfg.AtHardfork(rollup.Interop)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 1)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas))
require.Equal(t, L1InfoEcotoneLen, len(depTx.Data))
require.Equal(t, L1InfoFuncEcotoneBytes4, depTx.Data[:4])
// should still send Ecotone signature since upgrade happens after deposits
})
t.Run("first-block isthmus", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
rollupCfg := rollup.Config{}
rollupCfg.AfterHardfork(rollup.Interop, 2)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 2)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas))
require.Equal(t, L1InfoBedrockLen, len(depTx.Data))
require.Equal(t, L1InfoFuncIsthmusBytes4, depTx.Data[:4])
})
t.Run("genesis-block isthmus", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
rollupCfg := rollup.Config{}
rollupCfg.AfterHardfork(rollup.Interop, 2)
depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 0)
require.NoError(t, err)
require.False(t, depTx.IsSystemTransaction)
require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas))
require.Equal(t, L1InfoEcotoneLen, len(depTx.Data))
require.Equal(t, L1InfoBedrockLen, len(depTx.Data))
})
}

func TestDepositsCompleteBytes(t *testing.T) {
randomSeqNr := func(rng *rand.Rand) uint64 {
return rng.Uint64()
}
t.Run("valid return bytes", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
depTxByes, err := DepositsCompleteBytes(randomSeqNr(rng), info)
require.NoError(t, err)
require.Equal(t, depTxByes, DepositsCompleteBytes4)
require.Equal(t, DepositsCompleteLen, len(depTxByes))
})
t.Run("valid return Transaction", func(t *testing.T) {
rng := rand.New(rand.NewSource(1234))
info := testutils.MakeBlockInfo(nil)(rng)
depTx, err := DepositsCompleteDeposit(randomSeqNr(rng), info)
require.NoError(t, err)
require.Equal(t, depTx.Data, DepositsCompleteBytes4)
require.Equal(t, DepositsCompleteLen, len(depTx.Data))
require.Equal(t, DepositsCompleteGas, depTx.Gas)
require.False(t, depTx.IsSystemTransaction)
require.Equal(t, depTx.Value, big.NewInt(0))
require.Equal(t, depTx.From, L1InfoDepositerAddress)
})
}
38 changes: 38 additions & 0 deletions op-node/rollup/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,44 @@ func (c *Config) IsInteropActivationBlock(l2BlockTime uint64) bool {
!c.IsInterop(l2BlockTime-c.BlockTime)
}

func (c *Config) AtHardfork(hardfork ForkName) {
zero := uint64(0)
// IMPORTANT! ordered from newest to oldest
switch hardfork {
case Interop:
c.InteropTime = &zero
fallthrough
case Holocene:
c.HoloceneTime = &zero
fallthrough
case Granite:
c.GraniteTime = &zero
fallthrough
case Fjord:
c.FjordTime = &zero
fallthrough
case Ecotone:
c.EcotoneTime = &zero
fallthrough
case Delta:
c.DeltaTime = &zero
fallthrough
case Canyon:
c.CanyonTime = &zero
fallthrough
case Regolith:
c.RegolithTime = &zero
fallthrough
case None:
break
}
}
func (c *Config) AfterHardfork(hardfork ForkName, timestamp uint64) {
c.AtHardfork(hardfork)
// required after hardfork time bump
c.BlockTime = timestamp
}

// ForkchoiceUpdatedVersion returns the EngineAPIMethod suitable for the chain hard fork version.
func (c *Config) ForkchoiceUpdatedVersion(attr *eth.PayloadAttributes) eth.EngineAPIMethod {
if attr == nil {
Expand Down

0 comments on commit ccf505d

Please sign in to comment.