Skip to content

Commit

Permalink
feat: ban deposits interop (#11712)
Browse files Browse the repository at this point in the history
* interop: disable interop messages in force-deposits

Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com>

* interop: clean up config helpers

* op-node: fix/improve L1 info tx tests

* op-node: fix attributes test

* op-node: fix sequence-number usage in post-interop system deposit, fix tests

* op-contracts: L1Block interop: fix diff, remove duplicate test from renaming

* contracts: update metadata

* contracts: fix build warnings

* contracts: fix interface build

* script: ignore

* lint: fix

* test: .testdata directory

* tests: fix revert

---------

Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com>
Co-authored-by: protolambda <proto@protolambda.com>
Co-authored-by: Mark Tyneway <mark.tyneway@gmail.com>
  • Loading branch information
4 people authored Sep 11, 2024
1 parent 4ffc7cf commit 627f7af
Show file tree
Hide file tree
Showing 29 changed files with 910 additions and 117 deletions.
12 changes: 11 additions & 1 deletion op-node/rollup/derive/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,19 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex
return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err))
}

txs := make([]hexutil.Bytes, 0, 1+len(depositTxs)+len(upgradeTxs))
var afterForceIncludeTxs []hexutil.Bytes
if ba.rollupCfg.IsInterop(nextL2Time) {
depositsCompleteTx, err := DepositsCompleteBytes(seqNumber, l1Info)
if err != nil {
return nil, NewCriticalError(fmt.Errorf("failed to create depositsCompleteTx: %w", err))
}
afterForceIncludeTxs = append(afterForceIncludeTxs, depositsCompleteTx)
}

txs := make([]hexutil.Bytes, 0, 1+len(depositTxs)+len(afterForceIncludeTxs)+len(upgradeTxs))
txs = append(txs, l1InfoTx)
txs = append(txs, depositTxs...)
txs = append(txs, afterForceIncludeTxs...)
txs = append(txs, upgradeTxs...)

var withdrawals *types.Withdrawals
Expand Down
92 changes: 92 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,98 @@ func TestPreparePayloadAttributes(t *testing.T) {
require.Equal(t, l1InfoTx, []byte(attrs.Transactions[0]))
require.True(t, attrs.NoTxPool)
})
t.Run("new 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 // next origin, where deposits may be

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)
userDepositTxs, err := encodeDeposits(depositTxs)
require.NoError(t, err)

// sets config to post-interop
cfg.ActivateAtGenesis(rollup.Interop)

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

var l2Txs []eth.Data
l2Txs = append(l2Txs, l1InfoTx)
l2Txs = append(l2Txs, userDepositTxs...)
l2Txs = append(l2Txs, depositsComplete)

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, eth.Data(depositsComplete).String(), attrs.Transactions[len(l2Txs)-1].String())
require.Equal(t, l2Txs, attrs.Transactions)
require.True(t, attrs.NoTxPool)
})

t.Run("same origin without 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.InfoHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number // same origin again, so the sequence number is not reset

// sets config to post-interop
cfg.ActivateAtGenesis(rollup.Interop)

seqNumber := l2Parent.SequenceNumber + 1
epoch := l1Info.ID()
l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, seqNumber, l1Info, 0)
require.NoError(t, err)
depositsComplete, err := DepositsCompleteBytes(seqNumber, l1Info)
require.NoError(t, err)

var l2Txs []eth.Data
l2Txs = append(l2Txs, l1InfoTx)
l2Txs = append(l2Txs, depositsComplete)

l1Fetcher.ExpectInfoByHash(epoch.Hash, l1Info, 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, eth.Data(depositsComplete).String(), attrs.Transactions[len(l2Txs)-1].String())
require.Equal(t, l2Txs, attrs.Transactions)
require.True(t, attrs.NoTxPool)
})

// 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
25 changes: 22 additions & 3 deletions op-node/rollup/derive/deposit_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ type UserDepositSource struct {
}

const (
UserDepositSourceDomain = 0
L1InfoDepositSourceDomain = 1
UpgradeDepositSourceDomain = 2
UserDepositSourceDomain = 0
L1InfoDepositSourceDomain = 1
UpgradeDepositSourceDomain = 2
AfterForceIncludeSourceDomain = 3
)

func (dep *UserDepositSource) SourceHash() common.Hash {
Expand Down Expand Up @@ -63,3 +64,21 @@ func (dep *UpgradeDepositSource) SourceHash() common.Hash {
copy(domainInput[32:], intentHash[:])
return crypto.Keccak256Hash(domainInput[:])
}

// AfterForceIncludeSource identifies the DepositsComplete post-user-deposits deposit-transaction.
type AfterForceIncludeSource struct {
L1BlockHash common.Hash
SeqNumber uint64 // without this the Deposit tx would have the same tx hash for every time the L1 info repeats.
}

func (dep *AfterForceIncludeSource) SourceHash() common.Hash {
var input [32 * 2]byte
copy(input[:32], dep.L1BlockHash[:])
binary.BigEndian.PutUint64(input[32*2-8:], dep.SeqNumber)
depositIDHash := crypto.Keccak256Hash(input[:])

var domainInput [32 * 2]byte
binary.BigEndian.PutUint64(domainInput[32-8:32], AfterForceIncludeSourceDomain)
copy(domainInput[32:], depositIDHash[:])
return crypto.Keccak256Hash(domainInput[:])
}
31 changes: 31 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,33 @@ func TestEcotone4788ContractSourceHash(t *testing.T) {

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

// TestL1InfoDepositSource
// cast keccak $(cast concat-hex 0x0000000000000000000000000000000000000000000000000000000000000001 $(cast keccak $(cast concat-hex 0xc00e5d67c2755389aded7d8b151cbd5bcdf7ed275ad5e028b664880fc7581c77 0x0000000000000000000000000000000000000000000000000000000000000004)))
// # 0x0586c503340591999b8b38bc9834bb16aec7d5bc00eb5587ab139c9ddab81977
func TestL1InfoDepositSource(t *testing.T) {
source := L1InfoDepositSource{
L1BlockHash: common.HexToHash("0xc00e5d67c2755389aded7d8b151cbd5bcdf7ed275ad5e028b664880fc7581c77"),
SeqNumber: 4,
}

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

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

// TestAfterForceIncludeSourceHash
// cast keccak $(cast concat-hex 0x0000000000000000000000000000000000000000000000000000000000000003 $(cast keccak $(cast concat-hex 0xc00e5d67c2755389aded7d8b151cbd5bcdf7ed275ad5e028b664880fc7581c77 0x0000000000000000000000000000000000000000000000000000000000000004)))
// # 0x0d165c391384b29c29f655e3f32315755b8c1e4c1147d1824d1243420dda5ec3
func TestAfterForceIncludeSource(t *testing.T) {
source := AfterForceIncludeSource{
L1BlockHash: common.HexToHash("0xc00e5d67c2755389aded7d8b151cbd5bcdf7ed275ad5e028b664880fc7581c77"),
SeqNumber: 4,
}

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

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
Loading

0 comments on commit 627f7af

Please sign in to comment.