public void BuildTransaction_When_OpReturnAmount_Is_Populated_Should_Add_Extra_Output_With_Data_And_Amount() { WalletTransactionHandlerTestContext testContext = SetupWallet(); string opReturnData = "some extra transaction info"; byte[] expectedBytes = Encoding.UTF8.GetBytes(opReturnData); TransactionBuildContext context = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, opReturnData); context.OpReturnAmount = Money.Coins(0.0001m); Transaction transactionResult = testContext.WalletTransactionHandler.BuildTransaction(context); IEnumerable <TxOut> unspendableOutputs = transactionResult.Outputs.Where(o => o.ScriptPubKey.IsUnspendable).ToList(); unspendableOutputs.Count().Should().Be(1); unspendableOutputs.Single().Value.Should().Be(Money.Coins(0.0001m)); IEnumerable <Op> ops = unspendableOutputs.Single().ScriptPubKey.ToOps(); ops.Count().Should().Be(2); ops.First().Code.Should().Be(OpcodeType.OP_RETURN); ops.Last().PushData.Should().BeEquivalentTo(expectedBytes); }
public void BuildTransactionNoChangeAdressesLeftCreatesNewChangeAddress() { WalletTransactionHandlerTestContext testContext = SetupWallet(); TransactionBuildContext context = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); Transaction transactionResult = testContext.WalletTransactionHandler.BuildTransaction(context); Transaction result = this.Network.CreateTransaction(transactionResult.ToHex()); (PubKey PubKey, BitcoinPubKeyAddress Address)expectedChangeAddressKeys = WalletTestsHelpers.GenerateAddressKeys(testContext.Wallet, testContext.AccountKeys.ExtPubKey, "1/0"); Assert.Single(result.Inputs); Assert.Equal(testContext.AddressTransaction.Id, result.Inputs[0].PrevOut.Hash); Assert.Equal(2, result.Outputs.Count); TxOut output = result.Outputs[0]; Assert.Equal((testContext.AddressTransaction.Amount - context.TransactionFee - 7500), output.Value); Assert.Equal(expectedChangeAddressKeys.Address.ScriptPubKey, output.ScriptPubKey); output = result.Outputs[1]; Assert.Equal(7500, output.Value); Assert.Equal(testContext.DestinationKeys.PubKey.ScriptPubKey, output.ScriptPubKey); Assert.Equal(testContext.AddressTransaction.Amount - context.TransactionFee, result.TotalOut); Assert.NotNull(transactionResult.GetHash()); Assert.Equal(result.GetHash(), transactionResult.GetHash()); }
public void BuildTransaction_When_OpReturnData_Is_Null_Should_Not_Add_Extra_Output() { WalletTransactionHandlerTestContext testContext = SetupWallet(); string opReturnData = null; TransactionBuildContext context = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, opReturnData); Transaction transactionResult = testContext.WalletTransactionHandler.BuildTransaction(context); transactionResult.Outputs.Where(o => o.ScriptPubKey.IsUnspendable).Should() .BeEmpty("because opReturnData is null"); }
public void BuildTransaction_When_OpReturnData_Is_Too_Long_Should_Fail_With_Helpful_Message() { WalletTransactionHandlerTestContext testContext = SetupWallet(); byte[] eightyOneBytes = Encoding.UTF8.GetBytes(this.costlyOpReturnData).Concat(Convert.ToByte(1)); string tooLongOpReturnString = Encoding.UTF8.GetString(eightyOneBytes); TransactionBuildContext context = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, tooLongOpReturnString); new Action(() => testContext.WalletTransactionHandler.BuildTransaction(context)) .Should().Throw <ArgumentOutOfRangeException>() .And.Message.Should().Contain(" maximum size of 83"); }
public void EstimateFee_Without_OpReturnData_Should_Be_Less_Than_Estimate_Fee_With_Costly_OpReturnData() { WalletTransactionHandlerTestContext testContext = SetupWallet(); // Context with OpReturnData TransactionBuildContext estimateContextWithOpReturn = CreateContext(this.Network, testContext.WalletReference, null, testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, this.costlyOpReturnData); Money feeEstimateWithOpReturn = testContext.WalletTransactionHandler.EstimateFee(estimateContextWithOpReturn); // Context without OpReturnData TransactionBuildContext estimateContextWithoutOpReturn = CreateContext(this.Network, testContext.WalletReference, null, testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, null); Money feeEstimateWithoutOpReturn = testContext.WalletTransactionHandler.EstimateFee(estimateContextWithoutOpReturn); feeEstimateWithOpReturn.Should().NotBe(feeEstimateWithoutOpReturn); feeEstimateWithoutOpReturn.Satoshi.Should().BeLessThan(feeEstimateWithOpReturn.Satoshi); }
public void EstimateFee_WithLowFee_Matches_BuildTransaction_WithLowFee_With_Long_OpReturnData_added() { WalletTransactionHandlerTestContext testContext = SetupWallet(); // Context to build requires password in order to sign transaction. TransactionBuildContext buildContext = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, this.costlyOpReturnData); testContext.WalletTransactionHandler.BuildTransaction(buildContext); // Context for estimate does not need password. TransactionBuildContext estimateContext = CreateContext(this.Network, testContext.WalletReference, null, testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, this.costlyOpReturnData); Money feeEstimate = testContext.WalletTransactionHandler.EstimateFee(estimateContext); feeEstimate.Should().Be(buildContext.TransactionFee); }
public void EstimateFeeWithLowFeeMatchesBuildTxLowFee() { WalletTransactionHandlerTestContext testContext = SetupWallet(); // Context to build requires password in order to sign transaction. TransactionBuildContext buildContext = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); testContext.WalletTransactionHandler.BuildTransaction(buildContext); // Context for estimate does not need password. TransactionBuildContext estimateContext = CreateContext(this.Network, testContext.WalletReference, null, testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); Money fee = testContext.WalletTransactionHandler.EstimateFee(estimateContext); Assert.Equal(fee, buildContext.TransactionFee); }
public void Actual_Fee_Without_OpReturnData_Should_Be_Less_Than_Actual_Fee_With_Costly_OpReturnData() { WalletTransactionHandlerTestContext testContext = SetupWallet(); // Context with OpReturnData TransactionBuildContext contextWithOpReturn = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, this.costlyOpReturnData); testContext.WalletTransactionHandler.BuildTransaction(contextWithOpReturn); // Context without OpReturnData TransactionBuildContext contextWithoutOpReturn = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0, null); testContext.WalletTransactionHandler.BuildTransaction(contextWithoutOpReturn); contextWithoutOpReturn.TransactionFee.Should().NotBe(contextWithOpReturn.TransactionFee); contextWithoutOpReturn.TransactionFee.Satoshi.Should().BeLessThan(contextWithOpReturn.TransactionFee.Satoshi); }
public void BuildTransactionUsesGivenChangeAddress() { WalletTransactionHandlerTestContext testContext = SetupWallet(); TransactionBuildContext context = CreateContext(this.Network, testContext.WalletReference, "password", testContext.DestinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); var key = new Key(); BitcoinPubKeyAddress address = key.PubKey.GetAddress(this.Network); HdAddress changeAddress = context.ChangeAddress = new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/0/0", Address = address.ToString(), Pubkey = key.PubKey.ScriptPubKey, ScriptPubKey = address.ScriptPubKey, //Transactions = new List<TransactionData>() }; Transaction transactionResult = testContext.WalletTransactionHandler.BuildTransaction(context); Transaction result = this.Network.CreateTransaction(transactionResult.ToHex()); Assert.Single(result.Inputs); Assert.Equal(testContext.AddressTransaction.Id, result.Inputs[0].PrevOut.Hash); Assert.Equal(2, result.Outputs.Count); TxOut output = result.Outputs[0]; Assert.Equal((testContext.AddressTransaction.Amount - context.TransactionFee - 7500), output.Value); Assert.Equal(changeAddress.ScriptPubKey, output.ScriptPubKey); output = result.Outputs[1]; Assert.Equal(7500, output.Value); Assert.Equal(testContext.DestinationKeys.PubKey.ScriptPubKey, output.ScriptPubKey); Assert.Equal(testContext.AddressTransaction.Amount - context.TransactionFee, result.TotalOut); Assert.NotNull(transactionResult.GetHash()); Assert.Equal(result.GetHash(), transactionResult.GetHash()); }