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

Trade payout address was reused from prior trade & no funds received #5725

Closed
ghost opened this issue Sep 25, 2021 · 7 comments · Fixed by #6590
Closed

Trade payout address was reused from prior trade & no funds received #5725

ghost opened this issue Sep 25, 2021 · 7 comments · Fixed by #6590

Comments

@ghost
Copy link

ghost commented Sep 25, 2021

Buy trade, maker: czcgg. Upon clicking "Payment started", the trade immediately transitioned to complete, although the seller had not yet acknowledged payment receipt.

Investigation showed that the trade obtained the same payout address as a prior trade done an hour earlier. Therefore the payout address listener found funds (from the prior trade) - this indicated to Bisq that the trade was complete.

The code in Bisq explicitly requests an unused address, ultimately relying on BitcoinJ for that.

An unused payout address is requested at trade initiation:

AddressEntry makerPayoutAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT);

public AddressEntry getFreshAddressEntry(boolean segwit) {
AddressEntry.Context context = AddressEntry.Context.AVAILABLE;
Optional<AddressEntry> addressEntry = getAddressEntryListAsImmutableList().stream()
.filter(e -> context == e.getContext())
.filter(e -> isAddressUnused(e.getAddress()))

public boolean isAddressUnused(Address address) {
return getNumTxOutputsForAddress(address) == 0;

public int getNumTxOutputsForAddress(Address address) {
return getTxOutputAddressMultiset().count(address);
}
private Multiset<Address> getTxOutputAddressMultiset() {
return txOutputAddressCache.updateAndGet(set -> set != null ? set : computeTxOutputAddressMultiset());
}
private Multiset<Address> computeTxOutputAddressMultiset() {
return wallet.getTransactions(false).stream()
.flatMap(t -> t.getOutputs().stream())
.map(WalletService::getAddressFromOutput)
.filter(Objects::nonNull)
.collect(ImmutableMultiset.toImmutableMultiset());

https://github.com/bisq-network/bitcoinj/blob/3186b200fff690fa51f3ebbf578f427d78242bc2/core/src/main/java/org/bitcoinj/wallet/Wallet.java#L3000-L3009

@ghost
Copy link

ghost commented Sep 28, 2021

Is it problem with BitcoinJ getTransactions method, or rather with cache (txOutputAddressCache) ?

@ghost
Copy link
Author

ghost commented Sep 28, 2021

I don't see anything wrong with the few lines of code used to create txOutputAddressCache. Unfortunately I don't know a way to reproduce the problem, it just seems to occasionally happen to random users. Similar example

@ghost
Copy link
Author

ghost commented Dec 18, 2021

This problem has been reported again. A prior trade completed normally then its payout address was reused by trade t9jejy even though the prior payout had been made, seen and confirmed in the blockchain. So exactly the same circumstances, even the duration of time between payout and re-used payout (approx 1 hour) is the same.

@ghost
Copy link
Author

ghost commented Feb 7, 2022

Received a third reported case mpcfvoz buy, taker for 0.01 BTC. The trade closed soon after taker hit "payment initiated". Bisq was looking for a payout on an address, but that address had been used as payout for a previous trade, 11 hours prior. So Bisq saw the earlier payout and closed this trade too soon. This is because Bisq expects a payout address to only be used one time.

A "band-aid" fix might possibly be to check for the payout amount to match the trade details, and that might prevent the issue from a user perspective, but the underlying problem is that Bisq chose to reuse an old address which is bad practice and quite wrong.

Opinions sought from @bisq-network/bisq-maintainers @chimp1984

@chimp1984
Copy link
Contributor

Yes your suggestion sounds feasible. The address should not be reused but there might be edge cases/bug situations where that happens.

@ghost
Copy link
Author

ghost commented May 3, 2022

Another instance of this issue was reported by @pazza83.

@ghost
Copy link

ghost commented Feb 19, 2023

Checking for payout amount would not work if the trade was settled using Manual Payout or with a Mediation penalty. But checking that block height of the payout > deposit block height would work.

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

Successfully merging a pull request may close this issue.

2 participants