BitSharp.Examples.ExamplePrograms.ReplayBlockExample C# (CSharp) Method

ReplayBlockExample() private method

private ReplayBlockExample ( ) : void
return void
        public void ReplayBlockExample()
        {
            // create example core daemon
            BlockProvider embeddedBlocks; IStorageManager storageManager;
            using (var coreDaemon = CreateExampleDaemon(out embeddedBlocks, out storageManager, maxHeight: 999))
            using (embeddedBlocks)
            using (storageManager)
            {
                // start a chain at the genesis block to represent the processed progress
                var processedChain = Chain.CreateForGenesisBlock(coreDaemon.ChainParams.GenesisChainedHeader).ToBuilder();

                // a dictionary of public key script hashes can be created for any addresses of interest, allowing for quick checking
                var scriptHashesOfInterest = new HashSet<UInt256>();

                // retrieve a chainstate to replay blocks with
                using (var chainState = coreDaemon.GetChainState())
                {
                    // enumerate the steps needed to take the currently processed chain towards the current chainstate
                    foreach (var pathElement in processedChain.NavigateTowards(chainState.Chain))
                    {
                        // retrieve the next block to replay and whether to replay forwards, or backwards for a re-org
                        var replayForward = pathElement.Item1 > 0;
                        var replayBlock = pathElement.Item2;

                        // begin replaying the transactions in the replay block
                        // if this is a re-org, the transactions will be replayed in reverse block order
                        var replayTxes = BlockReplayer.ReplayBlock(coreDaemon.CoreStorage, chainState, replayBlock.Hash, replayForward);

                        // prepare the tx scanner
                        var txScanner = new ActionBlock<ValidatableTx>(
                            validatableTx =>
                            {
                                // the transaction being replayed
                                var tx = validatableTx.Transaction;

                                // the previous tx outputs for each of the replay transaction's inputs
                                var prevTxOutputs = validatableTx.PrevTxOutputs;

                                // scan the replay transaction's inputs
                                if (!validatableTx.IsCoinbase)
                                {
                                    for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                                    {
                                        var input = tx.Inputs[inputIndex];
                                        var inputPrevTxOutput = validatableTx.PrevTxOutputs[inputIndex];

                                        // check if the input's previous transaction output is of interest
                                        var inputPrevTxOutputPublicScriptHash = new UInt256(SHA256Static.ComputeHash(inputPrevTxOutput.ScriptPublicKey));
                                        if (scriptHashesOfInterest.Contains(inputPrevTxOutputPublicScriptHash))
                                        {
                                            if (replayForward)
                                            { /* An output for an address of interest is being spent. */ }
                                            else
                                            { /* An output for an address of interest is being "unspent", on re-org. */}
                                        }
                                    }
                                }

                                // scan the replay transaction's outputs
                                for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
                                {
                                    var output = tx.Outputs[outputIndex];

                                    // check if the output is of interest
                                    var outputPublicScriptHash = new UInt256(SHA256Static.ComputeHash(output.ScriptPublicKey));
                                    if (scriptHashesOfInterest.Contains(outputPublicScriptHash))
                                    {
                                        if (replayForward)
                                        { /* An output for an address of interest is being minted. */ }
                                        else
                                        { /* An output for an address of interest is being "unminted", on re-org. */}
                                    }
                                }
                            });

                        // hook up and wait for the tx scanner
                        replayTxes.LinkTo(txScanner, new DataflowLinkOptions { PropagateCompletion = true });
                        txScanner.Completion.Wait();

                        // a wallet would now commit its progress
                        /*
                        walletDatabase.CurrentBlock = replayBlock.Hash;
                        walletDatabase.Commit();
                        */

                        // TODO: after successfully committing, a wallet would notify CoreDaemon of its current progress
                        // TODO: CoreDaemon will use this information in order to determine how far in the current chainstate it is safe to prune
                        // TODO: with this in place, if a wallet suffers a failure to commit it can just replay the block
                        // TODO: wallets can also remain disconnected from CoreDaemon, and just replay blocks to catch up when they are reconnected

                        // update the processed chain so that the next step towards the current chainstate can be taken
                        if (replayForward)
                            processedChain.AddBlock(replayBlock);
                        else
                            processedChain.RemoveBlock(replayBlock);
                    }
                }

                logger.Info("Processed chain height: {0:N0}", processedChain.Height);
            }
        }
    }