mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
feat: add validation for contract storage and contract bytecode
This commit is contained in:
parent
df86d197c1
commit
5679398f40
3 changed files with 102 additions and 7 deletions
|
|
@ -107,9 +107,9 @@ func (h *StateNetwork) validateContent(contentKey []byte, content []byte) error
|
|||
case AccountTrieNodeType:
|
||||
return h.validateAccountTrieNode(contentKey[1:], content)
|
||||
case ContractStorageTrieNodeType:
|
||||
return validateContractStorageTrieNode(h.spec, contentKey[1:], content)
|
||||
return h.validateContractStorageTrieNode(contentKey[1:], content)
|
||||
case ContractByteCodeType:
|
||||
return validateContractByteCode(h.spec, contentKey[1:], content)
|
||||
return h.validateContractByteCode(contentKey[1:], content)
|
||||
}
|
||||
return errors.New("unknown content type")
|
||||
}
|
||||
|
|
@ -135,11 +135,53 @@ func (h *StateNetwork) validateAccountTrieNode(contentKey []byte, content []byte
|
|||
return err
|
||||
}
|
||||
|
||||
func validateContractStorageTrieNode(spec *common.Spec, contentKey []byte, content []byte) error {
|
||||
return nil
|
||||
func (h *StateNetwork) validateContractStorageTrieNode(contentKey []byte, content []byte) error {
|
||||
contractStorageKey := &ContractStorageTrieNodeKey{}
|
||||
err := contractStorageKey.Deserialize(codec.NewDecodingReader(bytes.NewReader(contentKey), uint64(len(contentKey))))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contractProof := &ContractStorageTrieNodeWithProof{}
|
||||
err = contractProof.Deserialize(codec.NewDecodingReader(bytes.NewReader(content), uint64(len(content))))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stateRoot, err := h.getStateRoot(contractProof.BlockHash)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accountState, err := validateAccountState(stateRoot, contractStorageKey.AddressHash, &contractProof.AccountProof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = validateNodeTrieProof(common.Bytes32(accountState.Root), contractStorageKey.NodeHash, &contractStorageKey.Path, &contractProof.StoregeProof)
|
||||
return err
|
||||
}
|
||||
|
||||
func validateContractByteCode(spec *common.Spec, contentKey []byte, content []byte) error {
|
||||
func (h *StateNetwork) validateContractByteCode(contentKey []byte, content []byte) error {
|
||||
contractByteCodeKey := &ContractBytecodeKey{}
|
||||
err := contractByteCodeKey.Deserialize(codec.NewDecodingReader(bytes.NewReader(contentKey), uint64(len(contentKey))))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contractBytecodeWithProof := &ContractBytecodeWithProof{}
|
||||
err = contractBytecodeWithProof.Deserialize(codec.NewDecodingReader(bytes.NewReader(content), uint64(len(content))))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stateRoot, err := h.getStateRoot(contractBytecodeWithProof.BlockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accountState, err := validateAccountState(stateRoot, contractByteCodeKey.AddressHash, &contractBytecodeWithProof.AccountProof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(accountState.CodeHash, contractByteCodeKey.CodeHash[:]) {
|
||||
return errors.New("account state is invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +229,27 @@ func validateNodeTrieProof(rootHash common.Bytes32, nodeHash common.Bytes32, pat
|
|||
return nil
|
||||
}
|
||||
|
||||
func validateAccountState(rootHash common.Bytes32, addrrssHash common.Bytes32, proof *TrieProof) (*types.StateAccount, error) {
|
||||
path := make([]byte, 0, len(addrrssHash)*2)
|
||||
for _, item := range addrrssHash {
|
||||
before, after := unpackNibblePair(item)
|
||||
path = append(path, before, after)
|
||||
}
|
||||
lastProof, p, err := validateTrieProof(rootHash, path, proof)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n, err := trie.DecodeTrieNode(nil, lastProof)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stateBytes, _, err := trie.TraverseTrieNode(n, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.FullAccount(stateBytes)
|
||||
}
|
||||
|
||||
func validateTrieProof(rootHash common.Bytes32, path []byte, proof *TrieProof) (EncodedTrieNode, []byte, error) {
|
||||
if len(*proof) == 0 {
|
||||
return nil, nil, errors.New("proof should be empty")
|
||||
|
|
|
|||
|
|
@ -71,3 +71,35 @@ func TestValidateAccountTrieNode(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateContractStorage(t *testing.T) {
|
||||
cases, err := getTestCases("contract_storage_trie_node.yaml")
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, tt := range cases {
|
||||
server := rpc.NewServer()
|
||||
api := &MockAPI{
|
||||
header: tt.BlockHeader,
|
||||
}
|
||||
server.RegisterName("portal", api)
|
||||
bn := NewStateNetwork(nil, server)
|
||||
err = bn.validateContent(hexutil.MustDecode(tt.ContentKey), hexutil.MustDecode(tt.ContentValueOffer))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateContractByte(t *testing.T) {
|
||||
cases, err := getTestCases("contract_bytecode.yaml")
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, tt := range cases {
|
||||
server := rpc.NewServer()
|
||||
api := &MockAPI{
|
||||
header: tt.BlockHeader,
|
||||
}
|
||||
server.RegisterName("portal", api)
|
||||
bn := NewStateNetwork(nil, server)
|
||||
err = bn.validateContent(hexutil.MustDecode(tt.ContentKey), hexutil.MustDecode(tt.ContentValueOffer))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ func DecodeTrieNode(hash, buf []byte) (node, error) {
|
|||
return decodeNodeUnsafe(hash, buf)
|
||||
}
|
||||
|
||||
func TraverseTrieNode(node node, path []byte) (hashNode, []byte, error) {
|
||||
func TraverseTrieNode(node node, path []byte) ([]byte, []byte, error) {
|
||||
switch v := node.(type) {
|
||||
case *fullNode:
|
||||
first := path[0]
|
||||
|
|
@ -33,7 +33,7 @@ func TraverseTrieNode(node node, path []byte) (hashNode, []byte, error) {
|
|||
if !bytes.Equal(prePath, path) {
|
||||
return nil, nil, ErrDifferentLeafPrefix
|
||||
}
|
||||
return (v.Val).(hashNode), path, nil
|
||||
return (v.Val).(valueNode), path, nil
|
||||
} else {
|
||||
for index, key := range v.Key {
|
||||
if path[index] != key {
|
||||
|
|
|
|||
Loading…
Reference in a new issue