private static TransformManyBlock<BlockTx, Tuple<UInt256, CompletionCount, BlockTx>> InitQueueUnspentTxLookup(CancellationToken cancelToken) { return new TransformManyBlock<BlockTx, Tuple<UInt256, CompletionCount, BlockTx>>( blockTx => { var inputCount = !blockTx.IsCoinbase ? blockTx.Transaction.Inputs.Length : 0; var completionCount = new CompletionCount(inputCount + 1); var txHashes = new Tuple<UInt256, CompletionCount, BlockTx>[inputCount + 1]; txHashes[0] = Tuple.Create(blockTx.Hash, completionCount, blockTx); if (!blockTx.IsCoinbase) { for (var inputIndex = 0; inputIndex < blockTx.Transaction.Inputs.Length; inputIndex++) { var txHash = blockTx.Transaction.Inputs[inputIndex].PreviousTxOutputKey.TxHash; txHashes[inputIndex + 1] = Tuple.Create(txHash, completionCount, blockTx); } } return txHashes; }, new ExecutionDataflowBlockOptions { CancellationToken = cancelToken }); }
private static TransformManyBlock<DecodedBlockTx, Tuple<TxOutputKey, CompletionCount, DecodedBlockTx>> InitQueueUnspentTxLookup(CancellationToken cancelToken) { return new TransformManyBlock<DecodedBlockTx, Tuple<TxOutputKey, CompletionCount, DecodedBlockTx>>( blockTx => { var tx = blockTx.Transaction; var outputCount = tx.Outputs.Length; var inputCount = !blockTx.IsCoinbase ? tx.Inputs.Length * 2 : 0; var txOutputKeys = new Tuple<TxOutputKey, CompletionCount, DecodedBlockTx>[1 + outputCount + inputCount]; var completionCount = new CompletionCount(txOutputKeys.Length); var keyIndex = 0; // warm-up the UnspentTx entry that will be added for the new tx txOutputKeys[keyIndex++] = Tuple.Create(new TxOutputKey(blockTx.Hash, uint.MaxValue), completionCount, blockTx); // warm-up the TxOutput entries that will be added for each of the tx's outputs for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++) { var txOutputKey = new TxOutputKey(blockTx.Hash, (uint)outputIndex); txOutputKeys[keyIndex++] = Tuple.Create(txOutputKey, completionCount, blockTx); } // warm-up the previous UnspentTx and TxOutput entries that will be needed for each of the tx's inputs if (!blockTx.IsCoinbase) { for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++) { var input = tx.Inputs[inputIndex]; // input's previous tx's UnspentTx entry var txOutputKey = new TxOutputKey(input.PrevTxHash, uint.MaxValue); txOutputKeys[keyIndex++] = Tuple.Create(txOutputKey, completionCount, blockTx); // input's previous tx outputs's TxOutput entry txOutputKey = input.PrevTxOutputKey; txOutputKeys[keyIndex++] = Tuple.Create(txOutputKey, completionCount, blockTx); } } Debug.Assert(txOutputKeys.All(x => x != null)); return txOutputKeys; }, new ExecutionDataflowBlockOptions { CancellationToken = cancelToken }); }