github.com/ethereum/go-ethereum@v1.16.1/core/stateless/witness.go (about) 1 // Copyright 2024 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package stateless 18 19 import ( 20 "errors" 21 "maps" 22 "slices" 23 "sync" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core/types" 27 ) 28 29 // HeaderReader is an interface to pull in headers in place of block hashes for 30 // the witness. 31 type HeaderReader interface { 32 // GetHeader retrieves a block header from the database by hash and number, 33 GetHeader(hash common.Hash, number uint64) *types.Header 34 } 35 36 // Witness encompasses the state required to apply a set of transactions and 37 // derive a post state/receipt root. 38 type Witness struct { 39 context *types.Header // Header to which this witness belongs to, with rootHash and receiptHash zeroed out 40 41 Headers []*types.Header // Past headers in reverse order (0=parent, 1=parent's-parent, etc). First *must* be set. 42 Codes map[string]struct{} // Set of bytecodes ran or accessed 43 State map[string]struct{} // Set of MPT state trie nodes (account and storage together) 44 45 chain HeaderReader // Chain reader to convert block hash ops to header proofs 46 lock sync.Mutex // Lock to allow concurrent state insertions 47 } 48 49 // NewWitness creates an empty witness ready for population. 50 func NewWitness(context *types.Header, chain HeaderReader) (*Witness, error) { 51 // When building witnesses, retrieve the parent header, which will *always* 52 // be included to act as a trustless pre-root hash container 53 var headers []*types.Header 54 if chain != nil { 55 parent := chain.GetHeader(context.ParentHash, context.Number.Uint64()-1) 56 if parent == nil { 57 return nil, errors.New("failed to retrieve parent header") 58 } 59 headers = append(headers, parent) 60 } 61 // Create the wtness with a reconstructed gutted out block 62 return &Witness{ 63 context: context, 64 Headers: headers, 65 Codes: make(map[string]struct{}), 66 State: make(map[string]struct{}), 67 chain: chain, 68 }, nil 69 } 70 71 // AddBlockHash adds a "blockhash" to the witness with the designated offset from 72 // chain head. Under the hood, this method actually pulls in enough headers from 73 // the chain to cover the block being added. 74 func (w *Witness) AddBlockHash(number uint64) { 75 // Keep pulling in headers until this hash is populated 76 for int(w.context.Number.Uint64()-number) > len(w.Headers) { 77 tail := w.Headers[len(w.Headers)-1] 78 w.Headers = append(w.Headers, w.chain.GetHeader(tail.ParentHash, tail.Number.Uint64()-1)) 79 } 80 } 81 82 // AddCode adds a bytecode blob to the witness. 83 func (w *Witness) AddCode(code []byte) { 84 if len(code) == 0 { 85 return 86 } 87 w.Codes[string(code)] = struct{}{} 88 } 89 90 // AddState inserts a batch of MPT trie nodes into the witness. 91 func (w *Witness) AddState(nodes map[string]struct{}) { 92 if len(nodes) == 0 { 93 return 94 } 95 w.lock.Lock() 96 defer w.lock.Unlock() 97 98 maps.Copy(w.State, nodes) 99 } 100 101 // Copy deep-copies the witness object. Witness.Block isn't deep-copied as it 102 // is never mutated by Witness 103 func (w *Witness) Copy() *Witness { 104 cpy := &Witness{ 105 Headers: slices.Clone(w.Headers), 106 Codes: maps.Clone(w.Codes), 107 State: maps.Clone(w.State), 108 chain: w.chain, 109 } 110 if w.context != nil { 111 cpy.context = types.CopyHeader(w.context) 112 } 113 return cpy 114 } 115 116 // Root returns the pre-state root from the first header. 117 // 118 // Note, this method will panic in case of a bad witness (but RLP decoding will 119 // sanitize it and fail before that). 120 func (w *Witness) Root() common.Hash { 121 return w.Headers[0].Root 122 }