2020-06-02 20:49:46 +00:00
|
|
|
package mpt
|
|
|
|
|
|
|
|
import (
|
2020-10-23 07:55:08 +00:00
|
|
|
"fmt"
|
|
|
|
|
2020-06-02 20:49:46 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// BaseNode implements basic things every node needs like caching hash and
|
|
|
|
// serialized representation. It's a basic node building block intended to be
|
|
|
|
// included into all node types.
|
|
|
|
type BaseNode struct {
|
|
|
|
hash util.Uint256
|
|
|
|
bytes []byte
|
|
|
|
hashValid bool
|
|
|
|
bytesValid bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// BaseNodeIface abstracts away basic Node functions.
|
|
|
|
type BaseNodeIface interface {
|
|
|
|
Hash() util.Uint256
|
|
|
|
Type() NodeType
|
|
|
|
Bytes() []byte
|
|
|
|
}
|
|
|
|
|
2020-10-23 07:58:51 +00:00
|
|
|
type flushedNode interface {
|
|
|
|
setCache([]byte, util.Uint256)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BaseNode) setCache(bs []byte, h util.Uint256) {
|
|
|
|
b.bytes = bs
|
|
|
|
b.hash = h
|
|
|
|
b.bytesValid = true
|
|
|
|
b.hashValid = true
|
|
|
|
}
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// getHash returns the hash of this BaseNode.
|
2020-06-02 20:49:46 +00:00
|
|
|
func (b *BaseNode) getHash(n Node) util.Uint256 {
|
|
|
|
if !b.hashValid {
|
|
|
|
b.updateHash(n)
|
|
|
|
}
|
|
|
|
return b.hash
|
|
|
|
}
|
|
|
|
|
|
|
|
// getBytes returns a slice of bytes representing this node.
|
|
|
|
func (b *BaseNode) getBytes(n Node) []byte {
|
|
|
|
if !b.bytesValid {
|
|
|
|
b.updateBytes(n)
|
|
|
|
}
|
|
|
|
return b.bytes
|
|
|
|
}
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// updateHash updates the hash field for this BaseNode.
|
2020-06-02 20:49:46 +00:00
|
|
|
func (b *BaseNode) updateHash(n Node) {
|
2021-08-03 14:10:46 +00:00
|
|
|
if n.Type() == HashT || n.Type() == EmptyT {
|
|
|
|
panic("can't update hash for empty or hash node")
|
2020-06-02 20:49:46 +00:00
|
|
|
}
|
|
|
|
b.hash = hash.DoubleSha256(b.getBytes(n))
|
|
|
|
b.hashValid = true
|
|
|
|
}
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// updateCache updates the hash and bytes fields for this BaseNode.
|
2020-06-02 20:49:46 +00:00
|
|
|
func (b *BaseNode) updateBytes(n Node) {
|
2021-08-06 08:32:02 +00:00
|
|
|
bw := io.NewBufBinWriter()
|
|
|
|
bw.Grow(1 + n.Size())
|
|
|
|
encodeNodeWithType(n, bw.BinWriter)
|
|
|
|
b.bytes = bw.Bytes()
|
2020-06-02 20:49:46 +00:00
|
|
|
b.bytesValid = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// invalidateCache sets all cache fields to invalid state.
|
|
|
|
func (b *BaseNode) invalidateCache() {
|
|
|
|
b.bytesValid = false
|
|
|
|
b.hashValid = false
|
|
|
|
}
|
|
|
|
|
2021-08-03 11:19:50 +00:00
|
|
|
func encodeBinaryAsChild(n Node, w *io.BinWriter) {
|
|
|
|
if isEmpty(n) {
|
|
|
|
w.WriteB(byte(EmptyT))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.WriteB(byte(HashT))
|
|
|
|
w.WriteBytes(n.Hash().BytesBE())
|
|
|
|
}
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// encodeNodeWithType encodes the node together with its type.
|
2020-06-02 20:49:46 +00:00
|
|
|
func encodeNodeWithType(n Node, w *io.BinWriter) {
|
2021-08-03 14:10:46 +00:00
|
|
|
w.WriteB(byte(n.Type()))
|
2020-06-02 20:49:46 +00:00
|
|
|
n.EncodeBinary(w)
|
|
|
|
}
|
2020-10-23 07:55:08 +00:00
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// DecodeNodeWithType decodes the node together with its type.
|
2020-10-23 07:55:08 +00:00
|
|
|
func DecodeNodeWithType(r *io.BinReader) Node {
|
2020-10-21 13:58:41 +00:00
|
|
|
if r.Err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-23 07:55:08 +00:00
|
|
|
var n Node
|
|
|
|
switch typ := NodeType(r.ReadB()); typ {
|
|
|
|
case BranchT:
|
|
|
|
n = new(BranchNode)
|
|
|
|
case ExtensionT:
|
|
|
|
n = new(ExtensionNode)
|
|
|
|
case HashT:
|
2021-03-30 17:35:41 +00:00
|
|
|
n = &HashNode{
|
|
|
|
BaseNode: BaseNode{
|
|
|
|
hashValid: true,
|
|
|
|
},
|
|
|
|
}
|
2020-10-23 07:55:08 +00:00
|
|
|
case LeafT:
|
|
|
|
n = new(LeafNode)
|
2021-03-30 17:35:41 +00:00
|
|
|
case EmptyT:
|
2021-08-03 14:10:46 +00:00
|
|
|
n = EmptyNode{}
|
2020-10-23 07:55:08 +00:00
|
|
|
default:
|
|
|
|
r.Err = fmt.Errorf("invalid node type: %x", typ)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
n.DecodeBinary(r)
|
|
|
|
return n
|
|
|
|
}
|