public void SignCoinstakeTransactions() { // Arrange // Delete previous wallet and create a new one, mine blocks. File.Delete(this.walletName.GetX1WalletFilepath(this.factory.Network, this.factory.DataFolder)); this.factory.WalletManagerFactory.CreateWallet(new WalletCreateRequest { Passphrase = this.passphrase, WalletName = this.walletName }); int blockMined = 200; long totalMiningReward = 0; for (var i = 0; i < blockMined; i++) { var transactions = new List <Transaction>(); var zeroOneTwo = i % 3; var addressType = zeroOneTwo == 0 ? AddressType.PubKeyHash : zeroOneTwo == 1 ? AddressType.ColdStakingHot : AddressType.MultiSig; transactions.Add(Create_Wallet.CreateCoinbase(this.factory.ChainIndexer.Tip.Height, this.factory.GetScriptPubKeyForMining(walletName, addressType), this.factory, out var reward)); totalMiningReward += reward; ChainedHeaderBlock nextBlock = this.factory.AddNextBlock(transactions); } this.factory.SetIBD(false); this.factory.SyncToHeight(blockMined, this.walletName); var wm = this.factory.WalletManagerFactory.AutoLoad2(this.walletName); // Act // *** Sign PubKeyHash output var budget = wm.GetBalance(null, AddressType.PubKeyHash); var kernelCoin = budget.StakingCoins.First().Value; var txPubKeyHash1 = CoinstakeTransactionService.CreateCoinstakeTransaction(kernelCoin, Money.Coins(50).Satoshi, this.date, this.passphrase, out var privateKey1); var txPubKeyHash2 = txPubKeyHash1.Clone(); Assert2.TransactionsEqual(txPubKeyHash1, txPubKeyHash2); // sign with TransactionBuilder txPubKeyHash1.Sign(C.Network, new[] { privateKey1 }, new ICoin[] { kernelCoin.ToCoin() }); // sign with SigningService SigningService.SignInputs(txPubKeyHash2, new[] { privateKey1 }, new[] { kernelCoin }); // same valid result? Assert2.IsSegWit(txPubKeyHash1); Assert2.TransactionsEqual(txPubKeyHash1, txPubKeyHash2); // *** Sign ColdStakingHot output var coldStakeKernelCoin = wm.GetBalance(null, AddressType.ColdStakingHot).StakingCoins.First().Value; var txColdStaking1 = CoinstakeTransactionService.CreateCoinstakeTransaction(coldStakeKernelCoin, Money.Coins(50).Satoshi, this.date, this.passphrase, out var privateKey2); var txColdStaking2 = txColdStaking1.Clone(); Assert2.TransactionsEqual(txColdStaking1, txColdStaking2); // sign with TransactionBuilder SignScriptAddress(txColdStaking1, privateKey2, coldStakeKernelCoin); Assert2.IsSegWit(txColdStaking1); // sign with SigningService SigningService.SignInputs(txColdStaking2, new[] { privateKey2 }, new [] { coldStakeKernelCoin }); // same valid result? Assert2.TransactionsEqual(txColdStaking1, txColdStaking2); // *** Sign MultiSig output var multiSigKernelCoin = wm.GetBalance(null, AddressType.MultiSig).StakingCoins.First().Value; var txMulti1 = CoinstakeTransactionService.CreateCoinstakeTransaction(multiSigKernelCoin, Money.Coins(50).Satoshi, this.date, this.passphrase, out var privateKey3); var txMulti2 = txMulti1.Clone(); // sign with TransactionBuilder SignScriptAddress(txMulti1, privateKey3, multiSigKernelCoin); Assert2.IsSegWit(txMulti1); // sign with SigningService SigningService.SignInputs(txMulti2, new[] { privateKey3 }, new[] { multiSigKernelCoin }); // same valid result? Assert2.TransactionsEqual(txMulti1, txMulti2); }
void CreateNextBlock(BlockTemplate blockTemplate, List <SegWitCoin> kernelCoins) { SegWitCoin kernelCoin = kernelCoins[0]; foreach (var coin in kernelCoins) { if (coin.UtxoValue < kernelCoin.UtxoValue) { kernelCoin = coin; } } var newBlockHeight = this.nodeServices.ConsensusManager.Tip.Height + 1; var totalReward = blockTemplate.TotalFee + this.nodeServices.PosCoinviewRule.GetProofOfStakeReward(newBlockHeight); blockTemplate.Block.Header.Time = (uint)this.PosV3.CurrentBlockTime; Transaction tx = CoinstakeTransactionService.CreateAndSignCoinstakeTransaction(kernelCoin, totalReward.Satoshi, (uint)this.PosV3.CurrentBlockTime, this.passphrase, out Key blockSignatureKey); if (tx is PosTransaction posTransaction) { ((PosTransaction)blockTemplate.Block.Transactions[0]).Time = (uint)this.PosV3.CurrentBlockTime; } blockTemplate.Block.Transactions.Insert(1, tx); this.nodeServices.BlockProvider.BlockModified(this.nodeServices.ConsensusManager.Tip, blockTemplate.Block); ECDSASignature signature = blockSignatureKey.Sign(blockTemplate.Block.GetHash()); ((PosBlock)blockTemplate.Block).BlockSignature = new BlockSignature { Signature = signature.ToDER() }; ChainedHeader chainedHeader; try { chainedHeader = this.nodeServices.ConsensusManager.BlockMinedAsync(blockTemplate.Block).GetAwaiter().GetResult(); } catch (Exception) { this.Status.BlocksNotAccepted++; throw; } if (chainedHeader == null) { this.Status.BlocksNotAccepted += 1; return; } if (this.LastStakedBlock.BlockTime != 0) { this.Status.ActualTime = (int)(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - this.LastStakedBlock.BlockTime); } else { this.Status.ActualTime = (int)(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - this.Status.StartedUtc); } this.LastStakedBlock.Hash = chainedHeader.HashBlock; this.LastStakedBlock.Height = chainedHeader.Height; this.LastStakedBlock.BlockSize = chainedHeader.Block.BlockSize ?? -1; this.LastStakedBlock.TxId = chainedHeader.Block.Transactions[1].GetHash(); this.LastStakedBlock.Transactions = chainedHeader.Block.Transactions.Count; this.LastStakedBlock.TotalReward = totalReward; this.LastStakedBlock.KernelAddress = kernelCoin.SegWitAddress.Address; this.LastStakedBlock.WeightUsed = kernelCoin.UtxoValue; this.LastStakedBlock.TotalComputeTimeMs = this.stopwatch.ElapsedMilliseconds; this.LastStakedBlock.BlockTime = this.PosV3.CurrentBlockTime; this.Status.BlocksAccepted += 1; Log.Logger.LogInformation( $"Congratulations, your staked a new block at height {newBlockHeight} and received a total reward of {totalReward} {C.Network.CoinTicker}."); }