Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions crates/optimism/tests/proofs/reorg/reorg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ func TestReorgUsingAccountProof(gt *testing.T) {
slots []common.Hash
}
var cases []caseEntry

// deploy another contract in the reorged blocks
{
rContract, rDeployBlock := utils.DeploySimpleStorage(t, user)
t.Logf("Reorg SimpleStorage deployed at %s block=%d", rContract.Address().Hex(), rDeployBlock.BlockNumber.Uint64())

cases = append(cases, caseEntry{
Block: rDeployBlock.BlockNumber.Uint64(),
addr: rContract.Address(),
slots: []common.Hash{common.HexToHash("0x0")},
})
}

for i := 0; i < 3; i++ {
tx := alice.Transfer(bob.Address(), eth.OneGWei)
receipt, err := tx.Included.Eval(ctx)
Expand Down Expand Up @@ -74,18 +87,6 @@ func TestReorgUsingAccountProof(gt *testing.T) {
})
}

// deploy another contract in the reorged blocks
{
rContract, rDeployBlock := utils.DeploySimpleStorage(t, user)
t.Logf("Reorg SimpleStorage deployed at %s block=%d", rContract.Address().Hex(), rDeployBlock.BlockNumber.Uint64())

cases = append(cases, caseEntry{
Block: rDeployBlock.BlockNumber.Uint64(),
addr: rContract.Address(),
slots: []common.Hash{common.HexToHash("0x0")},
})
}

sys.L2CLSequencer.StopSequencer()

var divergenceBlockNumber uint64
Expand Down
26 changes: 26 additions & 0 deletions crates/optimism/tests/proofs/utils/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ func NormalizeProofResponse(res *eth.AccountResult) {
res.StorageProof[i].Proof = []hexutil.Bytes{}
}
}

// Normalize empty CodeHash
// Geth returns 0x0000000000000000000000000000000000000000000000000000000000000000
// Reth returns 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
if res.CodeHash == (common.Hash{}) {
res.CodeHash = crypto.Keccak256Hash(nil)
}

// Normalize empty StorageHash
// Geth returns 0x0000000000000000000000000000000000000000000000000000000000000000
// Reth returns 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
if res.StorageHash == (common.Hash{}) {
res.StorageHash = types.EmptyRootHash
}
}

// VerifyProof verifies an account and its storage proofs against a given state root.
Expand Down Expand Up @@ -95,6 +109,18 @@ func VerifyProof(res *eth.AccountResult, stateRoot common.Hash) error {
return fmt.Errorf("failed to verify account value with key %s (path %x) in account trie %s: %w", res.Address, path, stateRoot, err)
}

// If the proof demonstrates non-existence (nil value), we must check if the RPC claimed the account is empty.
if len(accountProofValue) == 0 {
isEmpty := res.Nonce == 0 &&
res.Balance.ToInt().Sign() == 0 &&
(res.StorageHash == types.EmptyRootHash || res.StorageHash == common.Hash{}) &&
(res.CodeHash == crypto.Keccak256Hash(nil) || res.CodeHash == common.Hash{})

if isEmpty {
return nil
}
}

if !bytes.Equal(accountClaimedValue, accountProofValue) {
return fmt.Errorf("L1 RPC is tricking us, account proof does not match provided deserialized values:\n"+
" claimed: %x\n"+
Expand Down
Loading