github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/mpt/extension.go (about)

     1  package mpt
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/nspcc-dev/neo-go/pkg/config/limits"
    10  	"github.com/nspcc-dev/neo-go/pkg/io"
    11  	"github.com/nspcc-dev/neo-go/pkg/util"
    12  )
    13  
    14  const (
    15  	// maxPathLength is the max length of the extension node key.
    16  	maxPathLength = (limits.MaxStorageKeyLen + 4) * 2
    17  
    18  	// MaxKeyLength is the max length of the key to put in the trie
    19  	// before transforming to nibbles.
    20  	MaxKeyLength = maxPathLength / 2
    21  )
    22  
    23  // ExtensionNode represents an MPT's extension node.
    24  type ExtensionNode struct {
    25  	BaseNode
    26  	key  []byte
    27  	next Node
    28  }
    29  
    30  var _ Node = (*ExtensionNode)(nil)
    31  
    32  // NewExtensionNode returns a hash node with the specified key and the next node.
    33  // Note: since it is a part of a Trie, the key must be mangled, i.e. must contain only bytes with high half = 0.
    34  func NewExtensionNode(key []byte, next Node) *ExtensionNode {
    35  	return &ExtensionNode{
    36  		key:  key,
    37  		next: next,
    38  	}
    39  }
    40  
    41  // Type implements Node interface.
    42  func (e ExtensionNode) Type() NodeType { return ExtensionT }
    43  
    44  // Hash implements BaseNode interface.
    45  func (e *ExtensionNode) Hash() util.Uint256 {
    46  	return e.getHash(e)
    47  }
    48  
    49  // Bytes implements BaseNode interface.
    50  func (e *ExtensionNode) Bytes() []byte {
    51  	return e.getBytes(e)
    52  }
    53  
    54  // DecodeBinary implements io.Serializable.
    55  func (e *ExtensionNode) DecodeBinary(r *io.BinReader) {
    56  	sz := r.ReadVarUint()
    57  	if sz > maxPathLength {
    58  		r.Err = fmt.Errorf("extension node key is too big: %d", sz)
    59  		return
    60  	}
    61  	e.key = make([]byte, sz)
    62  	r.ReadBytes(e.key)
    63  	no := new(NodeObject)
    64  	no.DecodeBinary(r)
    65  	e.next = no.Node
    66  	e.invalidateCache()
    67  }
    68  
    69  // EncodeBinary implements io.Serializable.
    70  func (e ExtensionNode) EncodeBinary(w *io.BinWriter) {
    71  	w.WriteVarBytes(e.key)
    72  	encodeBinaryAsChild(e.next, w)
    73  }
    74  
    75  // Size implements Node interface.
    76  func (e *ExtensionNode) Size() int {
    77  	return io.GetVarSize(len(e.key)) + len(e.key) +
    78  		1 + util.Uint256Size // e.next is never empty
    79  }
    80  
    81  // MarshalJSON implements the json.Marshaler.
    82  func (e *ExtensionNode) MarshalJSON() ([]byte, error) {
    83  	m := map[string]any{
    84  		"key":  hex.EncodeToString(e.key),
    85  		"next": e.next,
    86  	}
    87  	return json.Marshal(m)
    88  }
    89  
    90  // UnmarshalJSON implements the json.Unmarshaler.
    91  func (e *ExtensionNode) UnmarshalJSON(data []byte) error {
    92  	var obj NodeObject
    93  	if err := obj.UnmarshalJSON(data); err != nil {
    94  		return err
    95  	} else if u, ok := obj.Node.(*ExtensionNode); ok {
    96  		*e = *u
    97  		return nil
    98  	}
    99  	return errors.New("expected extension node")
   100  }
   101  
   102  // Clone implements Node interface.
   103  func (e *ExtensionNode) Clone() Node {
   104  	res := *e
   105  	return &res
   106  }