github.com/ethereum-optimism/optimism@v1.7.2/op-node/withdrawals/proof.go (about)

     1  package withdrawals
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/ethereum/go-ethereum/common"
     9  	"github.com/ethereum/go-ethereum/core/types"
    10  	"github.com/ethereum/go-ethereum/crypto"
    11  	"github.com/ethereum/go-ethereum/ethclient/gethclient"
    12  	"github.com/ethereum/go-ethereum/rlp"
    13  	"github.com/ethereum/go-ethereum/trie"
    14  )
    15  
    16  type proofDB struct {
    17  	m map[string][]byte
    18  }
    19  
    20  func (p *proofDB) Has(key []byte) (bool, error) {
    21  	_, ok := p.m[string(key)]
    22  	return ok, nil
    23  }
    24  
    25  func (p *proofDB) Get(key []byte) ([]byte, error) {
    26  	v, ok := p.m[string(key)]
    27  	if !ok {
    28  		return nil, errors.New("not found")
    29  	}
    30  	return v, nil
    31  }
    32  
    33  func GenerateProofDB(proof []string) *proofDB {
    34  	p := proofDB{m: make(map[string][]byte)}
    35  	for _, s := range proof {
    36  		value := common.FromHex(s)
    37  		key := crypto.Keccak256(value)
    38  		p.m[string(key)] = value
    39  	}
    40  	return &p
    41  }
    42  
    43  func VerifyAccountProof(root common.Hash, address common.Address, account types.StateAccount, proof []string) error {
    44  	expected, err := rlp.EncodeToBytes(&account)
    45  	if err != nil {
    46  		return fmt.Errorf("failed to encode rlp: %w", err)
    47  	}
    48  	secureKey := crypto.Keccak256(address[:])
    49  	db := GenerateProofDB(proof)
    50  	value, err := trie.VerifyProof(root, secureKey, db)
    51  	if err != nil {
    52  		return fmt.Errorf("failed to verify proof: %w", err)
    53  	}
    54  
    55  	if bytes.Equal(value, expected) {
    56  		return nil
    57  	} else {
    58  		return errors.New("proved value is not the same as the expected value")
    59  	}
    60  }
    61  
    62  func VerifyStorageProof(root common.Hash, proof gethclient.StorageResult) error {
    63  	secureKey := crypto.Keccak256(common.FromHex(proof.Key))
    64  	db := GenerateProofDB(proof.Proof)
    65  	value, err := trie.VerifyProof(root, secureKey, db)
    66  	if err != nil {
    67  		return fmt.Errorf("failed to verify proof: %w", err)
    68  	}
    69  
    70  	expected := proof.Value.Bytes()
    71  	if bytes.Equal(value, expected) {
    72  		return nil
    73  	} else {
    74  		return errors.New("proved value is not the same as the expected value")
    75  	}
    76  }
    77  
    78  func VerifyProof(stateRoot common.Hash, proof *gethclient.AccountResult) error {
    79  	err := VerifyAccountProof(
    80  		stateRoot,
    81  		proof.Address,
    82  		types.StateAccount{
    83  			Nonce:    proof.Nonce,
    84  			Balance:  proof.Balance,
    85  			Root:     proof.StorageHash,
    86  			CodeHash: proof.CodeHash[:],
    87  		},
    88  		proof.AccountProof,
    89  	)
    90  	if err != nil {
    91  		return fmt.Errorf("failed to validate account: %w", err)
    92  	}
    93  	for i, storageProof := range proof.StorageProof {
    94  		err = VerifyStorageProof(proof.StorageHash, storageProof)
    95  		if err != nil {
    96  			return fmt.Errorf("failed to validate storage proof %d: %w", i, err)
    97  		}
    98  	}
    99  	return nil
   100  }