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); } }
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); } }
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); }