public PowBlockAssembler(ConsensusLoop consensusLoop, Network network, ConcurrentChain chain, MempoolScheduler mempoolScheduler, TxMempool mempool, IDateTimeProvider dateTimeProvider, AssemblerOptions options = null) { options = options ?? new AssemblerOptions(); this.blockMinFeeRate = options.BlockMinFeeRate; // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity: this.blockMaxWeight = (uint)Math.Max(4000, Math.Min(PowMining.DefaultBlockMaxWeight - 4000, options.BlockMaxWeight)); // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity: this.blockMaxSize = (uint)Math.Max(1000, Math.Min(network.Consensus.Option <PowConsensusOptions>().MAX_BLOCK_SERIALIZED_SIZE - 1000, options.BlockMaxSize)); // Whether we need to account for byte usage (in addition to weight usage) this.needSizeAccounting = (blockMaxSize < network.Consensus.Option <PowConsensusOptions>().MAX_BLOCK_SERIALIZED_SIZE - 1000); this.consensusLoop = consensusLoop; this.chain = chain; this.mempoolScheduler = mempoolScheduler; this.mempool = mempool; this.dateTimeProvider = dateTimeProvider; this.options = options; this.network = network; this.inBlock = new TxMempool.SetEntries(); // Reserve space for coinbase tx this.blockSize = 1000; this.blockWeight = 4000; this.blockSigOpsCost = 400; this.fIncludeWitness = false; // These counters do not include coinbase tx this.blockTx = 0; this.fees = 0; this.pblocktemplate = new BlockTemplate { Block = new Block(), VTxFees = new List <Money>() }; }
public void GenerateBlocks(List <TrxStakingInfo> trxPairs) { this.LastCoinStakeSearchInterval = 0; if (this.chain.Tip != this.consensusLoop.Tip) { return; } BlockTemplate pblocktemplate = null; bool tryToSync = true; while (true) { while (!this.connection.ConnectedNodes.Any() || chainState.IsInitialBlockDownload) { this.LastCoinStakeSearchInterval = 0; tryToSync = true; this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(this.minerSleep)); } if (tryToSync) { tryToSync = false; if (this.connection.ConnectedNodes.Count() < 3 || this.chain.Tip.Header.Time < dateTimeProvider.GetTime() - 10 * 60) { this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(60000)); continue; } } if (pblocktemplate == null) { pblocktemplate = this.blockAssemblerFactory.Create(new AssemblerOptions() { IsProofOfStake = true }).CreateNewBlock(new Script()); } var pblock = pblocktemplate.Block; var pindexPrev = this.chain.Tip; var stakeTxes = new List <StakeTx>(); var coinset = this.coinView.FetchCoinsAsync(trxPairs.Select(s => s.TransactionHash).ToArray()).GetAwaiter().GetResult(); foreach (var sets in coinset.UnspentOutputs) { int index = 0; foreach (var outputx in sets._Outputs) { if (outputx != null && outputx.Value > Money.Zero) { var stakeTx = new StakeTx(); stakeTx.TxOut = outputx; stakeTx.OutPoint = new OutPoint(sets.TransactionId, index); stakeTx.PrvKey = trxPairs.First(t => t.TransactionHash == sets.TransactionId).PrvKey; stakeTx.OutputIndex = index; stakeTx.HashBlock = this.chain.GetBlock((int)sets.Height).HashBlock; stakeTx.UtxoSet = sets; stakeTxes.Add(stakeTx); } index++; } } // Trying to sign a block if (this.SignBlock(stakeTxes, pblock, pindexPrev, pblocktemplate.TotalFee)) { var blockResult = new BlockResult { Block = pblock }; this.CheckState(new ContextInformation(blockResult, network.Consensus), pindexPrev); trxPairs.Add(new TrxStakingInfo { TransactionHash = pblock.Transactions[1].GetHash(), PrvKey = trxPairs.First().PrvKey }); pblocktemplate = null; } else { this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(this.minerSleep)); } } }
public void GenerateBlocks(WalletSecret walletSecret) { this.LastCoinStakeSearchInterval = 0; BlockTemplate pblocktemplate = null; bool tryToSync = true; while (true) { if (this.chain.Tip != this.consensusLoop.Tip) { return; } while (!this.connection.ConnectedNodes.Any() || chainState.IsInitialBlockDownload) { this.LastCoinStakeSearchInterval = 0; tryToSync = true; this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(this.minerSleep)); } if (tryToSync) { tryToSync = false; if (this.connection.ConnectedNodes.Count() < 3 || this.chain.Tip.Header.Time < dateTimeProvider.GetTime() - 10 * 60) { //this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(60000)); continue; } } if (pblocktemplate == null) { pblocktemplate = this.blockAssemblerFactory.Create(new AssemblerOptions() { IsProofOfStake = true }).CreateNewBlock(new Script()); } var pblock = pblocktemplate.Block; var pindexPrev = this.consensusLoop.Tip; var stakeTxes = new List <StakeTx>(); var spendable = this.wallet.GetSpendableTransactions(1); var coinset = this.coinView.FetchCoinsAsync(spendable.SelectMany(s => s.Transactions.Select(t => t.Id)).ToArray()).GetAwaiter().GetResult(); foreach (var unspentInfo in spendable) { foreach (var infoTransaction in unspentInfo.Transactions) { var set = coinset.UnspentOutputs.FirstOrDefault(f => f?.TransactionId == infoTransaction.Id); var utxo = set?._Outputs[infoTransaction.Index.Value]; if (utxo != null && utxo.Value > Money.Zero) { var stakeTx = new StakeTx(); stakeTx.TxOut = utxo; stakeTx.OutPoint = new OutPoint(set.TransactionId, infoTransaction.Index.Value); stakeTx.Address = unspentInfo.Address; stakeTx.OutputIndex = infoTransaction.Index.Value; stakeTx.HashBlock = this.chain.GetBlock((int)set.Height).HashBlock; stakeTx.UtxoSet = set; stakeTx.Secret = walletSecret; //temporary stakeTxes.Add(stakeTx); } } } // Trying to sign a block if (this.SignBlock(stakeTxes, pblock, pindexPrev, pblocktemplate.TotalFee)) { var blockResult = new BlockResult { Block = pblock }; this.CheckState(new ContextInformation(blockResult, this.network.Consensus), pindexPrev); pblocktemplate = null; } else { this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(this.minerSleep)); } } }