Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: only verify storage root on OutputV0AtBlock #3

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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
65 changes: 37 additions & 28 deletions op-service/eth/account_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,9 @@ type AccountResult struct {

// Verify an account (and optionally storage) proof from the getProof RPC. See https://eips.ethereum.org/EIPS/eip-1186
func (res *AccountResult) Verify(stateRoot common.Hash) error {
// verify storage proof values, if any, against the storage trie root hash of the account
for i, entry := range res.StorageProof {
// load all MPT nodes into a DB
db := memorydb.New()
for j, encodedNode := range entry.Proof {
nodeKey := encodedNode
if len(encodedNode) >= 32 { // small MPT nodes are not hashed
nodeKey = crypto.Keccak256(encodedNode)
}
if err := db.Put(nodeKey, encodedNode); err != nil {
return fmt.Errorf("failed to load storage proof node %d of storage value %d into mem db: %w", j, i, err)
}
}
path := crypto.Keccak256(entry.Key[:])
val, err := trie.VerifyProof(res.StorageHash, path, db)
if err != nil {
return fmt.Errorf("failed to verify storage value %d with key %s (path %x) in storage trie %s: %w", i, entry.Key, path, res.StorageHash, err)
}
if val == nil && entry.Value.ToInt().Cmp(common.Big0) == 0 { // empty storage is zero by default
continue
}
comparison, err := rlp.EncodeToBytes(entry.Value.ToInt().Bytes())
if err != nil {
return fmt.Errorf("failed to encode storage value %d with key %s (path %x) in storage trie %s: %w", i, entry.Key, path, res.StorageHash, err)
}
if !bytes.Equal(val, comparison) {
return fmt.Errorf("value %d in storage proof does not match proven value at key %s (path %x)", i, entry.Key, path)
}
err := res.VerifyStorageRoot()
if err != nil {
return err
}

accountClaimed := []any{uint64(res.Nonce), res.Balance.ToInt().Bytes(), res.StorageHash, res.CodeHash}
Expand Down Expand Up @@ -93,3 +68,37 @@ func (res *AccountResult) Verify(stateRoot common.Hash) error {
}
return err
}

// Verify an account storage proof from the getProof RPC.
func (res *AccountResult) VerifyStorageRoot() error {
// verify storage proof values, if any, against the storage trie root hash of the account
for i, entry := range res.StorageProof {
// load all MPT nodes into a DB
db := memorydb.New()
for j, encodedNode := range entry.Proof {
nodeKey := encodedNode
if len(encodedNode) >= 32 { // small MPT nodes are not hashed
nodeKey = crypto.Keccak256(encodedNode)
}
if err := db.Put(nodeKey, encodedNode); err != nil {
return fmt.Errorf("failed to load storage proof node %d of storage value %d into mem db: %w", j, i, err)
}
}
path := crypto.Keccak256(entry.Key[:])
val, err := trie.VerifyProof(res.StorageHash, path, db)
if err != nil {
return fmt.Errorf("failed to verify storage value %d with key %s (path %x) in storage trie %s: %w", i, entry.Key, path, res.StorageHash, err)
}
if val == nil && entry.Value.ToInt().Cmp(common.Big0) == 0 { // empty storage is zero by default
continue
}
comparison, err := rlp.EncodeToBytes(entry.Value.ToInt().Bytes())
if err != nil {
return fmt.Errorf("failed to encode storage value %d with key %s (path %x) in storage trie %s: %w", i, entry.Key, path, res.StorageHash, err)
}
if !bytes.Equal(val, comparison) {
return fmt.Errorf("value %d in storage proof does not match proven value at key %s (path %x)", i, entry.Key, path)
}
}
return nil
}
6 changes: 3 additions & 3 deletions op-service/sources/l2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,14 @@ func (s *L2Client) OutputV0AtBlock(ctx context.Context, blockHash common.Hash) (

proof, err := s.GetProof(ctx, predeploys.L2ToL1MessagePasserAddr, []common.Hash{}, blockHash.String())
if err != nil {
return nil, fmt.Errorf("failed to get contract proof at block %s: %w", blockHash, err)
return nil, fmt.Errorf("failed to get contract proof at address %s block %s: %w ", predeploys.L2ToL1MessagePasserAddr, blockHash, err)
}
if proof == nil {
return nil, fmt.Errorf("proof %w", ethereum.NotFound)
}
// make sure that the proof (including storage hash) that we retrieved is correct by verifying it against the state-root
if err := proof.Verify(head.Root()); err != nil {
return nil, fmt.Errorf("invalid withdrawal root hash, state root was %s: %w", head.Root(), err)
if err := proof.VerifyStorageRoot(); err != nil {
return nil, fmt.Errorf("invalid withdrawal storage proof, root was %s: %w", proof.StorageHash, err)
}
stateRoot := head.Root()
return &eth.OutputV0{
Expand Down