Skip to content

Commit

Permalink
Fix: Output from txbuilder silently removed (#1185)
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasDorier authored Sep 6, 2023
1 parent f39e5da commit 9eb689d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 13 deletions.
22 changes: 22 additions & 0 deletions NBitcoin.Tests/transaction_tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3136,6 +3136,28 @@ public void Play()
var tx = aa.ExtractTransaction();
}

[Fact]
[Trait("UnitTest", "UnitTest")]
public void DoNotGenerateTransactionWithDust()
{
var k = new Key();
var scriptCoin = RandomCoin(Money.Coins(0.0003m), k.PubKey.ScriptPubKey, true);

var builder = Network.CreateTransactionBuilder();

var dust = builder.GetDust(new Key().GetScriptPubKey(ScriptPubKeyType.Legacy));

var ex = Assert.Throws<OutputTooSmallException>(() => {
builder
.AddCoins(scriptCoin)
.Send(new Key(), dust - Money.Satoshis(1))
.SetChange(new Key())
.BuildTransaction(false);
}
);
Assert.Equal(OutputTooSmallException.ErrorType.TooSmallBeforeSubstractedFee, ex.Reason);
}


[Fact]
[Trait("UnitTest", "UnitTest")]
Expand Down
15 changes: 2 additions & 13 deletions NBitcoin/TransactionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -820,11 +820,6 @@ public decimal FeeWeight
get;
set;
}
/// <summary>
/// Money which has been recovered from outputs that are too small to be included
/// we should be able to pay fees with that
/// </summary>
public Money SurrendedValue { get; set; } = Money.Zero;
}

List<BuilderGroup> _BuilderGroups = new List<BuilderGroup>();
Expand Down Expand Up @@ -1164,11 +1159,6 @@ public TransactionBuilder Send(Script scriptPubKey, Money amount)
if (amount < Money.Zero)
throw new ArgumentOutOfRangeException(nameof(amount), "amount can't be negative");
_LastSendBuilder = null; //If the amount is dust, we don't want the fee to be paid by the previous Send
if (DustPrevention && amount < GetDust(scriptPubKey) && !_OpReturnTemplate.CheckScriptPubKey(scriptPubKey))
{
CurrentGroup.SurrendedValue += amount;
return this;
}

var builder = new SendBuilder(this, amount, scriptPubKey);
CurrentGroup.Builders.Add(builder.Build);
Expand Down Expand Up @@ -1895,11 +1885,10 @@ private ICoin[] BuildTransaction(
{
var gctx = ctx.CurrentGroupContext;
IMoney zero = ctx.Zero;
IMoney surrendedMoney = zero is Money ? group.SurrendedValue : zero;
foreach (var builder in builders)
builder(ctx);

IMoney selectionTarget = (gctx.SentOutput + gctx.Fee - gctx.LeftOverChange + surrendedMoney).GetAmount(zero);
IMoney selectionTarget = (gctx.SentOutput + gctx.Fee - gctx.LeftOverChange).GetAmount(zero);

var unconsumed = coins.Where(c => !ctx.ConsumedOutpoints.Contains(c.Outpoint)).ToArray();

Expand All @@ -1917,7 +1906,7 @@ private ICoin[] BuildTransaction(
selectionTarget.Sub(unconsumed.Select(u => u.Amount).Sum(zero)));

var totalInput = selection.Select(s => s.Amount).Sum(zero);
var change = totalInput.Sub(selectionTarget).Add(surrendedMoney);
var change = totalInput.Sub(selectionTarget);
if (change.CompareTo(zero) == -1)
throw new NotEnoughFundsException(notEnoughFundsMessage,
group.Name,
Expand Down

0 comments on commit 9eb689d

Please sign in to comment.