Commit 1ca85526 authored by Axel Kingsley's avatar Axel Kingsley Committed by GitHub

Interop: Expanded E2E Tests (#12659)

* Expand Interop E2E Testing

* fix test ; address comment
parent b46bffed
...@@ -3,22 +3,24 @@ package interop ...@@ -3,22 +3,24 @@ package interop
import ( import (
"context" "context"
"math/big" "math/big"
"sync"
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-chain-ops/interopgen" "github.com/ethereum-optimism/optimism/op-chain-ops/interopgen"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
gethTypes "github.com/ethereum/go-ethereum/core/types"
) )
// TestInteropTrivial tests a simple interop scenario // setupAndRun is a helper function that sets up a SuperSystem
// Chains A and B exist, but no messages are sent between them // which contains two L2 Chains, and two users on each chain.
// and in fact no event-logs are emitted by either chain at all. func setupAndRun(t *testing.T, fn func(*testing.T, SuperSystem)) {
// A transaction is sent from Alice to Bob on Chain A.
// The balance of Bob on Chain A is checked before and after the tx.
// The balance of Bob on Chain B is checked after the tx.
func TestInteropTrivial(t *testing.T) {
recipe := interopgen.InteropDevRecipe{ recipe := interopgen.InteropDevRecipe{
L1ChainID: 900100, L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201}, L2ChainIDs: []uint64{900200, 900201},
...@@ -32,66 +34,163 @@ func TestInteropTrivial(t *testing.T) { ...@@ -32,66 +34,163 @@ func TestInteropTrivial(t *testing.T) {
// create a super system from the recipe // create a super system from the recipe
// and get the L2 IDs for use in the test // and get the L2 IDs for use in the test
s2 := NewSuperSystem(t, &recipe, worldResources) s2 := NewSuperSystem(t, &recipe, worldResources)
ids := s2.L2IDs()
// chainA is the first L2 chain
chainA := ids[0]
// chainB is the second L2 chain
chainB := ids[1]
// create two users on all L2 chains // create two users on all L2 chains
s2.AddUser("Alice") s2.AddUser("Alice")
s2.AddUser("Bob") s2.AddUser("Bob")
bobAddr := s2.Address(chainA, "Bob") // run the test
fn(t, s2)
// check the balance of Bob }
clientA := s2.L2GethClient(chainA)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
bobBalance, err := clientA.BalanceAt(ctx, bobAddr, nil)
require.NoError(t, err)
expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance)
// send a tx from Alice to Bob
s2.SendL2Tx(
chainA,
"Alice",
func(l2Opts *helpers.TxOpts) {
l2Opts.ToAddr = &bobAddr
l2Opts.Value = big.NewInt(1000000)
l2Opts.GasFeeCap = big.NewInt(1_000_000_000)
l2Opts.GasTipCap = big.NewInt(1_000_000_000)
},
)
// check the balance of Bob after the tx
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
bobBalance, err = clientA.BalanceAt(ctx, bobAddr, nil)
require.NoError(t, err)
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000001000000", 10)
require.Equal(t, expectedBalance, bobBalance)
// check that the balance of Bob on ChainB hasn't changed
bobAddrB := s2.Address(chainB, "Bob")
clientB := s2.L2GethClient(chainB)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
bobBalance, err = clientB.BalanceAt(ctx, bobAddrB, nil)
require.NoError(t, err)
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance)
s2.DeployEmitterContract(chainA, "Alice")
s2.DeployEmitterContract(chainB, "Alice")
for i := 0; i < 1; i++ {
s2.EmitData(chainA, "Alice", "0x1234567890abcdef")
s2.EmitData(chainB, "Alice", "0x1234567890abcdef")
}
time.Sleep(60 * time.Second) // TestInterop_IsolatedChains tests a simple interop scenario
// Chains A and B exist, but no messages are sent between them
// a transaction is sent from Alice to Bob on Chain A,
// and only Chain A is affected.
func TestInterop_IsolatedChains(t *testing.T) {
test := func(t *testing.T, s2 SuperSystem) {
ids := s2.L2IDs()
chainA := ids[0]
chainB := ids[1]
// check the balance of Bob
bobAddr := s2.Address(chainA, "Bob")
clientA := s2.L2GethClient(chainA)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
bobBalance, err := clientA.BalanceAt(ctx, bobAddr, nil)
require.NoError(t, err)
expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance)
// send a tx from Alice to Bob
s2.SendL2Tx(
chainA,
"Alice",
func(l2Opts *helpers.TxOpts) {
l2Opts.ToAddr = &bobAddr
l2Opts.Value = big.NewInt(1000000)
l2Opts.GasFeeCap = big.NewInt(1_000_000_000)
l2Opts.GasTipCap = big.NewInt(1_000_000_000)
},
)
// check the balance of Bob after the tx
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
bobBalance, err = clientA.BalanceAt(ctx, bobAddr, nil)
require.NoError(t, err)
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000001000000", 10)
require.Equal(t, expectedBalance, bobBalance)
// check that the balance of Bob on ChainB hasn't changed
bobAddrB := s2.Address(chainB, "Bob")
clientB := s2.L2GethClient(chainB)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
bobBalance, err = clientB.BalanceAt(ctx, bobAddrB, nil)
require.NoError(t, err)
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance)
}
setupAndRun(t, test)
}
// TestInteropTrivial_EmitLogs tests a simple interop scenario
// Chains A and B exist, but no messages are sent between them.
// A contract is deployed on each chain, and logs are emitted repeatedly.
func TestInteropTrivial_EmitLogs(t *testing.T) {
test := func(t *testing.T, s2 SuperSystem) {
ids := s2.L2IDs()
chainA := ids[0]
chainB := ids[1]
EmitterA := s2.DeployEmitterContract(chainA, "Alice")
EmitterB := s2.DeployEmitterContract(chainB, "Alice")
payload1 := "SUPER JACKPOT!"
numEmits := 10
// emit logs on both chains in parallel
var emitParallel sync.WaitGroup
emitOn := func(chainID string) {
for i := 0; i < numEmits; i++ {
s2.EmitData(chainID, "Alice", payload1)
}
emitParallel.Done()
}
emitParallel.Add(2)
go emitOn(chainA)
go emitOn(chainB)
emitParallel.Wait()
clientA := s2.L2GethClient(chainA)
clientB := s2.L2GethClient(chainB)
// check that the logs are emitted on chain A
qA := ethereum.FilterQuery{
Addresses: []common.Address{EmitterA},
}
logsA, err := clientA.FilterLogs(context.Background(), qA)
require.NoError(t, err)
require.Len(t, logsA, numEmits)
// check that the logs are emitted on chain B
qB := ethereum.FilterQuery{
Addresses: []common.Address{EmitterB},
}
logsB, err := clientB.FilterLogs(context.Background(), qB)
require.NoError(t, err)
require.Len(t, logsB, numEmits)
// wait for cross-safety to settle
// I've tried 30s but not all logs are cross-safe by then
time.Sleep(60 * time.Second)
supervisor := s2.SupervisorClient()
// requireMessage checks the safety level of a log against the supervisor
// it also checks that the error is as expected
requireMessage := func(chainID string, log gethTypes.Log, expectedSafety types.SafetyLevel, expectedError error) {
client := s2.L2GethClient(chainID)
// construct the expected hash of the log's payload
// (topics concatenated with data)
msgPayload := make([]byte, 0)
for _, topic := range log.Topics {
msgPayload = append(msgPayload, topic.Bytes()...)
}
msgPayload = append(msgPayload, log.Data...)
expectedHash := common.BytesToHash(crypto.Keccak256(msgPayload))
// convert payload hash to log hash
logHash := types.PayloadHashToLogHash(expectedHash, log.Address)
// get block for the log (for timestamp)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
block, err := client.BlockByHash(ctx, log.BlockHash)
require.NoError(t, err)
// make an identifier out of the sample log
identifier := types.Identifier{
Origin: log.Address,
BlockNumber: log.BlockNumber,
LogIndex: uint64(log.Index),
Timestamp: block.Time(),
ChainID: types.ChainIDFromBig(s2.ChainID(chainID)),
}
safety, error := supervisor.CheckMessage(context.Background(),
identifier,
logHash,
)
require.ErrorIs(t, error, expectedError)
// the supervisor could progress the safety level more quickly than we expect,
// which is why we check for a minimum safety level
require.True(t, safety.AtLeastAsSafe(expectedSafety), "log: %v should be at least %s, but is %s", log, expectedSafety.String(), safety.String())
}
// all logs should be cross-safe
for _, log := range logsA {
requireMessage(chainA, log, types.CrossSafe, nil)
}
for _, log := range logsB {
requireMessage(chainB, log, types.CrossSafe, nil)
}
}
setupAndRun(t, test)
} }
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"sort"
"testing" "testing"
"time" "time"
...@@ -79,8 +80,10 @@ type SuperSystem interface { ...@@ -79,8 +80,10 @@ type SuperSystem interface {
L2GethClient(network string) *ethclient.Client L2GethClient(network string) *ethclient.Client
// get the secret for a network and role // get the secret for a network and role
L2OperatorKey(network string, role devkeys.ChainOperatorRole) ecdsa.PrivateKey L2OperatorKey(network string, role devkeys.ChainOperatorRole) ecdsa.PrivateKey
// get the list of network IDs // get the list of network IDs as key-strings
L2IDs() []string L2IDs() []string
// get the chain ID for a network
ChainID(network string) *big.Int
// register a username to an account on all L2s // register a username to an account on all L2s
AddUser(username string) AddUser(username string)
// get the user key for a user on an L2 // get the user key for a user on an L2
...@@ -415,6 +418,10 @@ func (s *interopE2ESystem) newL2(id string, l2Out *interopgen.L2Output) l2Set { ...@@ -415,6 +418,10 @@ func (s *interopE2ESystem) newL2(id string, l2Out *interopgen.L2Output) l2Set {
} }
} }
func (s *interopE2ESystem) ChainID(network string) *big.Int {
return s.l2s[network].chainID
}
// prepareSupervisor creates a new supervisor for the system // prepareSupervisor creates a new supervisor for the system
func (s *interopE2ESystem) prepareSupervisor() *supervisor.SupervisorService { func (s *interopE2ESystem) prepareSupervisor() *supervisor.SupervisorService {
// Be verbose with op-supervisor, it's in early test phase // Be verbose with op-supervisor, it's in early test phase
...@@ -604,6 +611,7 @@ func (s *interopE2ESystem) L2IDs() []string { ...@@ -604,6 +611,7 @@ func (s *interopE2ESystem) L2IDs() []string {
for id := range s.l2s { for id := range s.l2s {
ids = append(ids, id) ids = append(ids, id)
} }
sort.Strings(ids)
return ids return ids
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
"github.com/ethereum/go-ethereum/common"
) )
type SupervisorClient struct { type SupervisorClient struct {
...@@ -19,9 +20,7 @@ func NewSupervisorClient(client client.RPC) *SupervisorClient { ...@@ -19,9 +20,7 @@ func NewSupervisorClient(client client.RPC) *SupervisorClient {
} }
} }
func (cl *SupervisorClient) Stop( func (cl *SupervisorClient) Stop(ctx context.Context) error {
ctx context.Context,
) error {
var result error var result error
err := cl.client.CallContext( err := cl.client.CallContext(
ctx, ctx,
...@@ -33,9 +32,7 @@ func (cl *SupervisorClient) Stop( ...@@ -33,9 +32,7 @@ func (cl *SupervisorClient) Stop(
return result return result
} }
func (cl *SupervisorClient) Start( func (cl *SupervisorClient) Start(ctx context.Context) error {
ctx context.Context,
) error {
var result error var result error
err := cl.client.CallContext( err := cl.client.CallContext(
ctx, ctx,
...@@ -47,10 +44,7 @@ func (cl *SupervisorClient) Start( ...@@ -47,10 +44,7 @@ func (cl *SupervisorClient) Start(
return result return result
} }
func (cl *SupervisorClient) AddL2RPC( func (cl *SupervisorClient) AddL2RPC(ctx context.Context, rpc string) error {
ctx context.Context,
rpc string,
) error {
var result error var result error
err := cl.client.CallContext( err := cl.client.CallContext(
ctx, ctx,
...@@ -63,6 +57,25 @@ func (cl *SupervisorClient) AddL2RPC( ...@@ -63,6 +57,25 @@ func (cl *SupervisorClient) AddL2RPC(
return result return result
} }
func (cl *SupervisorClient) CheckMessage(ctx context.Context, identifier types.Identifier, logHash common.Hash) (types.SafetyLevel, error) {
var result types.SafetyLevel
err := cl.client.CallContext(
ctx,
&result,
"supervisor_checkMessage",
identifier,
logHash)
if err != nil {
return types.Invalid, fmt.Errorf("failed to check message (chain %s), (block %v), (index %v), (logHash %s): %w",
identifier.ChainID,
identifier.BlockNumber,
identifier.LogIndex,
logHash,
err)
}
return result, nil
}
func (cl *SupervisorClient) UnsafeView(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) { func (cl *SupervisorClient) UnsafeView(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) {
var result types.ReferenceView var result types.ReferenceView
err := cl.client.CallContext( err := cl.client.CallContext(
...@@ -93,26 +106,51 @@ func (cl *SupervisorClient) SafeView(ctx context.Context, chainID types.ChainID, ...@@ -93,26 +106,51 @@ func (cl *SupervisorClient) SafeView(ctx context.Context, chainID types.ChainID,
func (cl *SupervisorClient) Finalized(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) { func (cl *SupervisorClient) Finalized(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) {
var result eth.BlockID var result eth.BlockID
err := cl.client.CallContext(ctx, &result, "supervisor_finalized", chainID) err := cl.client.CallContext(
ctx,
&result,
"supervisor_finalized",
chainID)
return result, err return result, err
} }
func (cl *SupervisorClient) DerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.BlockRef, error) { func (cl *SupervisorClient) DerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.BlockRef, error) {
var result eth.BlockRef var result eth.BlockRef
err := cl.client.CallContext(ctx, &result, "supervisor_derivedFrom", chainID, derived) err := cl.client.CallContext(
ctx,
&result,
"supervisor_derivedFrom",
chainID,
derived)
return result, err return result, err
} }
func (cl *SupervisorClient) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { func (cl *SupervisorClient) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error {
return cl.client.CallContext(ctx, nil, "supervisor_updateLocalUnsafe", chainID, head) return cl.client.CallContext(
ctx,
nil,
"supervisor_updateLocalUnsafe",
chainID,
head)
} }
func (cl *SupervisorClient) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error { func (cl *SupervisorClient) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error {
return cl.client.CallContext(ctx, nil, "supervisor_updateLocalSafe", chainID, derivedFrom, lastDerived) return cl.client.CallContext(
ctx,
nil,
"supervisor_updateLocalSafe",
chainID,
derivedFrom,
lastDerived)
} }
func (cl *SupervisorClient) UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalizedL1 eth.L1BlockRef) error { func (cl *SupervisorClient) UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalizedL1 eth.L1BlockRef) error {
return cl.client.CallContext(ctx, nil, "supervisor_updateFinalizedL1", chainID, finalizedL1) return cl.client.CallContext(
ctx,
nil,
"supervisor_updateFinalizedL1",
chainID,
finalizedL1)
} }
func (cl *SupervisorClient) Close() { func (cl *SupervisorClient) Close() {
......
...@@ -308,14 +308,14 @@ func (su *SupervisorBackend) DependencySet() depset.DependencySet { ...@@ -308,14 +308,14 @@ func (su *SupervisorBackend) DependencySet() depset.DependencySet {
// Query methods // Query methods
// ---------------------------- // ----------------------------
func (su *SupervisorBackend) CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) { func (su *SupervisorBackend) CheckMessage(identifier types.Identifier, logHash common.Hash) (types.SafetyLevel, error) {
su.mu.RLock() su.mu.RLock()
defer su.mu.RUnlock() defer su.mu.RUnlock()
chainID := identifier.ChainID chainID := identifier.ChainID
blockNum := identifier.BlockNumber blockNum := identifier.BlockNumber
logIdx := identifier.LogIndex logIdx := identifier.LogIndex
_, err := su.chainDBs.Check(chainID, blockNum, uint32(logIdx), payloadHash) _, err := su.chainDBs.Check(chainID, blockNum, uint32(logIdx), logHash)
if errors.Is(err, types.ErrFuture) { if errors.Is(err, types.ErrFuture) {
return types.LocalUnsafe, nil return types.LocalUnsafe, nil
} }
......
...@@ -358,7 +358,7 @@ func (db *ChainsDB) NextDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID ...@@ -358,7 +358,7 @@ func (db *ChainsDB) NextDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID
// Safest returns the strongest safety level that can be guaranteed for the given log entry. // Safest returns the strongest safety level that can be guaranteed for the given log entry.
// it assumes the log entry has already been checked and is valid, this function only checks safety levels. // it assumes the log entry has already been checked and is valid, this function only checks safety levels.
// Cross-safety levels are all considered to be more safe than any form of local-safety. // Safety levels are assumed to graduate from LocalUnsafe to LocalSafe to CrossUnsafe to CrossSafe, with Finalized as the strongest.
func (db *ChainsDB) Safest(chainID types.ChainID, blockNum uint64, index uint32) (safest types.SafetyLevel, err error) { func (db *ChainsDB) Safest(chainID types.ChainID, blockNum uint64, index uint32) (safest types.SafetyLevel, err error) {
db.mu.RLock() db.mu.RLock()
defer db.mu.RUnlock() defer db.mu.RUnlock()
......
...@@ -14,7 +14,6 @@ import ( ...@@ -14,7 +14,6 @@ import (
"github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
ethTypes "github.com/ethereum/go-ethereum/core/types" ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
) )
const ( const (
...@@ -74,7 +73,7 @@ func (i *CrossL2Inbox) DecodeExecutingMessageLog(l *ethTypes.Log) (types.Executi ...@@ -74,7 +73,7 @@ func (i *CrossL2Inbox) DecodeExecutingMessageLog(l *ethTypes.Log) (types.Executi
if err != nil { if err != nil {
return types.ExecutingMessage{}, fmt.Errorf("failed to convert chain ID %v to uint32: %w", identifier.ChainId, err) return types.ExecutingMessage{}, fmt.Errorf("failed to convert chain ID %v to uint32: %w", identifier.ChainId, err)
} }
hash := payloadHashToLogHash(msgHash, identifier.Origin) hash := types.PayloadHashToLogHash(msgHash, identifier.Origin)
return types.ExecutingMessage{ return types.ExecutingMessage{
Chain: types.ChainIndex(chainID), // TODO(#11105): translate chain ID to chain index Chain: types.ChainIndex(chainID), // TODO(#11105): translate chain ID to chain index
Hash: hash, Hash: hash,
...@@ -117,17 +116,3 @@ func identifierFromBytes(identifierBytes io.Reader) (contractIdentifier, error) ...@@ -117,17 +116,3 @@ func identifierFromBytes(identifierBytes io.Reader) (contractIdentifier, error)
ChainId: chainID, ChainId: chainID,
}, nil }, nil
} }
// payloadHashToLogHash converts the payload hash to the log hash
// it is the concatenation of the log's address and the hash of the log's payload,
// which is then hashed again. This is the hash that is stored in the log storage.
// The logHash can then be used to traverse from the executing message
// to the log the referenced initiating message.
// TODO(#12424): this function is duplicated between contracts and backend/source/log_processor.go
// to avoid a circular dependency. It should be reorganized to avoid this duplication.
func payloadHashToLogHash(payloadHash common.Hash, addr common.Address) common.Hash {
msg := make([]byte, 0, 2*common.HashLength)
msg = append(msg, addr.Bytes()...)
msg = append(msg, payloadHash.Bytes()...)
return crypto.Keccak256Hash(msg)
}
...@@ -32,7 +32,7 @@ func TestDecodeExecutingMessageEvent(t *testing.T) { ...@@ -32,7 +32,7 @@ func TestDecodeExecutingMessageEvent(t *testing.T) {
Timestamp: new(big.Int).SetUint64(expected.Timestamp), Timestamp: new(big.Int).SetUint64(expected.Timestamp),
LogIndex: new(big.Int).SetUint64(uint64(expected.LogIdx)), LogIndex: new(big.Int).SetUint64(uint64(expected.LogIdx)),
} }
expected.Hash = payloadHashToLogHash(payloadHash, contractIdent.Origin) expected.Hash = types.PayloadHashToLogHash(payloadHash, contractIdent.Origin)
abi := snapshots.LoadCrossL2InboxABI() abi := snapshots.LoadCrossL2InboxABI()
validData, err := abi.Events[eventExecutingMessage].Inputs.Pack(payloadHash, contractIdent) validData, err := abi.Events[eventExecutingMessage].Inputs.Pack(payloadHash, contractIdent)
require.NoError(t, err) require.NoError(t, err)
......
...@@ -78,7 +78,7 @@ func (p *logProcessor) ProcessLogs(_ context.Context, block eth.BlockRef, rcpts ...@@ -78,7 +78,7 @@ func (p *logProcessor) ProcessLogs(_ context.Context, block eth.BlockRef, rcpts
// and because they represent paired data. // and because they represent paired data.
func logToLogHash(l *ethTypes.Log) common.Hash { func logToLogHash(l *ethTypes.Log) common.Hash {
payloadHash := crypto.Keccak256(logToMessagePayload(l)) payloadHash := crypto.Keccak256(logToMessagePayload(l))
return payloadHashToLogHash(common.Hash(payloadHash), l.Address) return types.PayloadHashToLogHash(common.Hash(payloadHash), l.Address)
} }
// logToMessagePayload is the data that is hashed to get the logHash // logToMessagePayload is the data that is hashed to get the logHash
...@@ -92,15 +92,3 @@ func logToMessagePayload(l *ethTypes.Log) []byte { ...@@ -92,15 +92,3 @@ func logToMessagePayload(l *ethTypes.Log) []byte {
msg = append(msg, l.Data...) msg = append(msg, l.Data...)
return msg return msg
} }
// payloadHashToLogHash converts the payload hash to the log hash
// it is the concatenation of the log's address and the hash of the log's payload,
// which is then hashed. This is the hash that is stored in the log storage.
// The logHash can then be used to traverse from the executing message
// to the log the referenced initiating message.
func payloadHashToLogHash(payloadHash common.Hash, addr common.Address) common.Hash {
msg := make([]byte, 0, 2*common.HashLength)
msg = append(msg, addr.Bytes()...)
msg = append(msg, payloadHash.Bytes()...)
return crypto.Keccak256Hash(msg)
}
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
) )
...@@ -251,3 +252,15 @@ func BlockSealFromRef(ref eth.BlockRef) BlockSeal { ...@@ -251,3 +252,15 @@ func BlockSealFromRef(ref eth.BlockRef) BlockSeal {
Timestamp: ref.Time, Timestamp: ref.Time,
} }
} }
// PayloadHashToLogHash converts the payload hash to the log hash
// it is the concatenation of the log's address and the hash of the log's payload,
// which is then hashed again. This is the hash that is stored in the log storage.
// The logHash can then be used to traverse from the executing message
// to the log the referenced initiating message.
func PayloadHashToLogHash(payloadHash common.Hash, addr common.Address) common.Hash {
msg := make([]byte, 0, 2*common.HashLength)
msg = append(msg, addr.Bytes()...)
msg = append(msg, payloadHash.Bytes()...)
return crypto.Keccak256Hash(msg)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment