예제 #1
0
        private void MintBlock(List <Transaction> transactions, Chain chain)
        {
            var hashes = new HashSet <Hash>(transactions.Select(tx => tx.Hash));

            var lastBlockHash = chain.GetLastBlockHash();
            var lastBlock     = chain.GetBlockByHash(lastBlockHash);
            var isFirstBlock  = lastBlock == null;

            var protocol = (uint)Nexus.GetGovernanceValue(Nexus.RootStorage, Nexus.NexusProtocolVersionTag);

            while (hashes.Count > 0)
            {
                var block = new Block(isFirstBlock ? 1 : (lastBlock.Height + 1), chain.Address, Timestamp.Now, hashes, isFirstBlock ? Hash.Null : lastBlock.Hash, protocol);

                try
                {
                    chain.BakeBlock(ref block, ref transactions, MinimumFee, _validatorKeys, Timestamp.Now);
                    chain.AddBlock(block, transactions, MinimumFee);
                }
                catch (InvalidTransactionException e)
                {
                    var tx = transactions.First(x => x.Hash == e.Hash);
                    Interlocked.Decrement(ref _size);
                    hashes.Remove(e.Hash);

                    lock (_rejections)
                    {
                        _rejections[e.Hash] = e.Message;
                    }

                    transactions.Remove(tx);
                    OnTransactionFailed?.Invoke(tx);
                    continue;
                }

                lock (_entries)
                {
                    foreach (var tx in transactions)
                    {
                        _pendingSet.Remove(tx.Hash);
                    }
                }

                foreach (var tx in transactions)
                {
                    Interlocked.Decrement(ref _size);
                    OnTransactionCommitted?.Invoke(tx);
                }

                break;
            }

            lock (_pendingBlocks)
            {
                _pendingBlocks.Remove(chain);
            }
        }
예제 #2
0
        private void MintBlock(List <Transaction> transactions, Chain chain)
        {
            var hashes = new HashSet <Hash>(transactions.Select(tx => tx.Hash));

            var isFirstBlock = chain.LastBlock == null;

            while (hashes.Count > 0)
            {
                var block = new Block(isFirstBlock ? 1 : (chain.LastBlock.Height + 1), chain.Address, Timestamp.Now, hashes, isFirstBlock ? Hash.Null : chain.LastBlock.Hash);

                try
                {
                    chain.AddBlock(block, transactions, MinimumFee);
                }
                catch (InvalidTransactionException e)
                {
                    var tx = transactions.First(x => x.Hash == e.Hash);
                    Interlocked.Decrement(ref _size);
                    hashes.Remove(e.Hash);

                    lock (_rejections)
                    {
                        _rejections[e.Hash] = e.Message;
                    }

                    transactions.Remove(tx);
                    OnTransactionFailed?.Invoke(tx);
                    continue;
                }

                lock (_entries)
                {
                    foreach (var tx in transactions)
                    {
                        _pendingSet.Remove(tx.Hash);
                    }
                }

                foreach (var tx in transactions)
                {
                    Interlocked.Decrement(ref _size);
                    OnTransactionRemoved?.Invoke(tx);
                }
                break;
            }

            lock (_pendingBlocks)
            {
                _pendingBlocks.Remove(chain);
            }
        }
예제 #3
0
        public OperatingError Execute(Block block, TransactionReceipt receipt, IBlockchainSnapshot snapshot)
        {
            var transactionRepository = _stateManager.CurrentSnapshot.Transactions;

            /* check transaction with this hash in database */
            if (transactionRepository.GetTransactionByHash(receipt.Hash) != null)
            {
                return(OperatingError.AlreadyExists);
            }
            /* verify transaction */

            /* find if verification should be skipped for this transaction */
            var indexInCycle = block.Header.Index % StakingContract.CycleDuration;
            var cycle        = block.Header.Index / StakingContract.CycleDuration;

            var isGenesisBlock = block.Header.Index == 0;
            var isDistributeCycleRewardsAndPenaltiesTx = IsDistributeCycleRewardsAndPenaltiesTx(block, receipt.Transaction);
            var isFinishVrfLotteryTx = IsFinishVrfLotteryTx(block, receipt.Transaction);
            var isFinishCycleTx      = IsFinishCycleTx(block, receipt.Transaction);
            // there are some cases when transaction verification is skipped
            // (1) genesis block's transactions
            // (2) DistributeCycleRewardsAndPenalties transaction. This transaction is executed during block,
            //          (a) indexInCycle( = blockHeight % CycleDuration) == AttendanceDetectionDuration (CycleDuration / 10)
            // (3) FinishVrfLottery transaction. This transaction is executed during block,
            //          (a) indexInCycle( = blockHeight % CycleDuration) == VrfSubmissionPhaseDuration (CycleDuration / 2)
            // (4) FinishCycle transaction. This transaction is executed during block,
            //          (a) indexInCycle( = blockHeight % CycleDuration) == 0
            //          (b) cycle (= blockHeight / cycleDuration) > 0

            var canTransactionMissVerification = isGenesisBlock ||
                                                 isDistributeCycleRewardsAndPenaltiesTx || isFinishVrfLotteryTx || isFinishCycleTx;

            var verifyError = VerifyInternal(receipt, canTransactionMissVerification, HardforkHeights.IsHardfork_9Active(block.Header.Index));

            if (verifyError != OperatingError.Ok)
            {
                return(verifyError);
            }
            /* maybe we don't need this check, but I'm afraid */
            if (!receipt.Transaction.FullHash(receipt.Signature, HardforkHeights.IsHardfork_9Active(block.Header.Index)).Equals(receipt.Hash))
            {
                return(OperatingError.HashMismatched);
            }
            /* check transaction nonce */
            var nonce = transactionRepository.GetTotalTransactionCount(receipt.Transaction.From);

            if (nonce != receipt.Transaction.Nonce)
            {
                return(OperatingError.InvalidNonce);
            }
            /* try to persist transaction */
            var result = _transactionExecuter.Execute(block, receipt, snapshot);

            if (result != OperatingError.Ok)
            {
                OnTransactionFailed?.Invoke(this, receipt);
                return(result);
            }

            /* finalize transaction state */
            OnTransactionExecuted?.Invoke(this, receipt);
            return(OperatingError.Ok);
        }