internal/ethapi: return error when requesting invalid trie key (#25762)

This change makes eth_getProof and eth_getStorageAt return an error when
the argument contains invalid hex in storage keys.

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
lightclient 2022-09-16 18:16:32 +02:00 committed by GitHub
parent d213cb0924
commit 8ade5e6c14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -18,6 +18,7 @@ package ethapi
import ( import (
"context" "context"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
@ -674,15 +675,19 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
} }
// create the proof for the storageKeys // create the proof for the storageKeys
for i, key := range storageKeys { for i, hexKey := range storageKeys {
key, err := decodeHash(hexKey)
if err != nil {
return nil, err
}
if storageTrie != nil { if storageTrie != nil {
proof, storageError := state.GetStorageProof(address, common.HexToHash(key)) proof, storageError := state.GetStorageProof(address, key)
if storageError != nil { if storageError != nil {
return nil, storageError return nil, storageError
} }
storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), toHexSlice(proof)} storageProof[i] = StorageResult{hexKey, (*hexutil.Big)(state.GetState(address, key).Big()), toHexSlice(proof)}
} else { } else {
storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}} storageProof[i] = StorageResult{hexKey, &hexutil.Big{}, []string{}}
} }
} }
@ -703,6 +708,22 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
}, state.Error() }, state.Error()
} }
// decodeHash parses a hex-encoded 32-byte hash. The input may optionally
// be prefixed by 0x and can have an byte length up to 32.
func decodeHash(s string) (common.Hash, error) {
if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
s = s[2:]
}
b, err := hex.DecodeString(s)
if err != nil {
return common.Hash{}, fmt.Errorf("hex string invalid")
}
if len(b) > 32 {
return common.Hash{}, fmt.Errorf("hex string too long, want at most 32 bytes")
}
return common.BytesToHash(b), nil
}
// GetHeaderByNumber returns the requested canonical block header. // GetHeaderByNumber returns the requested canonical block header.
// * When blockNr is -1 the chain head is returned. // * When blockNr is -1 the chain head is returned.
// * When blockNr is -2 the pending chain head is returned. // * When blockNr is -2 the pending chain head is returned.
@ -821,12 +842,16 @@ func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blo
// GetStorageAt returns the storage from the state at the given address, key and // GetStorageAt returns the storage from the state at the given address, key and
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
// numbers are also allowed. // numbers are also allowed.
func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
res := state.GetState(address, common.HexToHash(key)) key, err := decodeHash(hexKey)
if err != nil {
return nil, fmt.Errorf("unable to decode storage key: %s", err)
}
res := state.GetState(address, key)
return res[:], state.Error() return res[:], state.Error()
} }