/// <summary> /// /// </summary> /// <param name="coinbase"></param> /// <param name="solution"></param> /// <param name="runningDistribution"></param> /// <returns></returns> public VerifyResult VerifyCoinbaseTransaction(Vout coinbase, ulong solution, decimal runningDistribution) { Guard.Argument(coinbase, nameof(coinbase)).NotNull(); Guard.Argument(solution, nameof(solution)).NotZero().NotNegative(); Guard.Argument(runningDistribution, nameof(runningDistribution)).NotZero().NotNegative(); if (coinbase.Validate().Any()) { return(VerifyResult.UnableToVerify); } if (coinbase.T != CoinType.Coinbase) { return(VerifyResult.UnableToVerify); } var verifyNetworkShare = VerifyNetworkShare(solution, coinbase.A.DivWithNanoTan(), runningDistribution); if (verifyNetworkShare == VerifyResult.UnableToVerify) { return(verifyNetworkShare); } using var pedersen = new Pedersen(); var commitSum = pedersen.CommitSum(new List <byte[]> { coinbase.C }, new List <byte[]> { coinbase.C }); return(commitSum == null ? VerifyResult.Succeed : VerifyResult.UnableToVerify); }
private void clear_butt_Click(object sender, EventArgs e) { R1.Clear(); Vin.Clear(); Vout.Clear(); MaxPower.Clear(); R1Val.Clear(); R2Val.Clear(); }
public async Task GetTaskAsync_Verbose_ReturnsTransactionVerboseModelAsync() { this.chainState.Setup(c => c.ConsensusTip) .Returns(this.chain.Tip); ChainedHeader block = this.chain.GetBlock(1); Transaction transaction = this.CreateTransaction(); var txId = new uint256(12142124); this.pooledTransaction.Setup(p => p.GetTransaction(txId)) .ReturnsAsync(transaction); var blockStore = new Mock <IBlockStore>(); blockStore.Setup(b => b.GetTrxBlockIdAsync(txId)) .ReturnsAsync(block.HashBlock); this.fullNode.Setup(f => f.NodeFeature <IBlockStore>(false)) .Returns(blockStore.Object); this.controller = new NodeController(this.fullNode.Object, this.LoggerFactory.Object, this.dateTimeProvider.Object, this.chainState.Object, this.nodeSettings, this.connectionManager.Object, this.chain, this.network, this.pooledTransaction.Object, this.pooledGetUnspentTransaction.Object, this.getUnspentTransaction.Object, this.networkDifficulty.Object); string txid = txId.ToString(); bool verbose = true; var json = (JsonResult)await this.controller.GetRawTransactionAsync(txid, verbose).ConfigureAwait(false); var resultModel = (TransactionVerboseModel)json.Value; Assert.NotNull(resultModel); var model = Assert.IsType <TransactionVerboseModel>(resultModel); Assert.Equal(transaction.GetHash().ToString(), model.TxId); Assert.Equal(transaction.GetSerializedSize(), model.Size); Assert.Equal(transaction.Version, model.Version); Assert.Equal((uint)transaction.LockTime, model.LockTime); Assert.Equal(transaction.ToHex(), model.Hex); Assert.Equal(block.HashBlock.ToString(), model.BlockHash); Assert.Equal(3, model.Confirmations); Assert.Equal(Utils.DateTimeToUnixTime(block.Header.BlockTime), model.Time); Assert.Equal(Utils.DateTimeToUnixTime(block.Header.BlockTime), model.BlockTime); Assert.NotEmpty(model.VIn); Vin input = model.VIn[0]; var expectedInput = new Vin(transaction.Inputs[0].PrevOut, transaction.Inputs[0].Sequence, transaction.Inputs[0].ScriptSig); Assert.Equal(expectedInput.Coinbase, input.Coinbase); Assert.Equal(expectedInput.ScriptSig, input.ScriptSig); Assert.Equal(expectedInput.Sequence, input.Sequence); Assert.Equal(expectedInput.TxId, input.TxId); Assert.Equal(expectedInput.VOut, input.VOut); Assert.NotEmpty(model.VOut); Vout output = model.VOut[0]; var expectedOutput = new Vout(0, transaction.Outputs[0], this.network); Assert.Equal(expectedOutput.Value, output.Value); Assert.Equal(expectedOutput.N, output.N); Assert.Equal(expectedOutput.ScriptPubKey.Hex, output.ScriptPubKey.Hex); }
public async Task GetTaskAsync_Verbose_ReturnsTransactionVerboseModelAsync() { // Add the 'txindex' setting, otherwise the transactions won't be found. this.nodeSettings.ConfigReader.MergeInto(new TextFileConfiguration("-txindex=1")); this.chainState.Setup(c => c.ConsensusTip) .Returns(this.chain.Tip); ChainedHeader block = this.chain.GetHeader(1); Transaction transaction = this.CreateTransaction(); var txId = new uint256(12142124); this.pooledTransaction.Setup(p => p.GetTransaction(txId)) .ReturnsAsync(transaction); this.blockStore.Setup(b => b.GetBlockIdByTransactionId(txId)) .Returns(block.HashBlock); this.controller = new FullNodeController(this.LoggerFactory.Object, this.pooledTransaction.Object, this.pooledGetUnspentTransaction.Object, this.getUnspentTransaction.Object, this.networkDifficulty.Object, this.fullNode.Object, this.nodeSettings, this.network, this.chain, this.chainState.Object, this.connectionManager.Object, this.consensusManager.Object, this.blockStore.Object); TransactionModel result = await this.controller.GetRawTransactionAsync(txId.ToString(), true).ConfigureAwait(false); Assert.NotNull(result); var model = Assert.IsType <TransactionVerboseModel>(result); Assert.Equal(transaction.GetHash().ToString(), model.TxId); Assert.Equal(transaction.GetSerializedSize(), model.Size); Assert.Equal(transaction.Version, model.Version); Assert.Equal((uint)transaction.LockTime, model.LockTime); Assert.Equal(transaction.ToHex(), model.Hex); Assert.Equal(block.HashBlock.ToString(), model.BlockHash); Assert.Equal(3, model.Confirmations); Assert.Equal(Utils.DateTimeToUnixTime(block.Header.BlockTime), model.Time); Assert.Equal(Utils.DateTimeToUnixTime(block.Header.BlockTime), model.BlockTime); Assert.NotEmpty(model.VIn); Vin input = model.VIn[0]; var expectedInput = new Vin(transaction.Inputs[0].PrevOut, transaction.Inputs[0].Sequence, transaction.Inputs[0].ScriptSig); Assert.Equal(expectedInput.Coinbase, input.Coinbase); Assert.Equal(expectedInput.ScriptSig, input.ScriptSig); Assert.Equal(expectedInput.Sequence, input.Sequence); Assert.Equal(expectedInput.TxId, input.TxId); Assert.Equal(expectedInput.VOut, input.VOut); Assert.NotEmpty(model.VOut); Vout output = model.VOut[0]; var expectedOutput = new Vout(0, transaction.Outputs[0], this.network); Assert.Equal(expectedOutput.Value, output.Value); Assert.Equal(expectedOutput.N, output.N); Assert.Equal(expectedOutput.ScriptPubKey.Hex, output.ScriptPubKey.Hex); }
public override int GetHashCode() { unchecked { var hashCode = (TransactionId != null ? TransactionId.GetHashCode() : 0); hashCode = (hashCode * 397) ^ Sequence.GetHashCode(); hashCode = (hashCode * 397) ^ Vout.GetHashCode(); hashCode = (hashCode * 397) ^ (ScriptSig != null ? ScriptSig.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (Addresses != null ? Addresses.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (Value != null ? Value.GetHashCode() : 0); return(hashCode); } }
public async Task SendingATransactionWithAnOpReturn() { int sendingAccountBalanceOnStart = 98000596; int receivingAccountBalanceOnStart = 0; using (NodeBuilder builder = NodeBuilder.Create(this)) { // Arrange. // Create a sending and a receiving node. CoreNode sendingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Miner).Start(); CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Listener).Start(); TestHelper.ConnectAndSync(sendingNode, receivingNode); // Check balances. WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC)); WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart)); // Act. // Get an address to send to. IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/unusedAddresses") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 1 }) .GetJsonAsync <IEnumerable <string> >(); // Build and send the transaction with an Op_Return. WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/build-transaction") .PostJsonAsync(new BuildTransactionRequest { WalletName = "mywallet", AccountName = "account 0", FeeType = "low", Password = "******", ShuffleOutputs = true, AllowUnconfirmed = true, Recipients = unusedaddresses.Select(address => new RecipientModel { DestinationAddress = address, Amount = "1" }).ToList(), OpReturnData = "some data to send", OpReturnAmount = "1" }) .ReceiveJson <WalletBuildTransactionModel>(); await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/send-transaction") .PostJsonAsync(new SendTransactionRequest { Hex = buildTransactionModel.Hex }) .ReceiveJson <WalletSendTransactionModel>(); // Assert. // Mine and sync so that we make sure the receiving node is up to date. TestHelper.MineBlocks(sendingNode, 1); TestHelper.WaitForNodeToSync(sendingNode, receivingNode); // The receiving node should have coins. receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed).Should().Be(new Money(receivingAccountBalanceOnStart + 1, MoneyUnit.BTC)); // The sending node should have fewer coins. sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed).Should().Be(new Money(sendingAccountBalanceOnStart + 4 - 2, MoneyUnit.BTC)); // Check the transaction. string lastBlockHash = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("consensus/getbestblockhash") .GetJsonAsync <string>(); BlockTransactionDetailsModel block = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("blockstore/block") .SetQueryParams(new { hash = lastBlockHash, showTransactionDetails = true, outputJson = true }) .GetJsonAsync <BlockTransactionDetailsModel>(); TransactionVerboseModel trx = block.Transactions.SingleOrDefault(t => t.TxId == buildTransactionModel.TransactionId.ToString()); trx.Should().NotBeNull(); Vout opReturnOutputFromBlock = trx.VOut.Single(t => t.ScriptPubKey.Type == "nulldata"); opReturnOutputFromBlock.Value.Should().Be(1); var script = opReturnOutputFromBlock.ScriptPubKey.Asm; string[] ops = script.Split(" "); ops[0].Should().Be("OP_RETURN"); Encoders.Hex.DecodeData(ops[1]).Should().BeEquivalentTo(System.Text.Encoding.UTF8.GetBytes("some data to send")); } }
private async Task ProcessBlockForSwapVoteTransactionsAsync(BlockTransactionDetailsModel block, int blockHeight) { // Inspect each transaction foreach (TransactionVerboseModel transaction in block.Transactions) { // Find the first the OP_RETURN output. Vout opReturnOutput = transaction.VOut.FirstOrDefault(v => v.ScriptPubKey.Type == "nulldata"); if (opReturnOutput == null) { continue; } IList <Op> ops = new NBitcoin.Script(opReturnOutput.ScriptPubKey.Asm).ToOps(); var potentialVote = Encoding.ASCII.GetString(ops.Last().PushData); try { var isVote = potentialVote.Substring(0, 1); if (isVote != "V") { continue; } var isVoteValue = potentialVote.Substring(1, 1); if (isVoteValue == "1" || isVoteValue == "0") { // Verify the sender address is a valid Strat address var potentialStratAddress = potentialVote.Substring(2); ValidatedAddress validateResult = await $"http://localhost:{this.StratisNetworkApiPort}/api" .AppendPathSegment("node/validateaddress") .SetQueryParams(new { address = potentialStratAddress }) .GetJsonAsync <ValidatedAddress>(); if (!validateResult.IsValid) { Console.WriteLine($"Invalid STRAT address: '{potentialStratAddress}'"); continue; } AddressBalancesResult balance = await $"http://localhost:{this.StratisNetworkApiPort}/api" .AppendPathSegment($"blockstore/{BlockStoreRouteEndPoint.GetAddressesBalances}") .SetQueryParams(new { addresses = potentialStratAddress, minConfirmations = 0 }) .GetJsonAsync <AddressBalancesResult>(); if (isVoteValue == "0") { this.castVotes.Add(new CastVote() { Address = potentialStratAddress, Balance = balance.Balances[0].Balance, InFavour = false, BlockHeight = blockHeight }); Console.WriteLine($"'No' vote found at height {blockHeight}."); } if (isVoteValue == "1") { this.castVotes.Add(new CastVote() { Address = potentialStratAddress, Balance = balance.Balances[0].Balance, InFavour = true, BlockHeight = blockHeight }); Console.WriteLine($"'Yes' vote found at height {blockHeight}."); } } } catch (Exception) { } } }
private async Task ProcessBlockForCollateralVoteTransactionsAsync(BlockTransactionDetailsModel block, int blockHeight) { // Inspect each transaction foreach (TransactionVerboseModel transaction in block.Transactions) { // Find the first the OP_RETURN output. Vout opReturnOutput = transaction.VOut.FirstOrDefault(v => v.ScriptPubKey.Type == "nulldata"); if (opReturnOutput == null) { continue; } // Before checking if it's a vote, check if it's a swap transaction as we now know it has an OP_RETURN. // Ignore any transactions that have inconsequential OP_RETURN values. if (opReturnOutput.Value >= 1.0m) { // For the purposes of speeding up this search, it doesn't matter per se whether the burn transaction has a valid destination address in it. TransactionModel tx = this.blockExplorerClient.GetTransaction(transaction.TxId); // Check the inputs of the transaction to see if it was funded by one of the vote addresses. string address = null; foreach (In input in tx._in) { if (input.hash == null) { continue; } // The block explorer calls this 'hash' but it is in fact the address that funded the input. // It is possible that several voting addresses consolidated together in one swap transaction, so just take the first one. if (this.collateralVotes.ContainsKey(input.hash)) { if (address == null) { // We will assign the entire burn amount to the first found voting address. address = input.hash; } else { // However, we have to recompute the balance of all the vote addresses present in the inputs that we are not going to assign the burn to. // This is because they will not necessarily be revisited later if there are no further transactions affecting them. // We presume that since they are participating in a burn subsequent to their initial vote, their balance will drop. if (!address.Equals(input.hash)) { AddressBalancesResult balance = await $"http://localhost:{this.StratisNetworkApiPort}/api" .AppendPathSegment($"blockstore/{BlockStoreRouteEndPoint.GetAddressesBalances}") .SetQueryParams(new { addresses = input.hash, minConfirmations = 0 }) .GetJsonAsync <AddressBalancesResult>(); Console.WriteLine($"Reset balance for '{input.hash}' to {balance.Balances[0].Balance} due to burn transaction {transaction.TxId} at height {blockHeight}"); this.collateralVotes[input.hash].Balance = balance.Balances[0].Balance; } } } } if (address != null) { this.collateralVotes[address].BlockHeight = blockHeight; this.collateralVotes[address].Balance = Money.Coins(opReturnOutput.Value); Console.WriteLine($"Detected that address '{address}' burnt {opReturnOutput.Value} via transaction {transaction.TxId} at height {blockHeight}"); // We can now skip checking if this output was a vote. continue; } } IList <Op> ops = new NBitcoin.Script(opReturnOutput.ScriptPubKey.Asm).ToOps(); var potentialVote = Encoding.ASCII.GetString(ops.Last().PushData); try { var isVote = potentialVote.Substring(0, 1); if (isVote != "V") { continue; } var isCollateralVote = potentialVote.Substring(1, 1); if (isCollateralVote != "C") { continue; } var collateralVote = potentialVote.Substring(2, 1); if (!new[] { "A", "B", "C", "D", "E" }.Contains(collateralVote)) { Console.WriteLine($"Invalid vote found '{collateralVote}'; height {blockHeight}."); continue; } // Verify the sender address is a valid Strat address var potentialStratAddress = potentialVote.Substring(3); ValidatedAddress validateResult = await $"http://localhost:{this.StratisNetworkApiPort}/api" .AppendPathSegment("node/validateaddress") .SetQueryParams(new { address = potentialStratAddress }) .GetJsonAsync <ValidatedAddress>(); if (!validateResult.IsValid) { Console.WriteLine($"Invalid STRAT address: '{potentialStratAddress}'"); continue; } AddressBalancesResult balance = await $"http://localhost:{this.StratisNetworkApiPort}/api" .AppendPathSegment($"blockstore/{BlockStoreRouteEndPoint.GetAddressesBalances}") .SetQueryParams(new { addresses = potentialStratAddress, minConfirmations = 0 }) .GetJsonAsync <AddressBalancesResult>(); Money determinedBalance = balance.Balances[0].Balance; if (!this.collateralVotes.ContainsKey(potentialStratAddress)) { Console.WriteLine($"Collateral vote found for {potentialStratAddress} at height {blockHeight}; Selection '{collateralVote}'; Balance {determinedBalance}"); this.collateralVotes.Add(potentialStratAddress, new CollateralVote() { Address = potentialStratAddress, Balance = determinedBalance, Selection = collateralVote, BlockHeight = blockHeight }); } else { Console.WriteLine($"Updating existing vote for {potentialStratAddress} at height {blockHeight}; Selection '{collateralVote}'; Balance {determinedBalance}"); this.collateralVotes[potentialStratAddress] = new CollateralVote() { Address = potentialStratAddress, Balance = determinedBalance, Selection = collateralVote, BlockHeight = blockHeight }; } } catch (Exception) { } } }
public Transaction(JObject json, Block block, List <Vin> _vin) //details { txid = json["result"]["txid"].ToString(); hash = json["result"]["hash"].ToString(); size = Int32.Parse(json["result"]["size"].ToString()); weight = Int32.Parse(json["result"]["weight"].ToString()); if (block != null) { time = block.time; status = "Confirmed"; includedInBlock = "Yes"; blockh = block.height; conf = block.confirmations; } else { status = "Unconfirmed"; includedInBlock = "No"; conf = 0; } int br = json["result"]["vout"].Count(); decimal ukupnoIzlaztr = 0; vout = new List <Vout>(); foreach (int i in Enumerable.Range(0, br)) { var s = json["result"]["vout"][i]["value"].ToString(); decimal value = Decimal.Round(decimal.Parse(json["result"]["vout"][i]["value"].ToString(), System.Globalization.NumberStyles.Any), 8, MidpointRounding.AwayFromZero); if (value > 0) { ukupnoIzlaztr += value; int bradresa = json["result"]["vout"][i]["scriptPubKey"]["addresses"].Count(); List <string> a = new List <string>(); foreach (int j in Enumerable.Range(0, bradresa)) { string address = json["result"]["vout"][i]["scriptPubKey"]["addresses"][j].ToString(); a.Add(address); } Vout v = new Vout(); v.value = value; ScriptPubKey spk = new ScriptPubKey(); spk.addresses = new List <string>(); foreach (string add in a) { spk.addresses.Add(add); } v.scriptPubKey = spk; v.n = Int32.Parse(json["result"]["vout"][i]["n"].ToString()); vout.Add(v); } } ukupnoIzlaz = ukupnoIzlaztr; //vin decimal ukupnoUlaztr = 0; vin = _vin; int br2 = _vin.Count(); foreach (int i in Enumerable.Range(0, br2)) { ukupnoUlaztr += _vin[i].value; } ukupnoUlaz = ukupnoUlaztr; if (_vin[0].coinbase == true) { fee = 0; } else { fee = ukupnoUlaz - ukupnoIzlaz; } }
public Transaction(JObject json, List <Vin> _vin)//summary { txid = json["result"]["txid"].ToString(); hash = json["result"]["hash"].ToString(); int br = json["result"]["vout"].Count(); decimal ukupnoIzlaztr = 0; vout = new List <Vout>(); foreach (int i in Enumerable.Range(0, br)) { var s = json["result"]["vout"][i]["value"].ToString(); decimal value = Decimal.Round(decimal.Parse(json["result"]["vout"][i]["value"].ToString(), System.Globalization.NumberStyles.Any), 8, MidpointRounding.AwayFromZero); if (value > 0) { ukupnoIzlaztr += value; int bradresa = json["result"]["vout"][i]["scriptPubKey"]["addresses"].Count(); List <string> a = new List <string>(); foreach (int j in Enumerable.Range(0, bradresa)) { string address = json["result"]["vout"][i]["scriptPubKey"]["addresses"][j].ToString(); a.Add(address); } Vout v = new Vout(); v.value = value; ScriptPubKey spk = new ScriptPubKey(); spk.addresses = new List <string>(); foreach (string add in a) { spk.addresses.Add(add); } v.scriptPubKey = spk; vout.Add(v); } } ukupnoIzlaz = ukupnoIzlaztr; decimal ukupnoUlaztr = 0; vin = _vin; int br2 = _vin.Count(); foreach (int i in Enumerable.Range(0, br2)) { ukupnoUlaztr += _vin[i].value; } ukupnoUlaz = ukupnoUlaztr; if (_vin[0].coinbase == true) { fee = 0; } else { fee = ukupnoUlaz - ukupnoIzlaz; } }