github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/mpt/base.go (about) 1 package mpt 2 3 import ( 4 "fmt" 5 6 "github.com/nspcc-dev/neo-go/pkg/crypto/hash" 7 "github.com/nspcc-dev/neo-go/pkg/io" 8 "github.com/nspcc-dev/neo-go/pkg/util" 9 ) 10 11 // BaseNode implements basic things every node needs like caching hash and 12 // serialized representation. It's a basic node building block intended to be 13 // included into all node types. 14 type BaseNode struct { 15 hash util.Uint256 16 bytes []byte 17 hashValid bool 18 bytesValid bool 19 } 20 21 // BaseNodeIface abstracts away basic Node functions. 22 type BaseNodeIface interface { 23 Hash() util.Uint256 24 Type() NodeType 25 Bytes() []byte 26 } 27 28 type flushedNode interface { 29 setCache([]byte, util.Uint256) 30 } 31 32 func (b *BaseNode) setCache(bs []byte, h util.Uint256) { 33 b.bytes = bs 34 b.hash = h 35 b.bytesValid = true 36 b.hashValid = true 37 } 38 39 // getHash returns the hash of this BaseNode. 40 func (b *BaseNode) getHash(n Node) util.Uint256 { 41 if !b.hashValid { 42 b.updateHash(n) 43 } 44 return b.hash 45 } 46 47 // getBytes returns a slice of bytes representing this node. 48 func (b *BaseNode) getBytes(n Node) []byte { 49 if !b.bytesValid { 50 b.updateBytes(n) 51 } 52 return b.bytes 53 } 54 55 // updateHash updates the hash field for this BaseNode. 56 func (b *BaseNode) updateHash(n Node) { 57 if n.Type() == HashT || n.Type() == EmptyT { 58 panic("can't update hash for empty or hash node") 59 } 60 b.hash = hash.DoubleSha256(b.getBytes(n)) 61 b.hashValid = true 62 } 63 64 // updateCache updates the hash and bytes fields for this BaseNode. 65 func (b *BaseNode) updateBytes(n Node) { 66 bw := io.NewBufBinWriter() 67 bw.Grow(1 + n.Size()) 68 encodeNodeWithType(n, bw.BinWriter) 69 b.bytes = bw.Bytes() 70 b.bytesValid = true 71 } 72 73 // invalidateCache sets all cache fields to invalid state. 74 func (b *BaseNode) invalidateCache() { 75 b.bytesValid = false 76 b.hashValid = false 77 } 78 79 func encodeBinaryAsChild(n Node, w *io.BinWriter) { 80 if isEmpty(n) { 81 w.WriteB(byte(EmptyT)) 82 return 83 } 84 w.WriteB(byte(HashT)) 85 w.WriteBytes(n.Hash().BytesBE()) 86 } 87 88 // encodeNodeWithType encodes the node together with its type. 89 func encodeNodeWithType(n Node, w *io.BinWriter) { 90 w.WriteB(byte(n.Type())) 91 n.EncodeBinary(w) 92 } 93 94 // DecodeNodeWithType decodes the node together with its type. 95 func DecodeNodeWithType(r *io.BinReader) Node { 96 if r.Err != nil { 97 return nil 98 } 99 var n Node 100 switch typ := NodeType(r.ReadB()); typ { 101 case BranchT: 102 n = new(BranchNode) 103 case ExtensionT: 104 n = new(ExtensionNode) 105 case HashT: 106 n = &HashNode{ 107 BaseNode: BaseNode{ 108 hashValid: true, 109 }, 110 } 111 case LeafT: 112 n = new(LeafNode) 113 case EmptyT: 114 n = EmptyNode{} 115 default: 116 r.Err = fmt.Errorf("invalid node type: %x", typ) 117 return nil 118 } 119 n.DecodeBinary(r) 120 return n 121 }