mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 15:00:30 +01:00
core: Implement sendBsqTest
First, the sendBsq test creates one BTC and two BSQ wallets. Afterward, it funds the BTC and one BSQ wallet with 1 BTC. Next, the funded BSQ wallet sends 100 BSQ to the second BSQ wallet.
This commit is contained in:
parent
3263a9145b
commit
abcc9f8185
4 changed files with 158 additions and 2 deletions
|
@ -68,6 +68,14 @@ dependencies {
|
|||
integrationTestImplementation('bitcoind:regtest') {
|
||||
exclude(module: 'kotlin-stdlib-jdk8')
|
||||
}
|
||||
integrationTestImplementation libs.hamcrest
|
||||
integrationTestImplementation libs.mockito.core
|
||||
integrationTestImplementation libs.mockito.junit.jupiter
|
||||
|
||||
integrationTestImplementation libs.junit.jupiter.api
|
||||
integrationTestImplementation libs.junit.jupiter.params
|
||||
|
||||
integrationTestRuntimeOnly libs.junit.jupiter.engine
|
||||
}
|
||||
|
||||
test {
|
||||
|
|
148
core/src/integrationTest/java/bisq/core/BitcoinjBsqTests.java
Normal file
148
core/src/integrationTest/java/bisq/core/BitcoinjBsqTests.java
Normal file
|
@ -0,0 +1,148 @@
|
|||
package bisq.core;
|
||||
|
||||
import bisq.core.btc.exceptions.BsqChangeBelowDustException;
|
||||
import bisq.core.btc.wallet.BisqDefaultCoinSelector;
|
||||
import bisq.core.btc.wallet.BsqCoinSelector;
|
||||
import bisq.core.btc.wallet.BsqWalletV2;
|
||||
import bisq.core.btc.wallet.BtcWalletV2;
|
||||
import bisq.core.btc.wallet.WalletFactory;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.dao.state.model.blockchain.TxOutputKey;
|
||||
import bisq.core.dao.state.unconfirmed.UnconfirmedBsqChangeOutputListService;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.TransactionOutput;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
import org.bitcoinj.wallet.Wallet;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
|
||||
|
||||
import bisq.wallets.regtest.BitcoindExtension;
|
||||
import bisq.wallets.regtest.bitcoind.BitcoindRegtestSetup;
|
||||
|
||||
@ExtendWith(BitcoindExtension.class)
|
||||
@Slf4j
|
||||
public class BitcoinjBsqTests {
|
||||
|
||||
private static class BisqRegtestNetworkParams extends RegTestParams {
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
}
|
||||
|
||||
private final BitcoindRegtestSetup regtestSetup;
|
||||
private final BisqRegtestNetworkParams networkParams;
|
||||
|
||||
public BitcoinjBsqTests(BitcoindRegtestSetup regtestSetup) {
|
||||
this.regtestSetup = regtestSetup;
|
||||
networkParams = new BisqRegtestNetworkParams();
|
||||
networkParams.setPort(regtestSetup.getP2pPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendBsqTest(@TempDir Path tempDir) throws InterruptedException, InsufficientMoneyException, BsqChangeBelowDustException {
|
||||
var walletFactory = new WalletFactory(networkParams);
|
||||
Wallet btcWallet = walletFactory.createBtcWallet();
|
||||
Wallet secondBsqWallet = walletFactory.createBsqWallet();
|
||||
|
||||
var wallets = List.of(btcWallet, secondBsqWallet);
|
||||
var regtestWalletAppKit = new RegtestWalletAppKit(networkParams, tempDir, wallets);
|
||||
regtestWalletAppKit.initialize();
|
||||
|
||||
WalletAppKit walletAppKit = regtestWalletAppKit.getWalletAppKit();
|
||||
Wallet bsqWallet = walletAppKit.wallet();
|
||||
|
||||
var bsqWalletReceivedLatch = new CountDownLatch(1);
|
||||
bsqWallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) ->
|
||||
bsqWalletReceivedLatch.countDown());
|
||||
|
||||
var btcWalletReceivedLatch = new CountDownLatch(1);
|
||||
btcWallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) ->
|
||||
btcWalletReceivedLatch.countDown());
|
||||
|
||||
Address currentReceiveAddress = bsqWallet.currentReceiveAddress();
|
||||
String address = currentReceiveAddress.toString();
|
||||
regtestSetup.fundAddress(address, 1.0);
|
||||
|
||||
currentReceiveAddress = btcWallet.currentReceiveAddress();
|
||||
address = currentReceiveAddress.toString();
|
||||
regtestSetup.fundAddress(address, 1.0);
|
||||
|
||||
regtestSetup.mineOneBlock();
|
||||
|
||||
boolean isSuccess = bsqWalletReceivedLatch.await(30, TimeUnit.SECONDS);
|
||||
assertThat("BSQ wallet not funded after 30 seconds.", isSuccess);
|
||||
|
||||
Coin balance = bsqWallet.getBalance();
|
||||
assertThat("BitcoinJ BSQ wallet balance should equal 1 BTC.", balance.equals(Coin.COIN));
|
||||
|
||||
isSuccess = btcWalletReceivedLatch.await(30, TimeUnit.SECONDS);
|
||||
assertThat("BTC wallet not funded after 30 seconds.", isSuccess);
|
||||
|
||||
balance = btcWallet.getBalance();
|
||||
assertThat("BitcoinJ BTC wallet balance should equal 1 BTC.", balance.equals(Coin.COIN));
|
||||
|
||||
DaoStateService daoStateService = mock(DaoStateService.class);
|
||||
doReturn(true).when(daoStateService)
|
||||
.isTxOutputSpendable(any(TxOutputKey.class));
|
||||
|
||||
var bsqCoinSelector = new BsqCoinSelector(daoStateService, mock(UnconfirmedBsqChangeOutputListService.class));
|
||||
var btcCoinSelector = new BisqDefaultCoinSelector(true) {
|
||||
@Override
|
||||
protected boolean isDustAttackUtxo(TransactionOutput output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTxOutputSpendable(TransactionOutput output) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var btcWalletV2 = new BtcWalletV2(btcCoinSelector, btcWallet);
|
||||
var bsqWalletV2 = new BsqWalletV2(networkParams,
|
||||
walletAppKit.peerGroup(),
|
||||
btcWalletV2,
|
||||
bsqWallet,
|
||||
bsqCoinSelector);
|
||||
|
||||
var secondBsqWalletReceivedLatch = new CountDownLatch(1);
|
||||
secondBsqWallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) ->
|
||||
secondBsqWalletReceivedLatch.countDown());
|
||||
|
||||
// Send 100 BSQ (1 BSQ = 100 Satoshis)
|
||||
Address receiverAddress = secondBsqWallet.currentReceiveAddress();
|
||||
Coin receiverAmount = Coin.ofSat(100 * 100);
|
||||
bsqWalletV2.sendBsq(receiverAddress, receiverAmount, Coin.ofSat(10));
|
||||
|
||||
regtestSetup.mineOneBlock();
|
||||
|
||||
isSuccess = secondBsqWalletReceivedLatch.await(30, TimeUnit.SECONDS);
|
||||
assertThat("Didn't receive BSQ after 30 seconds.", isSuccess);
|
||||
|
||||
assertEquals(bsqWallet.getBalance(), Coin.ofSat(99990000));
|
||||
assertEquals(btcWallet.getBalance(), Coin.ofSat(99999747));
|
||||
assertEquals(secondBsqWallet.getBalance(), Coin.ofSat(10000));
|
||||
}
|
||||
}
|
|
@ -134,7 +134,7 @@ public abstract class BisqDefaultCoinSelector implements CoinSelector {
|
|||
return isConfirmed || (isPending && (permitForeignPendingTx || isOwnTx));
|
||||
}
|
||||
|
||||
abstract boolean isTxOutputSpendable(TransactionOutput output);
|
||||
protected abstract boolean isTxOutputSpendable(TransactionOutput output);
|
||||
|
||||
// TODO Why it uses coin age and not try to minimize number of inputs as the highest priority?
|
||||
// Asked Oscar and he also don't knows why coin age is used. Should be changed so that min. number of inputs is
|
||||
|
|
|
@ -31,7 +31,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
* We lookup for spendable outputs which matches any of our addresses.
|
||||
*/
|
||||
@Slf4j
|
||||
class BtcCoinSelector extends BisqDefaultCoinSelector {
|
||||
public class BtcCoinSelector extends BisqDefaultCoinSelector {
|
||||
private final Set<Address> addresses;
|
||||
private final long ignoreDustThreshold;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue