Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to speed up transaction: Bad request #11215

Open
MarnixCroes opened this issue Aug 4, 2023 · 11 comments
Open

Unable to speed up transaction: Bad request #11215

MarnixCroes opened this issue Aug 4, 2023 · 11 comments

Comments

@MarnixCroes
Copy link
Contributor

General Description

This is a selfspend.
In the logs it says "not enough additional fees to relay"? this is the transaction https://mempool.space/testnet/tx/db82cd4e2383c95f1721dc5d10001a19ab792f0f79d1e20c0997c0beb4c4c448

How To Reproduce?

  1. Do selfspend to fresh address
  2. Click on Speed up
  3. See ERROR

Screenshots

Screenshot from 2023-08-04 14-57-25

Logs

I got the same logs everytime (same item order and frequency), tried 4 times

2023-08-04 14:56:41.432 [1] INFO	TransactionBroadcaster.BroadcastTransactionToNetworkNodeAsync (47)	Trying to broadcast transaction with random node (::ffff:66.183.0.205):9078dceb617d29bbfe9cfc0548416f655a6c83cea41b545f4f229ceb0a49ad29.
2023-08-04 14:56:45.773 [26] INFO	P2pBehavior.ProcessGetDataAsync (109)	Successfully served transaction to node ([::ffff:66.183.0.205]:18333): 9078dceb617d29bbfe9cfc0548416f655a6c83cea41b545f4f229ceb0a49ad29.
2023-08-04 14:56:45.773 [6] INFO	P2pBehavior.ProcessGetDataAsync (109)	Successfully served transaction to node ([::ffff:66.183.0.205]:18333): 9078dceb617d29bbfe9cfc0548416f655a6c83cea41b545f4f229ceb0a49ad29.
2023-08-04 14:56:46.437 [26] INFO	TransactionBroadcaster.BroadcastTransactionToNetworkNodeAsync (71)	Disconnected node: ::ffff:66.183.0.205. Successfully broadcasted transaction: 9078dceb617d29bbfe9cfc0548416f655a6c83cea41b545f4f229ceb0a49ad29.
2023-08-04 14:57:08.437 [26] INFO	TransactionBroadcaster.SendTransactionAsync (178)	Random node could not broadcast transaction. Reason: Did not serve the transaction..
2023-08-04 14:57:08.439 [26] INFO	TransactionBroadcaster.BroadcastTransactionToBackendAsync (94)	Broadcasting with backend...
2023-08-04 14:57:10.280 [1] ERROR	SpeedUpTransactionDialogViewModel.OnSpeedUpTransactionAsync (88)	System.Net.Http.HttpRequestException: Bad Request
insufficient fee, rejecting replacement 9078dceb617d29bbfe9cfc0548416f655a6c83cea41b545f4f229ceb0a49ad29, not enough additional fees to relay; 0.00000152 < 0.00000153:::01000000018b1cec07c1bc714ec9dd8917e83936dbbb2f7ef967ace26642b4859881b27e620200000000fdffffff0210270000000000001600140df8b90e724d9cc090c490c7bbf06ce14bf2f36861e502000000000022512079178a01b2cf2f4d17a2a337f28e8aacf107e3c31545de9aa920c282653daf1100000000
   at WalletWasabi.Tor.Http.Extensions.HttpResponseMessageExtensions.ThrowRequestExceptionFromContentAsync(HttpResponseMessage me, CancellationToken cancellationToken) in WalletWasabi/Tor/Http/Extensions/HttpResponseMessageExtensions.cs:line 122
   at WalletWasabi.WebClients.Wasabi.WasabiClient.BroadcastAsync(String hex) in WalletWasabi/WebClients/Wasabi/WasabiClient.cs:line 147
   at WalletWasabi.WebClients.Wasabi.WasabiClient.BroadcastAsync(Transaction transaction) in WalletWasabi/WebClients/Wasabi/WasabiClient.cs:line 153
   at WalletWasabi.WebClients.Wasabi.WasabiClient.BroadcastAsync(SmartTransaction transaction) in WalletWasabi/WebClients/Wasabi/WasabiClient.cs:line 158
   at WalletWasabi.Blockchain.TransactionBroadcasting.TransactionBroadcaster.BroadcastTransactionToBackendAsync(SmartTransaction transaction) in WalletWasabi/Blockchain/TransactionBroadcasting/TransactionBroadcaster.cs:line 101
   at WalletWasabi.Blockchain.TransactionBroadcasting.TransactionBroadcaster.SendTransactionAsync(SmartTransaction transaction) in WalletWasabi/Blockchain/TransactionBroadcasting/TransactionBroadcaster.cs:line 197
   at WalletWasabi.Fluent.ViewModels.Wallets.Home.History.Features.SpeedUpTransactionDialogViewModel.OnSpeedUpTransactionAsync(BuildTransactionResult boostingTransaction) in WalletWasabi.Fluent/ViewModels/Wallets/Home/History/Features/SpeedUpTransactionDialogViewModel.cs:line 81

Wasabi Version

3e151ca

@MarnixCroes
Copy link
Contributor Author

I can repro it now with another transaction aswell

@nopara73
Copy link
Contributor

nopara73 commented Aug 5, 2023

not enough additional fees to relay; 0.00000152 < 0.00000153

looks like you only need a single satoshi there : )

@nopara73
Copy link
Contributor

nopara73 commented Aug 5, 2023

cant repro

@yahiheb
Copy link
Collaborator

yahiheb commented Aug 6, 2023

This happened to me as well: #11224
5686d5d
I did cancel a tx but that is basically the same as a selfspend.

@lukasdll
Copy link

lukasdll commented Sep 21, 2023

Update: After doing many more tests than the 4 below, I could reproduce the issue, but the conditions to reproduce are yet unclear. Sometimes speeding up a self-transaction works fine others it doesn't.


Detailed explanation:

To try to reproduce the issue, I made 2 different tests on Main and 2 different tests on Testnet, and I could not reproduce any unexpected behavior, but I found a potential improvement (balance check + UX message).

On Main I could replace the transaction without any error related to fees, both using the speed-up and the cancellation.

Main test 1:

  1. Send the transaction with default fees.
    https://mempool.space/tx/8f7b055f8e88cb7a0fe589c585d84b847f75d5ea2df9e1af357fe4366168acdd
  2. Speed-up the transaction (success).
    https://mempool.space/tx/86cc02ec625cef07d3fb009c7f89e851a96a6cd7a1a2500a84e6b916d99126f6
  3. Cancel the transaction (success).
    https://mempool.space/tx/8f7b055f8e88cb7a0fe589c585d84b847f75d5ea2df9e1af357fe4366168acdd

Main test 2:

  1. Send the transaction with lower fees than the default.
    https://mempool.space/tx/69792d8483c7e9009e612fc3efa649e7be0bf430d079e3b1c4297bce825f0051
  2. Cancel the transaction (success).
    https://mempool.space/tx/9ebeda9b6894799ee0b9997b21487fedf15d8c3242aaacf80d1ea8990173b77a

OS: Linux
Wallet version: v2.0.4
Sha256: 1dbc4b531f75504631277898b274d068651fa1ad2cdb7df455d239d15a97abaf Wasabi-2.0.4.deb


Then I tried to reproduce on Testnet with a different OS (Windows).

On Testnet (Test 1), I could obtain the same error message.

Testnet 1:

  1. Send the transaction with low fees (1.36 sats v/B).
    https://mempool.space/testnet/tx/423f4e5fbcd73bf559cd8103682cbf064039404986eac98c5d9a9b909b417dce
  2. Try to speed-up, and it fails: HttpRequestException: BadRequest insufficient fee, rejecting replacement.

Logs:

TransactionBroadcaster.BroadcastTransactionToBackendAsync (94)  Broadcasting with backend...
ERROR  SpeedUpTransactionDialogViewModel.OnSpeedUpTransactionAsync (97)  System.Net.Http.HttpRequestException: Bad Request
insufficient fee, rejecting replacement c727254e9ad92236d999619ebfd702e0722867ada249429e159a8c71feecefbe, not enough additional fees to relay; 0.00000109 < 0.0000011:::01000000000101e6d4345bac49e96736e86ca19c0e35f4cc8b0becd9aa6047ec2ded1c64e0ecea0000000000fdffffff01ab1e000000000000160014f982508ba23df0209c0cf526da53a16b75294d29024730440220510430901a220c843fe7947907e153fdec0070ef38f8b85f8199f7867f53cfce022036f075dbdbe455b7bf29a4548be0701c50b937729da8a79a55e9a9fdfd2754c20121031975815df14a24d9fb3d2e9a2d5d3dd287cfeb9a5be0539f38bc54d207586abc00000000
   at WalletWasabi.Tor.Http.Extensions.HttpResponseMessageExtensions.ThrowRequestExceptionFromContentAsync(HttpResponseMessage me, CancellationToken cancellationToken)
   at WalletWasabi.WebClients.Wasabi.WasabiClient.BroadcastAsync(String hex)
   at WalletWasabi.WebClients.Wasabi.WasabiClient.BroadcastAsync(Transaction transaction)
   at WalletWasabi.WebClients.Wasabi.WasabiClient.BroadcastAsync(SmartTransaction transaction)
   at WalletWasabi.Blockchain.TransactionBroadcasting.TransactionBroadcaster.BroadcastTransactionToBackendAsync(SmartTransaction transaction)
   at WalletWasabi.Blockchain.TransactionBroadcasting.TransactionBroadcaster.SendTransactionAsync(SmartTransaction transaction)
   at WalletWasabi.Fluent.ViewModels.Wallets.Home.History.Features.SpeedUpTransactionDialogViewModel.OnSpeedUpTransactionAsync(BuildTransactionResult boostingTransaction)

Testnet 2:

  1. Send the transaction with low fees (1.37 sats v/B).
    https://mempool.space/testnet/tx/460d4257c0014df4e8635ec210ec88b4ec06ca1dbc414603bd3a99dcc024a6fc
  2. Speed-up the transaction (success).
    https://mempool.space/testnet/tx/328b33799307cdbe6e8e67fff0d1f940127756321cadd0d1768b95a0208771b3

OS: Windows
Wallet version: v2.0.4
Sha256: 97cfc014ab8d735c9530aac74537e322704779c641f35ac2bf21619039536ab2 Wasabi-2.0.4.msi

@lukasdll
Copy link

After a lot more testing, I reached the conclusion that there is probably a rounding issue while calculating or subtracting the RBF fee to the output. That's why there is always 1 missing sat, and the transaction fails, but only when maths' want to make that rounding issue appear.

I found the place in the code where the magic happens and added quite a few logs.

It is in particular interesting:

Final amount in the selected own output after fee subtraction: 0.00005990

RBF Transaction Outputs: 0.00005991 to tb1qc4yczzve5mhj335qnrxggcqavvlvdmgp5j929u

Full logs below:

Transaction is successfully propagated: c8dbe5fd6a28ed792a6e68525106fb4790c345714880d497c9841c624c5b2028.
Starting to build a RBF transaction.
Best fee rate calculated: 1 Sat/B
Original fee: 0.00000159, Transaction size: 110 bytes
Original transaction fee rate: 1.445 Sat/B
Minimum RBF fee rate calculated: 2.445 Sat/B
Additional fee required for RBF: 0.00000110
Final RBF fee rate to use: 2.445 Sat/B
Selected own output for RBF: 0.00006100 to address tb1qc4yczzve5mhj335qnrxggcqavvlvdmgp5j929u
Final amount in the selected own output after fee subtraction: 0.00005990
Modifying the largest own output to cover the new fee.
Additional fee required for RBF: 0.00000110
Original transaction fee rate: 1.445 Sat/B
Final amount in the selected own output after fee subtraction: 0.00005990
Is the added fee sufficient for RBF? True
Final RBF transaction hash: 82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801
RBF Transaction Inputs: 5082130cb716ebc218fa313e4d2f278c9f8aa73d2595a3f57cc37e709763a7cf
RBF Transaction Outputs: 0.00005991 to tb1qc4yczzve5mhj335qnrxggcqavvlvdmgp5j929u
Total RBF Transaction Output Value: 5991
Final RBF Transaction Fee: 268
areForeignAmountsUnchanged: True
boostingTransaction.Transaction.GetWalletOutputs(_wallet.KeyManager).Any(): True
AreWePayingTheFee: True
Trying to broadcast transaction with random node (::ffff:127.0.0.1):82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801.
Successfully served transaction to node ([::ffff:127.0.0.1]:37150): 82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801.
Successfully served transaction to node ([::ffff:127.0.0.1]:37150): 82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801.
Disconnected node: ::ffff:127.0.0.1. Successfully broadcasted transaction: 82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801.
Round 38b34e58734f5666a82142e362b7f2f529bba5c54fee16630d4924c6e1339415 - Mining Fee Rate: 1 Sat/B, Network: TestNet, Max Suggested Amount: 43000.00000000, Min Amount Credential Value: 0.00005000
Random node could not broadcast transaction. Reason: Did not serve the transaction..
Broadcasting with backend...
ERROR  SpeedUpTransactionDialogViewModel.OnSpeedUpTransactionAsync (114)  System.Net.Http.HttpRequestException: Bad Request
insufficient fee, rejecting replacement 82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801, not enough additional fees to relay; 0.00000109 < 0.0000011:::01000000000101cfa76397707ec37cf5a395253da78a9f8c272f4d3e31fa18c2eb16b70c1382500100000000fdffffff01d417000000000000160014c549810999a6ef28c68098cc84601d633ec6ed010247304402200bbcae0911ec9aab6c0425c4681a0673937c201c96f0642b9373f0b442e6cc61022077204e7f8327553868b4bd4b78e912c4a272881f29f0c809e6a0dac43ffb8d1e012102439d930672257b4d348a4c5c056a9212a01827d0d9992ec1f12b7f366f8dbe762f382600
   at WalletWasabi.Tor.Http.Extensions.HttpResponseMessageExtensions.ThrowRequestExceptionFromContentAsync(HttpResponseMessage me, CancellationToken cancellationToken) in WalletWasabi\Tor\Http\Extensions\HttpResponseMessageExtensions.cs:line 122

https://mempool.space/testnet/tx/c8dbe5fd6a28ed792a6e68525106fb4790c345714880d497c9841c624c5b2028
RBF (failed): 82d73ac7f5db214314c2c1c19877f63d9c1474ae11577de909052ad88fe67801

I should be able to find a fix soon

@lukasdll
Copy link

The problem happens when the final fee rate has three decimals. In the previous failing example, the fee rate was: 2.445 Sat/B.

I pulled the "cables" and found a few suspects in the NBitcoin library:

public decimal SatoshiPerByte
{
    get
    {
        return (decimal)_FeePerK.Satoshi / 1000;
    }
}

If _FeePerK.Satoshi has a value that doesn't evenly divide by 1000, we could lose some precision.

And also:

public Money GetFee(int virtualSize)
{
    Money nFee = _FeePerK.Satoshi * virtualSize / 1000;
    if (nFee == Money.Zero)
        nFee = Money.Satoshis(1.0m);
    return nFee;
}

This could also lead to rounding issues, especially if virtualSize doesn't multiply evenly into _FeePerK.Satoshi * 1000.

A quick & easy solution could be to ceil-up the rbfFeeRate amount in RbfTransaction(...) to two decimals.

		var rbfFeeRate = (bestFeeRate is null || bestFeeRate <= minimumRbfFeeRate)
			? minimumRbfFeeRate
			: bestFeeRate;

		decimal originalRbfFeeRateValue = rbfFeeRate.SatoshiPerByte;
		decimal roundedRbfFeeRateValue = Math.Ceiling(originalRbfFeeRateValue * 100) / 100;
		rbfFeeRate = new FeeRate(roundedRbfFeeRateValue);

I'm testing the above, see if it solves this issue. Probably a unit test with edge cases would be appropriate.

@nopara73
Copy link
Contributor

Is it possible to easily resolve it in NBitcoin? (Doesn't have to be quickly.) https://github.com/MetacoSA/NBitcoin/

@lukasdll
Copy link

Indeed, it would be cleaner to solve it on NBitcoin. I will see what is possible to suggest on that end.

@nopara73
Copy link
Contributor

Thank you, I appreciate it.

@lukasdll
Copy link

lukasdll commented Oct 3, 2023

I could prevent the bug from appearing by altering NBitcoin FeeRate at FeeRate.cs.

The conversion from decimal to long truncates the decimal portion. This can result in small inaccuracies.

E.g.:
The fee rate per byte would be: 101/70 = 1.442857...
The fee rate per kilobyte would be: 1.442857 * 1000 = 1442.857...
But, when converted to long, the value becomes 1442, effectively rounding down and losing the 0.857 fractional value.

		public FeeRate(Money feePaid, int size)
		{
			if (feePaid is null)
				throw new ArgumentNullException(nameof(feePaid));
			if (feePaid.Satoshi < 0)
				throw new ArgumentOutOfRangeException(nameof(feePaid), "Cannot be less than 0.");
			if (size > 0)
				_FeePerK = (long)Math.Round((decimal)feePaid.Satoshi / size * 1000m, MidpointRounding.AwayFromZero);
			else
				_FeePerK = Money.Zero;
		}

By using Math.Round with MidpointRounding.AwayFromZero, any decimal value from .5 to .999' is always rounded up to the next whole number. Without specifying MidpointRounding.AwayFromZero, and thus using the default MidpointRounding.ToEven (Banker’s Rounding), values ending in .5 are rounded to the nearest even whole number, which may produce discrepancies or undesired results in certain circumstances.

I'm going to test it a bit more and make a pull request to the NBitcoin repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants