// Copyright 2021 go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package trie import ( "encoding/binary" "errors" "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/utils" "github.com/gballet/go-verkle" ) // VerkleTrie is a wrapper around VerkleNode that implements the trie.Trie // interface so that Verkle trees can be reused verbatim. type VerkleTrie struct { root verkle.VerkleNode db *Database } //func (vt *VerkleTrie) ToDot() string { //return verkle.ToDot(vt.root) //} func NewVerkleTrie(root verkle.VerkleNode, db *Database) *VerkleTrie { return &VerkleTrie{ root: root, db: db, } } var errInvalidProof = errors.New("invalid proof") // GetKey returns the sha3 preimage of a hashed key that was previously used // to store a value. func (trie *VerkleTrie) GetKey(key []byte) []byte { return key } // TryGet returns the value for key stored in the trie. The value bytes must // not be modified by the caller. If a node was not found in the database, a // trie.MissingNodeError is returned. func (trie *VerkleTrie) TryGet(key []byte) ([]byte, error) { return trie.root.Get(key, trie.db.DiskDB().Get) } func (t *VerkleTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { var err error if err = t.TryUpdate(utils.GetTreeKeyVersion(key), []byte{0}); err != nil { return fmt.Errorf("updateStateObject (%x) error: %v", key, err) } var nonce [32]byte binary.BigEndian.PutUint64(nonce[:], acc.Nonce) if err = t.TryUpdate(utils.GetTreeKeyNonce(key), nonce[:]); err != nil { return fmt.Errorf("updateStateObject (%x) error: %v", key, err) } if err = t.TryUpdate(utils.GetTreeKeyBalance(key), acc.Balance.Bytes()); err != nil { return fmt.Errorf("updateStateObject (%x) error: %v", key, err) } if err = t.TryUpdate(utils.GetTreeKeyCodeKeccak(key), acc.CodeHash); err != nil { return fmt.Errorf("updateStateObject (%x) error: %v", key, err) } return nil } // TryUpdate associates key with value in the trie. If value has length zero, any // existing value is deleted from the trie. The value bytes must not be modified // by the caller while they are stored in the trie. If a node was not found in the // database, a trie.MissingNodeError is returned. func (trie *VerkleTrie) TryUpdate(key, value []byte) error { return trie.root.Insert(key, value, func(h []byte) ([]byte, error) { return trie.db.DiskDB().Get(h) }) } // TryDelete removes any existing value for key from the trie. If a node was not // found in the database, a trie.MissingNodeError is returned. func (trie *VerkleTrie) TryDelete(key []byte) error { return trie.root.Delete(key) } // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. func (trie *VerkleTrie) Hash() common.Hash { // TODO cache this value rootC := trie.root.ComputeCommitment() return rootC.Bytes() } func nodeToDBKey(n verkle.VerkleNode) []byte { ret := n.ComputeCommitment().Bytes() return ret[:] } // Commit writes all nodes to the trie's memory database, tracking the internal // and external (for account tries) references. func (trie *VerkleTrie) Commit(onleaf LeafCallback) (common.Hash, int, error) { flush := make(chan verkle.VerkleNode) go func() { trie.root.(*verkle.InternalNode).Flush(func(n verkle.VerkleNode) { flush <- n }) close(flush) }() var commitCount int for n := range flush { commitCount += 1 value, err := n.Serialize() if err != nil { panic(err) } if err := trie.db.DiskDB().Put(nodeToDBKey(n), value); err != nil { return common.Hash{}, commitCount, err } } // XXX onleaf hasn't been called return trie.Hash(), commitCount, nil } // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. func (trie *VerkleTrie) NodeIterator(startKey []byte) NodeIterator { return newVerkleNodeIterator(trie, nil) } // Prove constructs a Merkle proof for key. The result contains all encoded nodes // on the path to the value at key. The value itself is also included in the last // node and can be retrieved by verifying the proof. // // If the trie does not contain a value for key, the returned proof contains all // nodes of the longest existing prefix of the key (at least the root), ending // with the node that proves the absence of the key. func (trie *VerkleTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error { panic("not implemented") } func (trie *VerkleTrie) Copy(db *Database) *VerkleTrie { return &VerkleTrie{ root: trie.root.Copy(), db: db, } } func (trie *VerkleTrie) IsVerkle() bool { return true } type KeyValuePair struct { Key []byte Value []byte } type verkleproof struct { Proof *verkle.Proof Cis []*verkle.Point Indices []byte Yis []*verkle.Fr Leaves []KeyValuePair } func (trie *VerkleTrie) ProveAndSerialize(keys [][]byte, kv map[common.Hash][]byte) ([]byte, error) { proof, cis, indices, yis := verkle.MakeVerkleMultiProof(trie.root, keys) vp := verkleproof{ Proof: proof, Cis: cis, Indices: indices, Yis: yis, } for key, val := range kv { var k [32]byte copy(k[:], key[:]) vp.Leaves = append(vp.Leaves, KeyValuePair{ Key: k[:], Value: val, }) } return rlp.EncodeToBytes(vp) } func DeserializeAndVerifyVerkleProof(serialized []byte) (map[common.Hash]common.Hash, error) { proof, cis, indices, yis, leaves, err := deserializeVerkleProof(serialized) if err != nil { return nil, fmt.Errorf("could not deserialize proof: %w", err) } if !verkle.VerifyVerkleProof(proof, cis, indices, yis, verkle.GetConfig()) { return nil, errInvalidProof } return leaves, nil } func deserializeVerkleProof(proof []byte) (*verkle.Proof, []*verkle.Point, []byte, []*verkle.Fr, map[common.Hash]common.Hash, error) { var vp verkleproof err := rlp.DecodeBytes(proof, &vp) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("verkle proof deserialization error: %w", err) } leaves := make(map[common.Hash]common.Hash, len(vp.Leaves)) for _, kvp := range vp.Leaves { leaves[common.BytesToHash(kvp.Key)] = common.BytesToHash(kvp.Value) } return vp.Proof, vp.Cis, vp.Indices, vp.Yis, leaves, nil } // Copy the values here so as to avoid an import cycle const ( PUSH1 = 0x60 PUSH32 = 0x71 ) func ChunkifyCode(addr common.Address, code []byte) ([][32]byte, error) { lastOffset := byte(0) chunkCount := len(code) / 31 if len(code)%31 != 0 { chunkCount++ } chunks := make([][32]byte, chunkCount) for i := range chunks { end := 31 * (i + 1) if len(code) < end { end = len(code) } copy(chunks[i][1:], code[31*i:end]) for j := lastOffset; int(j) < len(code[31*i:end]); j++ { if code[j] >= byte(PUSH1) && code[j] <= byte(PUSH32) { j += code[j] - byte(PUSH1) + 1 lastOffset = (j + 1) % 31 } } chunks[i][0] = lastOffset } return chunks, nil }