public void FinishPairing() { if (this.leftNodes.Count == 0) throw new InvalidOperationException(); while (this.leftNodes.Count > 1) { var leftNode = this.leftNodes.Last(); var rightNode = new MerkleTreeNode(leftNode.Index + (1 << leftNode.Depth), leftNode.Depth, leftNode.Hash, pruned: true); AddNode(rightNode); } }
public void TestCalculateMerkleRoot() { var node1 = new MerkleTreeNode(index: 0, depth: 0, hash: (UInt256)1, pruned: false); var node2 = new MerkleTreeNode(index: 1, depth: 0, hash: (UInt256)2, pruned: false); var node3 = new MerkleTreeNode(index: 2, depth: 0, hash: (UInt256)3, pruned: false); var depth1Hash1 = MerkleTree.PairHashes(node1.Hash, node2.Hash); var depth1Hash2 = MerkleTree.PairHashes(node3.Hash, node3.Hash); var expectedMerkleRoot = MerkleTree.PairHashes(depth1Hash1, depth1Hash2); var hashes = new List<UInt256> { node1.Hash, node2.Hash, node3.Hash }; var actualMerkleRoot = MerkleTree.CalculateMerkleRoot(hashes); ; Assert.AreEqual(expectedMerkleRoot, actualMerkleRoot); }
public static MerkleTreeNode Pair(MerkleTreeNode left, MerkleTreeNode right) { if (left.Depth != right.Depth) throw new InvalidOperationException(); if (!left.Pruned) throw new ArgumentException("left"); if (!right.Pruned) throw new ArgumentException("right"); var expectedIndex = left.Index + (1 << left.Depth); if (right.Index != expectedIndex) throw new InvalidOperationException(); var pairHashBytes = new byte[64]; left.Hash.ToByteArray(pairHashBytes, 0); right.Hash.ToByteArray(pairHashBytes, 32); var pairHash = new UInt256(SHA256Static.ComputeDoubleHash(pairHashBytes)); return new MerkleTreeNode(left.Index, left.Depth + 1, pairHash, pruned: true); }
public void AddNode(MerkleTreeNode newNode) { // verify index is as expected if (newNode.Index != this.expectedIndex) throw new InvalidOperationException(); // determine the index the next node should be this.expectedIndex += 1 << newNode.Depth; // when streamining nodes, treat them as being pruned so they can be paired together newNode = newNode.AsPruned(); if (this.leftNodes.Count == 0) { this.leftNodes.Add(newNode); } else { var leftNode = this.leftNodes.Last(); if (newNode.Depth < leftNode.Depth) { this.leftNodes.Add(newNode); } else if (newNode.Depth == leftNode.Depth) { this.leftNodes[this.leftNodes.Count - 1] = leftNode.PairWith(newNode); } else if (newNode.Depth > leftNode.Depth) { throw new InvalidOperationException(); } this.ClosePairs(); } }
public void TestPruneMerkleTreeNodes() { var node1 = new MerkleTreeNode(index: 0, depth: 0, hash: (UInt256)1, pruned: false); var node2 = new MerkleTreeNode(index: 1, depth: 0, hash: (UInt256)2, pruned: false); var node3 = new MerkleTreeNode(index: 2, depth: 0, hash: (UInt256)3, pruned: false); var node4 = new MerkleTreeNode(index: 3, depth: 0, hash: (UInt256)4, pruned: false); var node5 = new MerkleTreeNode(index: 4, depth: 0, hash: (UInt256)5, pruned: false); var node6 = new MerkleTreeNode(index: 5, depth: 0, hash: (UInt256)6, pruned: false); var node7 = new MerkleTreeNode(index: 6, depth: 0, hash: (UInt256)7, pruned: false); var depth1Node1 = node1.AsPruned().PairWith(node2.AsPruned()); var depth1Node2 = node3.AsPruned().PairWith(node4.AsPruned()); var depth1Node3 = node5.AsPruned().PairWith(node6.AsPruned()); var depth1Node4 = node7.AsPruned().PairWithSelf(); var depth2Node1 = depth1Node1.PairWith(depth1Node2); var depth2Node2 = depth1Node3.PairWith(depth1Node4); var merkleRoot = depth2Node1.PairWith(depth2Node2); var nodes = new List<MerkleTreeNode> { node1, node2, node3, node4, node5, node6, node7 }; var cursor = new MemoryMerkleTreePruningCursor<MerkleTreeNode>(nodes); ////////////////////////////////////////////////// var expectedNodes1 = nodes; var actualNodes1 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes1, actualNodes1); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 2); var expectedNodes2 = new List<MerkleTreeNode> { node1, node2, node3.AsPruned(), node4, node5, node6, node7 }; var actualNodes2 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes2, actualNodes2); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 0); var expectedNodes3 = new List<MerkleTreeNode> { node1.AsPruned(), node2, node3.AsPruned(), node4, node5, node6, node7 }; var actualNodes3 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes3, actualNodes3); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 1); var expectedNodes4 = new List<MerkleTreeNode> { depth1Node1, node3.AsPruned(), node4, node5, node6, node7 }; var actualNodes4 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes4, actualNodes4); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 3); var expectedNodes5 = new List<MerkleTreeNode> { depth2Node1, node5, node6, node7 }; var actualNodes5 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes5, actualNodes5); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 5); var expectedNodes6 = new List<MerkleTreeNode> { depth2Node1, node5, node6.AsPruned(), node7 }; var actualNodes6 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes6, actualNodes6); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 6); var expectedNodes8 = new List<MerkleTreeNode> { depth2Node1, node5, node6.AsPruned(), depth1Node4 }; var actualNodes8 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes8, actualNodes8); ////////////////////////////////////////////////// MerkleTree.PruneNode(cursor, 4); var expectedNodes9 = new List<MerkleTreeNode> { merkleRoot }; var actualNodes9 = cursor.ReadNodes().ToList(); CollectionAssert.AreEqual(expectedNodes9, actualNodes9); }
public void TestReadMerkleTreeNodes() { var node1 = new MerkleTreeNode(index: 0, depth: 0, hash: (UInt256)1, pruned: false); var node2 = new MerkleTreeNode(index: 1, depth: 0, hash: (UInt256)2, pruned: false); var node3 = new MerkleTreeNode(index: 2, depth: 0, hash: (UInt256)3, pruned: false); var node4 = new MerkleTreeNode(index: 3, depth: 0, hash: (UInt256)4, pruned: false); var depth1Hash1 = MerkleTree.PairHashes(node1.Hash, node2.Hash); var depth1Hash2 = MerkleTree.PairHashes(node3.Hash, node4.Hash); var merkleRoot = MerkleTree.PairHashes(depth1Hash1, depth1Hash2); var nodes = new List<MerkleTreeNode> { node1, node2, node3, node4 }; var actualNodes = MerkleTree.ReadMerkleTreeNodes(merkleRoot, nodes).ToList(); CollectionAssert.AreEqual(nodes, actualNodes); }
public void WriteNode(MerkleTreeNode node) { if (!node.Pruned) throw new ArgumentException(); var recordBlockIndexColumn = new Int32ColumnValue { Columnid = cursor.blockIndexColumnId }; var recordTxIndexColumn = new Int32ColumnValue { Columnid = cursor.txIndexColumnId }; Api.RetrieveColumns(cursor.jetSession, cursor.blocksTableId, recordBlockIndexColumn, recordTxIndexColumn); if (this.blockIndex != recordBlockIndexColumn.Value.Value) throw new InvalidOperationException(); if (node.Index != recordTxIndexColumn.Value.Value) throw new InvalidOperationException(); using (var jetUpdate = cursor.jetSession.BeginUpdate(cursor.blocksTableId, JET_prep.Replace)) { Api.SetColumns(cursor.jetSession, cursor.blocksTableId, new Int32ColumnValue { Columnid = cursor.blockDepthColumnId, Value = node.Depth }, new BytesColumnValue { Columnid = cursor.blockTxHashColumnId, Value = DbEncoder.EncodeUInt256(node.Hash) }, new Int32ColumnValue { Columnid = cursor.blockTxBytesColumnId, Value = null }); jetUpdate.Save(); } }
public void WriteNode(MerkleTreeNode node) { if (!node.Pruned) throw new InvalidOperationException(); if (this.index < 0 || this.index >= this.nodes.Count) throw new InvalidOperationException(); this.nodes[this.index] = new BlockTx(node.Index, node.Depth, node.Hash, node.Pruned, null); }
public void WriteNode(MerkleTreeNode node) { if (!node.Pruned) throw new ArgumentException(); var kvPair = cursor.GetCurrent().Value; UInt256 recordBlockHash; int txIndex; DbEncoder.DecodeBlockHashTxIndex(kvPair.Key, out recordBlockHash, out txIndex); if (this.blockHash != recordBlockHash) throw new InvalidOperationException(); if (node.Index != txIndex) throw new InvalidOperationException(); var key = DbEncoder.EncodeBlockHashTxIndex(blockHash, node.Index); var blockTx = new BlockTx(node.Index, node.Depth, node.Hash, node.Pruned, null); cursor.Put(key, DataEncoder.EncodeBlockTx(blockTx), CursorPutOptions.Current); }
public static MerkleTreeNode PairWithSelf(MerkleTreeNode node) { if (!node.Pruned) throw new ArgumentException("left"); return Pair(node, new MerkleTreeNode(node.Index + (1 << node.Depth), node.Depth, node.Hash, pruned: true)); }
public MerkleTreeNode PairWith(MerkleTreeNode right) { return Pair(this, right); }
public MerkleTreeNode PairWith(MerkleTreeNode right) { return(Pair(this, right)); }