public static MPTNode NewHash(UInt256 hash) { if (hash is null) { throw new ArgumentNullException(nameof(NewHash)); } var n = new MPTNode { type = NodeType.HashNode, hash = hash, }; return(n); }
public static MPTNode NewLeaf(byte[] value) { if (value is null) { throw new ArgumentNullException(nameof(value)); } var n = new MPTNode { type = NodeType.LeafNode, Value = value, Reference = 1, }; return(n); }
public static MPTNode NewBranch() { var n = new MPTNode { type = NodeType.BranchNode, Reference = 1, Children = new MPTNode[BranchChildCount], }; for (int i = 0; i < BranchChildCount; i++) { n.Children[i] = new MPTNode(); } return(n); }
public void PutNode(MPTNode np) { var n = Resolve(np.Hash); if (n is null) { np.Reference = 1; cache[np.Hash] = new Trackable { Node = np.Clone(), State = TrackState.Added, }; return; } var entry = cache[np.Hash]; entry.Node.Reference++; entry.State = TrackState.Changed; }
public MPTNode Clone() { switch (type) { case NodeType.BranchNode: var n = new MPTNode { type = type, Reference = Reference, Children = new MPTNode[BranchChildCount], }; for (int i = 0; i < BranchChildCount; i++) { n.Children[i] = Children[i].CloneAsChild(); } return(n); case NodeType.ExtensionNode: return(new MPTNode { type = type, Key = (byte[])Key.Clone(), Next = Next.CloneAsChild(), Reference = Reference, }); case NodeType.LeafNode: return(new MPTNode { type = type, Value = (byte[])Value.Clone(), Reference = Reference, }); case NodeType.HashNode: case NodeType.Empty: return(this); default: throw new InvalidOperationException(nameof(Clone)); } }
public static MPTNode NewExtension(byte[] key, MPTNode next) { if (key is null || next is null) { throw new ArgumentNullException(nameof(NewExtension)); } if (key.Length == 0) { throw new InvalidOperationException(nameof(NewExtension)); } var n = new MPTNode { type = NodeType.ExtensionNode, Key = key, Next = next, Reference = 1, }; return(n); }
private bool GetProof(ref MPTNode node, ReadOnlySpan <byte> path, HashSet <byte[]> set) { switch (node.Type) { case NodeType.LeafNode: { if (path.IsEmpty) { set.Add(node.ToArrayWithoutReference()); return(true); } break; } case NodeType.Empty: break; case NodeType.HashNode: { var newNode = cache.Resolve(node.Hash); if (newNode is null) { throw new InvalidOperationException("Internal error, can't resolve hash when mpt getproof"); } node = newNode; return(GetProof(ref node, path, set)); } case NodeType.BranchNode: { set.Add(node.ToArrayWithoutReference()); if (path.IsEmpty) { return(GetProof(ref node.Children[MPTNode.BranchChildCount - 1], path, set)); } return(GetProof(ref node.Children[path[0]], path[1..], set));
private bool TryDelete(ref MPTNode node, ReadOnlySpan <byte> path) { switch (node.Type) { case NodeType.LeafNode: { if (path.IsEmpty) { if (!full) { cache.DeleteNode(node.Hash); } node = new MPTNode(); return(true); } return(false); } case NodeType.ExtensionNode: { if (path.StartsWith(node.Key)) { var oldHash = node.Hash; var result = TryDelete(ref node.Next, path[node.Key.Length..]);
private ReadOnlySpan <byte> Seek(ref MPTNode node, ReadOnlySpan <byte> path, out MPTNode start) { switch (node.Type) { case NodeType.LeafNode: { if (path.IsEmpty) { start = node; return(ReadOnlySpan <byte> .Empty); } break; } case NodeType.Empty: break; case NodeType.HashNode: { var newNode = cache.Resolve(node.Hash); if (newNode is null) { throw new InvalidOperationException("Internal error, can't resolve hash when mpt seek"); } node = newNode; return(Seek(ref node, path, out start)); } case NodeType.BranchNode: { if (path.IsEmpty) { start = node; return(ReadOnlySpan <byte> .Empty); } return(Concat(path[..1], Seek(ref node.Children[path[0]], path[1..], out start)));