private int GetBlocksToMaturity(StakeTx stakeTx) { if (!(stakeTx.UtxoSet.IsCoinbase || stakeTx.UtxoSet.IsCoinstake)) { return(0); } return(Math.Max(0, (int)this.network.Consensus.Option <PosConsensusOptions>().COINBASE_MATURITY + 1 - this.GetDepthInMainChain(stakeTx))); }
// Return depth of transaction in blockchain: // -1 : not in blockchain, and not in memory pool (conflicted transaction) // 0 : in memory pool, waiting to be included in a block // >=1 : this many blocks deep in the main chain private int GetDepthInMainChain(StakeTx stakeTx) { var chainedBlock = this.chain.GetBlock(stakeTx.HashBlock); if (chainedBlock == null) { return(-1); } // TODO: check if in memory pool then return 0 return(this.chain.Tip.Height - chainedBlock.Height + 1); }
private bool SignSignature(StakeTx from, Transaction txTo, params Script[] knownRedeems) { try { new TransactionBuilder() .AddKeys(from.PrvKey) .AddKnownRedeems(knownRedeems) .AddCoins(new Coin(from.OutPoint, from.TxOut)) .SignTransactionInPlace(txTo); } catch (Exception) { return(false); } return(true); }
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() || this.chainState.IsInitialBlockDownload) { this.LastCoinStakeSearchInterval = 0; tryToSync = true; Task.Delay(TimeSpan.FromMilliseconds(this.minerSleep), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult(); } if (tryToSync) { tryToSync = false; if (this.connection.ConnectedNodes.Count() < 3 || this.chain.Tip.Header.Time < this.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 { Task.Delay(TimeSpan.FromMilliseconds(this.minerSleep), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult(); } } }