neo-go/pkg/core/mpt/leaf.go
Anna Shaleva 36808b8904 core: clone MPT node while restoring it multiple times
We need this to avoid collapse collisions. Example of such collapse
described in
https://github.com/nspcc-dev/neo-go/pull/2019#discussion_r689629704.
2021-09-07 19:43:27 +03:00

85 lines
1.9 KiB
Go

package mpt
import (
"encoding/hex"
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// MaxValueLength is a max length of a leaf node value.
const MaxValueLength = 3 + storage.MaxStorageValueLen + 1
// LeafNode represents MPT's leaf node.
type LeafNode struct {
BaseNode
value []byte
}
var _ Node = (*LeafNode)(nil)
// NewLeafNode returns hash node with the specified value.
func NewLeafNode(value []byte) *LeafNode {
return &LeafNode{value: value}
}
// Type implements Node interface.
func (n LeafNode) Type() NodeType { return LeafT }
// Hash implements BaseNode interface.
func (n *LeafNode) Hash() util.Uint256 {
return n.getHash(n)
}
// Bytes implements BaseNode interface.
func (n *LeafNode) Bytes() []byte {
return n.getBytes(n)
}
// DecodeBinary implements io.Serializable.
func (n *LeafNode) DecodeBinary(r *io.BinReader) {
sz := r.ReadVarUint()
if sz > MaxValueLength {
r.Err = fmt.Errorf("leaf node value is too big: %d", sz)
return
}
n.value = make([]byte, sz)
r.ReadBytes(n.value)
n.invalidateCache()
}
// EncodeBinary implements io.Serializable.
func (n LeafNode) EncodeBinary(w *io.BinWriter) {
w.WriteVarBytes(n.value)
}
// Size implements Node interface.
func (n *LeafNode) Size() int {
return io.GetVarSize(len(n.value)) + len(n.value)
}
// MarshalJSON implements json.Marshaler.
func (n *LeafNode) MarshalJSON() ([]byte, error) {
return []byte(`{"value":"` + hex.EncodeToString(n.value) + `"}`), nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (n *LeafNode) UnmarshalJSON(data []byte) error {
var obj NodeObject
if err := obj.UnmarshalJSON(data); err != nil {
return err
} else if u, ok := obj.Node.(*LeafNode); ok {
*n = *u
return nil
}
return errors.New("expected leaf node")
}
// Clone implements Node interface.
func (n *LeafNode) Clone() Node {
res := *n
return &res
}