Ejemplo n.º 1
0
 public static byte[] EncodeBlockTxNode(BlockTxNode blockTx)
 {
     using (var stream = new MemoryStream())
         using (var writer = new BinaryWriter(stream))
         {
             EncodeBlockTxNode(writer, blockTx);
             return(stream.ToArray());
         }
 }
Ejemplo n.º 2
0
 public static void EncodeBlockTxNode(BinaryWriter writer, BlockTxNode blockTx)
 {
     writer.WriteInt32(blockTx.Index);
     writer.WriteInt32(blockTx.Depth);
     writer.WriteUInt256(blockTx.Hash);
     writer.WriteBool(blockTx.Pruned);
     if (!blockTx.Pruned)
     {
         writer.WriteBytes(blockTx.TxBytes.ToArray());
     }
 }
Ejemplo n.º 3
0
        // IBlockTxesStorage.PruneElements
        private void TestPruneElements(ITestStorageProvider provider)
        {
            // run 4 iterations of pruning: no adjacent blocks, one adjacent block on either side, and two adjacent blocks
            for (var iteration = 0; iteration < 4; iteration++)
            {
                provider.TestCleanup();

                using (var kernel = new StandardKernel())
                using (var storageManager = provider.OpenStorageManager())
                {
                    // add logging module
                    kernel.Load(new ConsoleLoggingModule(LogLevel.Debug));

                    var blockTxesStorage = storageManager.BlockTxesStorage;

                    // create a block
                    var block = CreateFakeBlock();
                    var txCount = block.Transactions.Length;

                    // determine expected merkle root node when fully pruned
                    var expectedFinalDepth = (int)Math.Ceiling(Math.Log(txCount, 2));
                    var expectedFinalElement = new BlockTxNode(index: 0, depth: expectedFinalDepth, hash: block.Header.MerkleRoot, pruned: true, encodedTx: null);

                    // pick a random pruning order
                    var random = new Random();
                    var pruneOrderSource = Enumerable.Range(0, txCount).ToList();
                    var pruneOrder = new List<int>(txCount);
                    while (pruneOrderSource.Count > 0)
                    {
                        var randomIndex = random.Next(pruneOrderSource.Count);

                        pruneOrder.Add(pruneOrderSource[randomIndex]);
                        pruneOrderSource.RemoveAt(randomIndex);
                    }

                    // add preceding block
                    if (iteration == 1 || iteration == 3)
                        blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() - 1), block.BlockTxes);

                    // add the block to be pruned
                    blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                    // add proceeding block
                    if (iteration == 2 || iteration == 3)
                        blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() + 1), block.BlockTxes);

                    // prune the block
                    var count = 0;
                    foreach (var pruneIndex in pruneOrder)
                    {
                        Debug.WriteLine(count++);

                        // prune a transaction
                        blockTxesStorage.PruneElements(new[] { new KeyValuePair<UInt256, IEnumerable<int>>(block.Hash, new[] { pruneIndex }) });

                        // read block transactions
                        IEnumerator<BlockTxNode> blockTxNodes;
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out blockTxNodes));

                        // verify block transactions, exception will be fired if invalid
                        MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, blockTxNodes.UsingAsEnumerable()).Count();
                    }

                    // read fully pruned block and verify
                    IEnumerator<BlockTxNode> finalBlockTxNodes;
                    Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out finalBlockTxNodes));
                    var finalNodes = MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).ToList();
                    Assert.AreEqual(1, finalNodes.Count);
                    Assert.AreEqual(expectedFinalElement, finalNodes[0]);

                    // verify preceding block was not affected
                    if (iteration == 1 || iteration == 3)
                    {
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() - 1), out finalBlockTxNodes));

                        // verify block transactions, exception will be fired if invalid
                        Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                    }

                    // verify proceeding block was not affected
                    if (iteration == 2 || iteration == 3)
                    {
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() + 1), out finalBlockTxNodes));

                        // verify block transactions, exception will be fired if invalid
                        Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                    }
                }
            }
        }
Ejemplo n.º 4
0
        // IBlockTxesStorage.PruneElements
        private void TestPruneElements(ITestStorageProvider provider)
        {
            // run 4 iterations of pruning: no adjacent blocks, one adjacent block on either side, and two adjacent blocks
            for (var iteration = 0; iteration < 4; iteration++)
            {
                provider.TestCleanup();

                using (var kernel = new StandardKernel())
                    using (var storageManager = provider.OpenStorageManager())
                    {
                        // add logging module
                        kernel.Load(new ConsoleLoggingModule(LogLevel.Debug));

                        var blockTxesStorage = storageManager.BlockTxesStorage;

                        // create a block
                        var block   = CreateFakeBlock();
                        var txCount = block.Transactions.Length;

                        // determine expected merkle root node when fully pruned
                        var expectedFinalDepth   = (int)Math.Ceiling(Math.Log(txCount, 2));
                        var expectedFinalElement = new BlockTxNode(index: 0, depth: expectedFinalDepth, hash: block.Header.MerkleRoot, pruned: true, encodedTx: null);

                        // pick a random pruning order
                        var random           = new Random();
                        var pruneOrderSource = Enumerable.Range(0, txCount).ToList();
                        var pruneOrder       = new List <int>(txCount);
                        while (pruneOrderSource.Count > 0)
                        {
                            var randomIndex = random.Next(pruneOrderSource.Count);

                            pruneOrder.Add(pruneOrderSource[randomIndex]);
                            pruneOrderSource.RemoveAt(randomIndex);
                        }

                        // add preceding block
                        if (iteration == 1 || iteration == 3)
                        {
                            blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() - 1), block.BlockTxes);
                        }

                        // add the block to be pruned
                        blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                        // add proceeding block
                        if (iteration == 2 || iteration == 3)
                        {
                            blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() + 1), block.BlockTxes);
                        }

                        // prune the block
                        var count = 0;
                        foreach (var pruneIndex in pruneOrder)
                        {
                            Debug.WriteLine(count++);

                            // prune a transaction
                            blockTxesStorage.PruneElements(new[] { new KeyValuePair <UInt256, IEnumerable <int> >(block.Hash, new[] { pruneIndex }) });

                            // read block transactions
                            IEnumerator <BlockTxNode> blockTxNodes;
                            Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out blockTxNodes));

                            // verify block transactions, exception will be fired if invalid
                            MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, blockTxNodes.UsingAsEnumerable()).Count();
                        }

                        // read fully pruned block and verify
                        IEnumerator <BlockTxNode> finalBlockTxNodes;
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out finalBlockTxNodes));
                        var finalNodes = MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).ToList();
                        Assert.AreEqual(1, finalNodes.Count);
                        Assert.AreEqual(expectedFinalElement, finalNodes[0]);

                        // verify preceding block was not affected
                        if (iteration == 1 || iteration == 3)
                        {
                            Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() - 1), out finalBlockTxNodes));

                            // verify block transactions, exception will be fired if invalid
                            Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                        }

                        // verify proceeding block was not affected
                        if (iteration == 2 || iteration == 3)
                        {
                            Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() + 1), out finalBlockTxNodes));

                            // verify block transactions, exception will be fired if invalid
                            Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                        }
                    }
            }
        }
Ejemplo n.º 5
0
        private IEnumerator<BlockTxNode> ReadBlockTransactions(UInt256 blockHash, bool requireTx)
        {
            using (var handle = this.cursorCache.TakeItem())
            {
                var cursor = handle.Item;

                using (var jetTx = cursor.jetSession.BeginTransaction())
                {
                    int blockIndex;
                    if (!TryGetBlockIndex(cursor, blockHash, out blockIndex))
                        throw new MissingDataException(blockHash);

                    Api.JetSetCurrentIndex(cursor.jetSession, cursor.blocksTableId, "IX_BlockIndexTxIndex");

                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, blockIndex, MakeKeyGrbit.NewKey);
                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, 0, MakeKeyGrbit.None);
                    if (!Api.TrySeek(cursor.jetSession, cursor.blocksTableId, SeekGrbit.SeekGE))
                        throw new MissingDataException(blockHash);

                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, blockIndex, MakeKeyGrbit.NewKey);
                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, int.MaxValue, MakeKeyGrbit.None);
                    if (!Api.TrySetIndexRange(cursor.jetSession, cursor.blocksTableId, SetIndexRangeGrbit.RangeUpperLimit))
                        throw new MissingDataException(blockHash);

                    do
                    {
                        var txIndexColumn = new Int32ColumnValue { Columnid = cursor.txIndexColumnId };
                        var blockDepthColumn = new Int32ColumnValue { Columnid = cursor.blockDepthColumnId };
                        var blockTxHashColumn = new BytesColumnValue { Columnid = cursor.blockTxHashColumnId };
                        var blockTxBytesColumn = new BytesColumnValue { Columnid = cursor.blockTxBytesColumnId };
                        Api.RetrieveColumns(cursor.jetSession, cursor.blocksTableId, txIndexColumn, blockDepthColumn, blockTxHashColumn, blockTxBytesColumn);

                        var txIndex = txIndexColumn.Value.Value;
                        var depth = blockDepthColumn.Value.Value;
                        var txHash = DbEncoder.DecodeUInt256(blockTxHashColumn.Value);
                        var txBytes = blockTxBytesColumn.Value;

                        // determine if transaction is pruned by its depth
                        var pruned = depth >= 0;
                        depth = Math.Max(0, depth);

                        if (pruned && requireTx)
                            throw new MissingDataException(blockHash);

                        var blockTxNode = new BlockTxNode(txIndex, depth, txHash, pruned, txBytes?.ToImmutableArray());

                        yield return blockTxNode;
                    }
                    while (Api.TryMoveNext(cursor.jetSession, cursor.blocksTableId));
                }
            }
        }
Ejemplo n.º 6
0
 public static byte[] EncodeBlockTxNode(BlockTxNode blockTx)
 {
     using (var stream = new MemoryStream())
     using (var writer = new BinaryWriter(stream))
     {
         EncodeBlockTxNode(writer, blockTx);
         return stream.ToArray();
     }
 }
Ejemplo n.º 7
0
 public static void EncodeBlockTxNode(BinaryWriter writer, BlockTxNode blockTx)
 {
     writer.WriteInt32(blockTx.Index);
     writer.WriteInt32(blockTx.Depth);
     writer.WriteUInt256(blockTx.Hash);
     writer.WriteBool(blockTx.Pruned);
     if (!blockTx.Pruned)
         writer.WriteBytes(blockTx.TxBytes.ToArray());
 }
Ejemplo n.º 8
0
        private IEnumerator <BlockTxNode> ReadBlockTransactions(UInt256 blockHash, bool requireTx)
        {
            using (var handle = this.cursorCache.TakeItem())
            {
                var cursor = handle.Item;

                using (var jetTx = cursor.jetSession.BeginTransaction())
                {
                    int blockIndex;
                    if (!TryGetBlockIndex(cursor, blockHash, out blockIndex))
                    {
                        throw new MissingDataException(blockHash);
                    }

                    Api.JetSetCurrentIndex(cursor.jetSession, cursor.blocksTableId, "IX_BlockIndexTxIndex");

                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, blockIndex, MakeKeyGrbit.NewKey);
                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, 0, MakeKeyGrbit.None);
                    if (!Api.TrySeek(cursor.jetSession, cursor.blocksTableId, SeekGrbit.SeekGE))
                    {
                        throw new MissingDataException(blockHash);
                    }

                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, blockIndex, MakeKeyGrbit.NewKey);
                    Api.MakeKey(cursor.jetSession, cursor.blocksTableId, int.MaxValue, MakeKeyGrbit.None);
                    if (!Api.TrySetIndexRange(cursor.jetSession, cursor.blocksTableId, SetIndexRangeGrbit.RangeUpperLimit))
                    {
                        throw new MissingDataException(blockHash);
                    }

                    do
                    {
                        var txIndexColumn = new Int32ColumnValue {
                            Columnid = cursor.txIndexColumnId
                        };
                        var blockDepthColumn = new Int32ColumnValue {
                            Columnid = cursor.blockDepthColumnId
                        };
                        var blockTxHashColumn = new BytesColumnValue {
                            Columnid = cursor.blockTxHashColumnId
                        };
                        var blockTxBytesColumn = new BytesColumnValue {
                            Columnid = cursor.blockTxBytesColumnId
                        };
                        Api.RetrieveColumns(cursor.jetSession, cursor.blocksTableId, txIndexColumn, blockDepthColumn, blockTxHashColumn, blockTxBytesColumn);

                        var txIndex = txIndexColumn.Value.Value;
                        var depth   = blockDepthColumn.Value.Value;
                        var txHash  = DbEncoder.DecodeUInt256(blockTxHashColumn.Value);
                        var txBytes = blockTxBytesColumn.Value;

                        // determine if transaction is pruned by its depth
                        var pruned = depth >= 0;
                        depth = Math.Max(0, depth);

                        if (pruned && requireTx)
                        {
                            throw new MissingDataException(blockHash);
                        }

                        var blockTxNode = new BlockTxNode(txIndex, depth, txHash, pruned, txBytes?.ToImmutableArray());

                        yield return(blockTxNode);
                    }while (Api.TryMoveNext(cursor.jetSession, cursor.blocksTableId));
                }
            }
        }