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  }