Exemple #1
0
        public static PreEvaluationBlock <T> MineNext <T>(
            Block <T> previousBlock,
            HashAlgorithmGetter hashAlgorithmGetter,
            IReadOnlyList <Transaction <T> > txs = null,
            byte[] nonce           = null,
            long difficulty        = 1,
            PublicKey miner        = null,
            TimeSpan?blockInterval = null,
            int protocolVersion    = Block <T> .CurrentProtocolVersion
            )
            where T : IAction, new()
        {
            var content = new BlockContent <T>
            {
                Index           = previousBlock.Index + 1,
                Difficulty      = difficulty,
                TotalDifficulty = previousBlock.TotalDifficulty + difficulty,
                Miner           = miner?.ToAddress() ?? previousBlock.Miner,
                PublicKey       = protocolVersion < 2 ? null : miner ?? previousBlock.PublicKey,
                PreviousHash    = previousBlock.Hash,
                Timestamp       = previousBlock.Timestamp.Add(blockInterval ?? TimeSpan.FromSeconds(15)),
                Transactions    = txs ?? Array.Empty <Transaction <T> >(),
                ProtocolVersion = protocolVersion,
            };

            HashAlgorithmType hashAlgorithm = hashAlgorithmGetter(previousBlock.Index + 1);
            var preEval = nonce is byte[] nonceBytes
                ? new PreEvaluationBlock <T>(content, hashAlgorithm, new Nonce(nonceBytes))
                : content.Mine(hashAlgorithm);

            preEval.ValidateTimestamp();
            return(preEval);
        }
Exemple #2
0
        public void Evaluate()
        {
            Address address     = _contents.Tx0InBlock1.Signer;
            var     blockAction = new SetStatesAtBlock(address, (Bencodex.Types.Integer) 123, 0);
            var     policy      = new BlockPolicy <Arithmetic>(
                blockAction: blockAction,
                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000),
                minimumDifficulty: 2,
                difficultyStability: 1
                );
            var stagePolicy = new VolatileStagePolicy <Arithmetic>();

            PreEvaluationBlock <Arithmetic> preEvalGenesis =
                _contents.Genesis.Mine(policy.GetHashAlgorithm(0));

            using (var fx = new DefaultStoreFixture())
            {
                Block <Arithmetic> genesis =
                    preEvalGenesis.Evaluate(_contents.GenesisKey, blockAction, fx.StateStore);
                AssertPreEvaluationBlocksEqual(preEvalGenesis, genesis);
                _output.WriteLine("#1: {0}", genesis);

                var blockChain = new BlockChain <Arithmetic>(
                    policy,
                    stagePolicy,
                    fx.Store,
                    fx.StateStore,
                    genesis
                    );
                AssertBencodexEqual((Bencodex.Types.Integer) 123, blockChain.GetState(address));

                HashDigest <SHA256> identicalGenesisStateRootHash =
                    preEvalGenesis.DetermineStateRootHash(blockChain);
                AssertBytesEqual(genesis.StateRootHash, identicalGenesisStateRootHash);

                BlockContent <Arithmetic> content1 = _contents.Block1;
                content1.PreviousHash = genesis.Hash;
                content1.Difficulty   = 2;
                content1.Transactions = new[] { _contents.Tx0InBlock1 };
                PreEvaluationBlock <Arithmetic> preEval1 = content1.Mine(policy.GetHashAlgorithm(1));

                Block <Arithmetic> block1 = preEval1.Evaluate(_contents.Block1Key, blockChain);
                AssertPreEvaluationBlocksEqual(preEval1, block1);
                _output.WriteLine("#1: {0}", block1);

                HashDigest <SHA256> identicalBlock1StateRootHash =
                    preEval1.DetermineStateRootHash(blockChain);
                AssertBytesEqual(block1.StateRootHash, identicalBlock1StateRootHash);

                blockChain.Append(block1);
                AssertBencodexEqual((Bencodex.Types.Integer) 158, blockChain.GetState(address));
            }
        }
Exemple #3
0
        public async Task <Block <T> > MineBlock(
            PrivateKey miner,
            DateTimeOffset timestamp,
            bool append,
            long maxBlockBytes,
            int maxTransactions,
            int maxTransactionsPerSigner,
            IComparer <Transaction <T> > txPriority = null,
            CancellationToken cancellationToken     = default(CancellationToken))
        {
            using var cts = new CancellationTokenSource();
            using CancellationTokenSource cancellationTokenSource =
                      CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token);

            void WatchTip(object target, (Block <T> OldTip, Block <T> NewTip) tip)
            {
                try
                {
                    cts.Cancel();
                }
                catch (ObjectDisposedException)
                {
                    // Ignore if mining was already finished.
                }
            }

            long      index      = Count;
            long      difficulty = Policy.GetNextBlockDifficulty(this);
            BlockHash?prevHash   = index > 0 ? Store.IndexBlockHash(Id, index - 1) : null;

            int sessionId = new System.Random().Next();
            int processId = Process.GetCurrentProcess().Id;

            _logger.Debug(
                "{SessionId}/{ProcessId}: Starting to mine block #{Index} with " +
                "difficulty {Difficulty} and previous hash {PreviousHash}...",
                sessionId,
                processId,
                index,
                difficulty,
                prevHash);

            HashAlgorithmType hashAlgorithm = Policy.GetHashAlgorithm(index);

            var metadata = new BlockMetadata
            {
                Index           = index,
                Difficulty      = difficulty,
                TotalDifficulty = Tip.TotalDifficulty + difficulty,
                PublicKey       = miner.PublicKey,
                PreviousHash    = prevHash,
                Timestamp       = timestamp,
            };

            var transactionsToMine = GatherTransactionsToMine(
                metadata,
                maxBlockBytes: maxBlockBytes,
                maxTransactions: maxTransactions,
                maxTransactionsPerSigner: maxTransactionsPerSigner,
                txPriority: txPriority
                );

            if (transactionsToMine.Count < Policy.GetMinTransactionsPerBlock(index))
            {
                cts.Cancel();
                throw new OperationCanceledException(
                          $"Mining canceled due to insufficient number of gathered transactions " +
                          $"to mine for the requirement of {Policy.GetMinTransactionsPerBlock(index)} " +
                          $"given by the policy: {transactionsToMine.Count}");
            }

            _logger.Verbose(
                "{SessionId}/{ProcessId}: Mined block #{Index} will include " +
                "{TxCount} transactions.",
                sessionId,
                processId,
                index,
                transactionsToMine.Count);

            var blockContent = new BlockContent <T>(metadata)
            {
                Transactions = transactionsToMine
            };
            PreEvaluationBlock <T> preEval;

            TipChanged += WatchTip;

            try
            {
                preEval = await Task.Run(
                    () => blockContent.Mine(hashAlgorithm, cancellationTokenSource.Token),
                    cancellationTokenSource.Token
                    );
            }
            catch (OperationCanceledException)
            {
                if (cts.IsCancellationRequested)
                {
                    throw new OperationCanceledException(
                              "Mining canceled due to change of tip index.");
                }

                throw new OperationCanceledException(cancellationToken);
            }
            finally
            {
                TipChanged -= WatchTip;
            }

            (Block <T> block, IReadOnlyList <ActionEvaluation> actionEvaluations) =
                preEval.EvaluateActions(miner, this);
            IEnumerable <TxExecution> txExecutions = MakeTxExecutions(block, actionEvaluations);

            UpdateTxExecutions(txExecutions);

            _logger.Debug(
                "{SessionId}/{ProcessId}: Mined block #{Index} {Hash} " +
                "with difficulty {Difficulty} and previous hash {PreviousHash}.",
                sessionId,
                processId,
                block.Index,
                block.Hash,
                block.Difficulty,
                block.PreviousHash);

            if (append)
            {
                Append(
                    block,
                    evaluateActions: true,
                    renderBlocks: true,
                    renderActions: true,
                    actionEvaluations: actionEvaluations);
            }

            return(block);
        }