remove DAO

Co-authored-by: premek <1145361+premek@users.noreply.github.com>
This commit is contained in:
l0nelyc0w 2021-10-19 20:45:55 +03:00 committed by woodser
parent f9f2cd07c3
commit cefba8e4b5
621 changed files with 583 additions and 68805 deletions

View file

@ -1,46 +0,0 @@
package bisq.core.dao.governance.ballot;
import bisq.core.dao.governance.ballot.BallotListService.BallotListChangeListener;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalService;
import bisq.core.dao.governance.proposal.ProposalValidatorProvider;
import bisq.core.dao.governance.proposal.storage.appendonly.ProposalPayload;
import bisq.common.persistence.PersistenceManager;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.junit.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class BallotListServiceTest {
@Test
@SuppressWarnings("unchecked")
public void testAddListenersWhenNewPayloadAdded() {
// given
ObservableList<ProposalPayload> payloads = FXCollections.observableArrayList();
ProposalService proposalService = mock(ProposalService.class);
when(proposalService.getProposalPayloads()).thenReturn(payloads);
BallotListService service = new BallotListService(proposalService, mock(PeriodService.class),
mock(ProposalValidatorProvider.class), mock(PersistenceManager.class));
BallotListChangeListener listener = mock(BallotListChangeListener.class);
service.addListener(listener);
service.addListeners();
// when
payloads.add(mock(ProposalPayload.class, RETURNS_DEEP_STUBS));
// then
verify(listener).onListChanged(any());
}
}

View file

@ -1,30 +0,0 @@
package bisq.core.dao.governance.proposal;
import bisq.core.btc.wallet.WalletsManager;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.state.DaoStateService;
import bisq.network.p2p.P2PService;
import bisq.common.crypto.PubKeyRing;
import bisq.common.persistence.PersistenceManager;
import javafx.beans.property.SimpleIntegerProperty;
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MyProposalListServiceTest {
@Test
public void canInstantiate() {
P2PService p2PService = mock(P2PService.class);
when(p2PService.getNumConnectedPeers()).thenReturn(new SimpleIntegerProperty(0));
PersistenceManager persistenceManager = mock(PersistenceManager.class);
MyProposalListService service = new MyProposalListService(p2PService,
mock(DaoStateService.class),
mock(PeriodService.class), mock(WalletsManager.class), persistenceManager, mock(PubKeyRing.class)
);
}
}

View file

@ -1,127 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.governance.proposal;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.storage.appendonly.ProposalStorageService;
import bisq.core.dao.governance.proposal.storage.temp.TempProposalPayload;
import bisq.core.dao.governance.proposal.storage.temp.TempProposalStorageService;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.DaoPhase;
import bisq.core.dao.state.model.governance.Proposal;
import bisq.network.p2p.P2PService;
import bisq.network.p2p.storage.payload.ProtectedStorageEntry;
import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
import bisq.network.p2p.storage.persistence.ProtectedDataStoreService;
import javafx.collections.ListChangeListener;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Tests of the P2PDataStorage::onRemoved callback behavior to ensure that the proper number of signal events occur.
*/
public class ProposalServiceP2PDataStorageListenerTest {
private ProposalService proposalService;
@Mock
private PeriodService periodService;
@Mock
private DaoStateService daoStateService;
@Mock
private ListChangeListener<Proposal> tempProposalListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.proposalService = new ProposalService(
mock(P2PService.class),
this.periodService,
mock(ProposalStorageService.class),
mock(TempProposalStorageService.class),
mock(AppendOnlyDataStoreService.class),
mock(ProtectedDataStoreService.class),
this.daoStateService,
mock(ProposalValidatorProvider.class),
true);
// Create a state so that all added/removed Proposals will actually update the tempProposals list.
when(this.periodService.isInPhase(anyInt(), any(DaoPhase.Phase.class))).thenReturn(true);
when(this.daoStateService.isParseBlockChainComplete()).thenReturn(false);
}
private static ProtectedStorageEntry buildProtectedStorageEntry() {
ProtectedStorageEntry protectedStorageEntry = mock(ProtectedStorageEntry.class);
TempProposalPayload tempProposalPayload = mock(TempProposalPayload.class);
Proposal tempProposal = mock(Proposal.class);
when(protectedStorageEntry.getProtectedStoragePayload()).thenReturn(tempProposalPayload);
when(tempProposalPayload.getProposal()).thenReturn(tempProposal);
return protectedStorageEntry;
}
// TESTCASE: If an onRemoved callback is called which does not remove anything the tempProposals listeners
// are not signaled.
@Test
public void onRemoved_noSignalIfNoChange() {
this.proposalService.onRemoved(Collections.singletonList(mock(ProtectedStorageEntry.class)));
verify(this.tempProposalListener, never()).onChanged(any());
}
// TESTCASE: If an onRemoved callback is called with 1 element AND it creates a remove of 1 element, the tempProposal
// listeners are signaled once.
@Test
public void onRemoved_signalOnceOnOneChange() {
ProtectedStorageEntry one = buildProtectedStorageEntry();
this.proposalService.onAdded(Collections.singletonList(one));
this.proposalService.getTempProposals().addListener(this.tempProposalListener);
this.proposalService.onRemoved(Collections.singletonList(one));
verify(this.tempProposalListener).onChanged(any());
}
// TESTCASE: If an onRemoved callback is called with 2 elements AND it creates a remove of 2 elements, the
// tempProposal listeners are signaled once.
@Test
public void onRemoved_signalOnceOnMultipleChanges() {
ProtectedStorageEntry one = buildProtectedStorageEntry();
ProtectedStorageEntry two = buildProtectedStorageEntry();
this.proposalService.onAdded(Arrays.asList(one, two));
this.proposalService.getTempProposals().addListener(this.tempProposalListener);
this.proposalService.onRemoved(Arrays.asList(one, two));
verify(this.tempProposalListener).onChanged(any());
}
}

View file

@ -1,79 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.governance.proposal.param;
import bisq.core.dao.governance.param.Param;
import bisq.core.locale.Res;
import bisq.core.util.coin.BsqFormatter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class ChangeParamValidatorTest {
@Before
public void setup() {
Res.setup();
}
@Test
public void testGetChangeValidationResult() throws ParamValidationException {
ChangeParamValidator changeParamValidator = new ChangeParamValidator(null, null, new BsqFormatter());
try {
changeParamValidator.validationChange(0, 0, 2, 2, Param.UNDEFINED);
Assert.fail();
} catch (ParamValidationException e) {
Assert.assertEquals(e.getError(), ParamValidationException.ERROR.SAME);
}
try {
changeParamValidator.validationChange(0, 1, 2, 2, Param.UNDEFINED);
Assert.fail();
} catch (ParamValidationException e) {
Assert.assertEquals(e.getError(), ParamValidationException.ERROR.NO_CHANGE_POSSIBLE);
}
try {
changeParamValidator.validationChange(0, -1, 2, 2, Param.UNDEFINED);
Assert.fail();
} catch (ParamValidationException e) {
Assert.assertEquals(e.getError(), ParamValidationException.ERROR.NO_CHANGE_POSSIBLE);
}
try {
changeParamValidator.validationChange(2, 4, 2, 1.1, Param.UNDEFINED);
Assert.fail();
} catch (ParamValidationException e) {
Assert.assertEquals(e.getError(), ParamValidationException.ERROR.TOO_HIGH);
}
try {
changeParamValidator.validationChange(4, 2, 1.5, 2, Param.UNDEFINED);
Assert.fail();
} catch (ParamValidationException e) {
Assert.assertEquals(e.getError(), ParamValidationException.ERROR.TOO_LOW);
}
changeParamValidator.validationChange(4, 2, 2, 2, Param.UNDEFINED);
changeParamValidator.validationChange(2, 4, 2, 2, Param.UNDEFINED);
changeParamValidator.validationChange(0, 1, 0, 0, Param.UNDEFINED);
changeParamValidator.validationChange(0, -1, 0, 0, Param.UNDEFINED);
changeParamValidator.validationChange(-1, 0, 0, 0, Param.UNDEFINED);
changeParamValidator.validationChange(1, 0, 0, 0, Param.UNDEFINED);
}
}

View file

@ -1,205 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.node.full;
// not converting this test because it is already ignored.
// Intro to jmockit can be found at http://jmockit.github.io/tutorial/Mocking.html
//@Ignore
/*
public class BlockParserTest {
// @Tested classes are instantiated automatically when needed in a test case,
// using injection where possible, see http://jmockit.github.io/tutorial/Mocking.html#tested
// To force instantiate earlier, use availableDuringSetup
@Tested(fullyInitialized = true, availableDuringSetup = true)
BlockParser blockParser;
@Tested(fullyInitialized = true, availableDuringSetup = true)
DaoStateService daoStateService;
// @Injectable are mocked resources used to for injecting into @Tested classes
// The naming of these resources doesn't matter, any resource that fits will be used for injection
// Used by daoStateService
@Injectable
PersistenceProtoResolver persistenceProtoResolver;
@Injectable
File storageDir;
@Injectable
String genesisTxId = "genesisTxId";
@Injectable
int genesisBlockHeight = 200;
// Used by fullNodeParser
@Injectable
RpcService rpcService;
@Tested(fullyInitialized = true, availableDuringSetup = true)
DaoStateService writeModel;
@Tested(fullyInitialized = true, availableDuringSetup = true)
TxParser txParser;
//FIXME
@Test
public void testIsBsqTx() {
// Setup a basic transaction with two inputs
int height = 200;
String hash = "abc123";
long time = new Date().getTime();
final List<TxInput> inputs = asList(new TxInput("tx1", 0, null),
new TxInput("tx1", 1, null));
final List<RawTxOutput> outputs = asList(new RawTxOutput(0, 101, "tx1", null, null, null, height));
RawTx rawTx = new RawTx("vo", height, hash, time,
ImmutableList.copyOf(inputs),
ImmutableList.copyOf(outputs));
// Return one spendable txoutputs with value, for three test cases
// 1) - null, 0 -> not BSQ transaction
// 2) - 100, null -> BSQ transaction
// 3) - 0, 100 -> BSQ transaction
new Expectations(daoStateService) {{
// Expectations can be recorded on mocked instances, either with specific matching arguments or catch all
// http://jmockit.github.io/tutorial/Mocking.html#results
// Results are returned in the order they're recorded, so in this case for the first call to
// getSpendableTxOutput("tx1", 0) the return value will be Optional.empty()
// for the second call the return is Optional.of(new TxOutput(0,... and so on
daoStateService.getUnspentTxOutput(new TxOutputKey("tx1", 0));
result = Optional.empty();
result = Optional.of(new RawTxOutput(0, 100, "txout1", null, null, null, height));
result = Optional.of(new RawTxOutput(0, 0, "txout1", null, null, null, height));
daoStateService.getUnspentTxOutput(new TxOutputKey("tx1", 1));
result = Optional.of(new RawTxOutput(0, 0, "txout2", null, null, null, height));
result = Optional.empty();
result = Optional.of(new RawTxOutput(0, 100, "txout2", null, null, null, height));
}};
String genesisTxId = "genesisTxId";
int blockHeight = 200;
String blockHash = "abc123";
Coin genesisTotalSupply = Coin.parseCoin("2.5");
// First time there is no BSQ value to spend so it's not a bsq transaction
assertFalse(txParser.findTx(rawTx, genesisTxId, blockHeight, genesisTotalSupply).isPresent());
// Second time there is BSQ in the first txout
assertTrue(txParser.findTx(rawTx, genesisTxId, blockHeight, genesisTotalSupply).isPresent());
// Third time there is BSQ in the second txout
assertTrue(txParser.findTx(rawTx, genesisTxId, blockHeight, genesisTotalSupply).isPresent());
}
@Test
public void testParseBlocks() {
// Setup blocks to test, starting before genesis
// Only the transactions related to bsq are relevant, no checks are done on correctness of blocks or other txs
// so hashes and most other data don't matter
long time = new Date().getTime();
int genesisHeight = 200;
int startHeight = 199;
int headHeight = 201;
Coin issuance = Coin.parseCoin("2.5");
RawTransaction genTx = new RawTransaction("gen block hash", 0, 0L, 0L, genesisTxId);
// Blockhashes
String bh199 = "blockhash199";
String bh200 = "blockhash200";
String bh201 = "blockhash201";
// Block 199
String cbId199 = "cbid199";
RawTransaction tx199 = new RawTransaction(bh199, 0, 0L, 0L, cbId199);
RawTx cbTx199 = new RawTx(cbId199, 199, bh199, time,
ImmutableList.copyOf(new ArrayList<TxInput>()),
ImmutableList.copyOf(asList(new RawTxOutput(0, 25, cbId199, null, null, null, 199))));
RawBlock block199 = new RawBlock(bh199, 10, 10, 199, 2, "root", asList(tx199), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", "previousBlockHash", bh200);
// Genesis Block
String cbId200 = "cbid200";
RawTransaction tx200 = new RawTransaction(bh200, 0, 0L, 0L, cbId200);
RawTx cbTx200 = new RawTx(cbId200, 200, bh200, time,
ImmutableList.copyOf(new ArrayList<TxInput>()),
ImmutableList.copyOf(asList(new RawTxOutput(0, 25, cbId200, null, null, null, 200))));
RawTx genesisTx = new RawTx(genesisTxId, 200, bh200, time,
ImmutableList.copyOf(asList(new TxInput("someoldtx", 0, null))),
ImmutableList.copyOf(asList(new RawTxOutput(0, issuance.getValue(), genesisTxId, null, null, null, 200))));
RawBlock block200 = new RawBlock(bh200, 10, 10, 200, 2, "root", asList(tx200, genTx), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh199, bh201);
// Block 201
// Make a bsq transaction
String cbId201 = "cbid201";
String bsqTx1Id = "bsqtx1";
RawTransaction tx201 = new RawTransaction(bh201, 0, 0L, 0L, cbId201);
RawTransaction txbsqtx1 = new RawTransaction(bh201, 0, 0L, 0L, bsqTx1Id);
long bsqTx1Value1 = Coin.parseCoin("2.4").getValue();
long bsqTx1Value2 = Coin.parseCoin("0.04").getValue();
RawTx cbTx201 = new RawTx(cbId201, 201, bh201, time,
ImmutableList.copyOf(new ArrayList<TxInput>()),
ImmutableList.copyOf(asList(new RawTxOutput(0, 25, cbId201, null, null, null, 201))));
RawTx bsqTx1 = new RawTx(bsqTx1Id, 201, bh201, time,
ImmutableList.copyOf(asList(new TxInput(genesisTxId, 0, null))),
ImmutableList.copyOf(asList(new RawTxOutput(0, bsqTx1Value1, bsqTx1Id, null, null, null, 201),
new RawTxOutput(1, bsqTx1Value2, bsqTx1Id, null, null, null, 201))));
RawBlock block201 = new RawBlock(bh201, 10, 10, 201, 2, "root", asList(tx201, txbsqtx1), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh200, "nextBlockHash");
// TODO update test with new API
/*
new Expectations(rpcService) {{
rpcService.requestBlock(199);
result = block199;
rpcService.requestBlock(200);
result = block200;
rpcService.requestBlock(201);
result = block201;
rpcService.requestTx(cbId199, 199);
result = cbTx199;
rpcService.requestTx(cbId200, genesisHeight);
result = cbTx200;
rpcService.requestTx(genesisTxId, genesisHeight);
result = genesisTx;
rpcService.requestTx(cbId201, 201);
result = cbTx201;
rpcService.requestTx(bsqTx1Id, 201);
result = bsqTx1;
}};
// Running parseBlocks to build the bsq blockchain
fullNodeParser.parseBlocks(startHeight, headHeight, block -> {
});
*/
// Verify that the genesis tx has been added to the bsq blockchain with the correct issuance amount
/* assertTrue(daoStateService.getGenesisTx().get() == genesisTx);
assertTrue(daoStateService.getGenesisTotalSupply().getValue() == issuance.getValue());
// And that other txs are not added
assertFalse(daoStateService.containsTx(cbId199));
assertFalse(daoStateService.containsTx(cbId200));
assertFalse(daoStateService.containsTx(cbId201));
// But bsq txs are added
assertTrue(daoStateService.containsTx(bsqTx1Id));
TxOutput bsqOut1 = daoStateService.getUnspentAndMatureTxOutput(bsqTx1Id, 0).get();
assertTrue(daoStateService.isUnspent(bsqOut1));
assertTrue(bsqOut1.getValue() == bsqTx1Value1);
TxOutput bsqOut2 = daoStateService.getUnspentAndMatureTxOutput(bsqTx1Id, 1).get();
assertTrue(daoStateService.isUnspent(bsqOut2));
assertTrue(bsqOut2.getValue() == bsqTx1Value2);
assertFalse(daoStateService.isTxOutputSpendable(genesisTxId, 0));
assertTrue(daoStateService.isTxOutputSpendable(bsqTx1Id, 0));
assertTrue(daoStateService.isTxOutputSpendable(bsqTx1Id, 1));
}
}
*/

View file

@ -1,140 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.node.full;
import bisq.core.dao.node.full.rpc.dto.RawDtoInput;
import bisq.core.dao.node.full.rpc.dto.DtoSignatureScript;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class RpcServiceTest {
private static final String SIGNATURE = "3045" +
"022100b6c2fa10587d6fed3a0eecfd098b160f69a850beca139fe03ef65bec4cba1c5b" +
"02204a833a16c22bbd32722243ea3270e672f646ee9406e8797e11093951e92efbd5";
private static final String SIGNATURE_1 = "3044" +
"02201f00d9a4aab1a3a239f1ad95a910092c0c55423480d609eaad4599cf7ecb7f48" +
"0220668b1a9cf5624b1c4ece6da3f64bc6021e509f588ae1006601acd8a9f83b3576";
private static final String SIGNATURE_2 = "3045" +
"022100982eca77a72a2bdba51b9231afd4521400bee1bb7830634eb26db2b0c621bc46" +
"022073d7325916e2b5ceb1d2e510a5161fd9115105a8dafa94068864624bb10d190e";
private static final String PUB_KEY =
"03dcca91c2ec7229f1b4f4c4f664c92d3303dddef8d38736f6a7f28de16f3ce416";
private static final String PUB_KEY_1 =
"0229713ad5c604c585128b3a5da6de20d78fc33bd3b595e9991f4c0e1fee99f845";
private static final String PUB_KEY_2 =
"0398ad45a74bf5a5c5a8ec31de6815d2e805a23e68c0f8001770e74bc4c17c5b31";
private static final String MULTISIG_REDEEM_SCRIPT_HEX =
"5221" + PUB_KEY_1 + "21" + PUB_KEY_2 + "52ae"; // OP_2 pub1 pub2 OP_2 OP_CHECKMULTISIG
private static final String P2WPKH_REDEEM_SCRIPT_HEX =
"0014" + "9bc809698674ec7c01d35d438e9d0de1aa87b6c8"; // 0 hash160
private static final String P2WSH_REDEEM_SCRIPT_HEX =
"0020" + "223d978073802f79e6ecdc7591e5dc1f0ea7030d6466f73c6b90391bc72e886f"; // 0 hash256
@Test
public void testExtractPubKeyAsHex_coinbase() {
checkExtractPubKeyAsHexReturnsNull(new RawDtoInput());
}
@Test
public void testExtractPubKeyAsHex_P2PK() {
var input = rawInput(SIGNATURE + "[ALL]");
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2PKH() {
var input = rawInput(SIGNATURE + "[ALL] " + PUB_KEY);
assertEquals(PUB_KEY, RpcService.extractPubKeyAsHex(input, true));
assertEquals(PUB_KEY, RpcService.extractPubKeyAsHex(input, false));
}
@Test
public void testExtractPubKeyAsHex_P2WPKH() {
var input = rawInput("", SIGNATURE + "01", PUB_KEY);
assertEquals(PUB_KEY, RpcService.extractPubKeyAsHex(input, true));
assertNull(RpcService.extractPubKeyAsHex(input, false));
}
@Test
public void testExtractPubKeyAsHex_P2SH_P2WPKH() {
var input = rawInput(P2WPKH_REDEEM_SCRIPT_HEX, SIGNATURE + "01", PUB_KEY);
assertEquals(PUB_KEY, RpcService.extractPubKeyAsHex(input, true));
assertNull(RpcService.extractPubKeyAsHex(input, false));
}
@Test
public void testExtractPubKeyAsHex_P2PKH_nonDefaultSighash() {
var input = rawInput(SIGNATURE + "[SINGLE|ANYONECANPAY] " + PUB_KEY);
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2WPKH_nonDefaultSighash() {
var input = rawInput("", SIGNATURE + "82", PUB_KEY);
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2SH_P2WPKH_nonDefaultSighash() {
var input = rawInput(P2WPKH_REDEEM_SCRIPT_HEX, SIGNATURE + "82", PUB_KEY);
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2SH_multisig() {
var input = rawInput("0 " + SIGNATURE_1 + "[ALL] " + SIGNATURE_2 + "[ALL] " + MULTISIG_REDEEM_SCRIPT_HEX);
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2SH_multisig_nonDefaultSighash() {
var input = rawInput("0 " + SIGNATURE_1 + "[ALL] " + SIGNATURE_2 + "[NONE] " + MULTISIG_REDEEM_SCRIPT_HEX);
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2WSH_multisig() {
var input = rawInput("", "", SIGNATURE_1 + "01", SIGNATURE_2 + "01", MULTISIG_REDEEM_SCRIPT_HEX);
checkExtractPubKeyAsHexReturnsNull(input);
}
@Test
public void testExtractPubKeyAsHex_P2SH_P2WSH_multisig() {
var input = rawInput(P2WSH_REDEEM_SCRIPT_HEX, "", SIGNATURE_1 + "01", SIGNATURE_2 + "01", MULTISIG_REDEEM_SCRIPT_HEX);
checkExtractPubKeyAsHexReturnsNull(input);
}
private static void checkExtractPubKeyAsHexReturnsNull(RawDtoInput input) {
assertNull(RpcService.extractPubKeyAsHex(input, true));
assertNull(RpcService.extractPubKeyAsHex(input, false));
}
private static RawDtoInput rawInput(String asm, String... txInWitness) {
var input = new RawDtoInput();
var scriptSig = new DtoSignatureScript();
scriptSig.setAsm(asm);
input.setScriptSig(scriptSig);
input.setTxInWitness(txInWitness.length > 0 ? List.of(txInWitness) : null);
return input;
}
}

View file

@ -1,234 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.node.full.rpc;
import bisq.core.dao.node.full.rpc.dto.RawDtoBlock;
import bisq.core.dao.node.full.rpc.dto.RawDtoTransaction;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.googlecode.jsonrpc4j.HttpException;
import com.googlecode.jsonrpc4j.JsonRpcClientException;
import com.googlecode.jsonrpc4j.RequestIDGenerator;
import kotlin.text.Charsets;
public class BitcoindClientTest {
private static final String TEST_BLOCK_HASH = "015f37a20d517645a11a6cdd316049f41bc77b4a4057b2dd092114b78147f42c";
private static final String TEST_BLOCK_VERBOSITY_0 = readFromResourcesUnPrettified("getblock-result-verbosity-0.txt");
private static final String TEST_BLOCK_VERBOSITY_1 = readFromResourcesUnPrettified("getblock-result-verbosity-1.json");
private static final String TEST_BLOCK_VERBOSITY_2 = readFromResourcesUnPrettified("getblock-result-verbosity-2.json");
private static final String TEST_NETWORK_INFO = readFromResourcesUnPrettified("getnetworkinfo-result.json");
private BitcoindClient client;
private int mockResponseCode = 200;
private boolean canConnect = true;
private ByteArrayInputStream mockResponse;
private ByteArrayInputStream mockErrorResponse;
private ByteArrayOutputStream mockOutputStream = new ByteArrayOutputStream();
@Before
public void setUp() throws Exception {
var mockURLStreamHandler = mock(MyURLStreamHandler.class);
var mockRequestIDGenerator = mock(RequestIDGenerator.class);
client = BitcoindClient.builder()
.rpcHost("127.0.0.1")
.rpcPort(18443)
.rpcUser("bisqdao")
.rpcPassword("bsq")
.urlStreamHandler(mockURLStreamHandler)
.requestIDGenerator(mockRequestIDGenerator)
.build();
when(mockURLStreamHandler.openConnection(any(), any())).then(inv -> {
var connection = mock(HttpURLConnection.class);
if (canConnect) {
when(connection.getOutputStream()).thenReturn(mockOutputStream);
if (mockResponseCode < 400) {
when(connection.getInputStream()).thenReturn(mockResponse);
} else {
when(connection.getInputStream()).thenThrow(IOException.class);
when(connection.getErrorStream()).thenReturn(mockErrorResponse);
}
} else {
doThrow(ConnectException.class).when(connection).connect();
}
return connection;
});
when(mockRequestIDGenerator.generateID()).thenReturn("987654321");
}
@Test
public void testGetBlockCount() throws Exception {
var expectedRequest = toJson("{'id':'987654321','jsonrpc':'2.0','method':'getblockcount','params':[]}");
mockResponse = toJsonIS("{'result':'150','error':null,'id':'123456789'}");
assertEquals((Integer) 150, client.getBlockCount());
assertEquals(expectedRequest, mockOutputStream.toString(UTF_8));
}
@Test(expected = ConnectException.class)
public void testGetBlockCount_noConnection() throws Exception {
canConnect = false;
client.getBlockCount();
}
@Test(expected = HttpException.class)
public void testGetBlockCount_wrongCredentials() throws Exception {
mockResponseCode = 401;
// mockResponseCustomHeaders.put("WWW-Authenticate", "[Basic realm=\"jsonrpc\"]");
client.getBlockCount();
}
@Test
public void testGetBlockHash() throws Exception {
var expectedRequest = toJson("{'id':'987654321','jsonrpc':'2.0','method':'getblockhash','params':[139]}");
mockResponse = toJsonIS("{'result':'" + TEST_BLOCK_HASH + "','error':null,'id':'123456789'}");
assertEquals(TEST_BLOCK_HASH, client.getBlockHash(139));
assertEquals(expectedRequest, mockOutputStream.toString(UTF_8));
}
@Test
public void testGetBestBlockHash() throws Exception {
var expectedRequest = toJson("{'id':'987654321','jsonrpc':'2.0','method':'getbestblockhash','params':[]}");
mockResponse = toJsonIS("{'result':'" + TEST_BLOCK_HASH + "','error':null,'id':'123456789'}");
assertEquals(TEST_BLOCK_HASH, client.getBestBlockHash());
assertEquals(expectedRequest, mockOutputStream.toString(UTF_8));
}
@Test(expected = JsonRpcClientException.class)
public void testGetBlockHash_heightOutOfRange() throws Exception {
mockResponseCode = 500;
mockErrorResponse = toJsonIS("{'result':null,'error':{'code':-8,'message':'Block height out of range'},'id':'123456789'}");
client.getBlockHash(151);
}
@Test
public void testGetBlock_verbosity_0() throws Exception {
doTestGetBlock(0, "\"" + TEST_BLOCK_VERBOSITY_0 + "\"");
}
@Test
public void testGetBlock_verbosity_1() throws Exception {
doTestGetBlock(1, TEST_BLOCK_VERBOSITY_1);
}
@Test
public void testGetBlock_verbosity_2() throws Exception {
doTestGetBlock(2, TEST_BLOCK_VERBOSITY_2);
}
private void doTestGetBlock(int verbosity, String blockJson) throws Exception {
var expectedRequest = toJson("{'id':'987654321','jsonrpc':'2.0','method':'getblock','params':['"
+ TEST_BLOCK_HASH + "'," + verbosity + "]}");
mockResponse = toJsonIS("{'result':" + blockJson + ",'error':null,'id':'123456789'}");
var block = client.getBlock(TEST_BLOCK_HASH, verbosity);
var blockJsonRoundTripped = new ObjectMapper().writeValueAsString(block);
assertEquals(verbosity == 0, block instanceof RawDtoBlock.Summarized);
assertEquals(verbosity == 1, block.getTx() != null &&
block.getTx().stream().allMatch(tx -> tx instanceof RawDtoTransaction.Summarized));
assertEquals(blockJson, blockJsonRoundTripped);
assertEquals(expectedRequest, mockOutputStream.toString(UTF_8));
}
@Test(expected = JsonRpcClientException.class)
public void testGetBlock_blockNotFound() throws Exception {
mockResponseCode = 500;
mockErrorResponse = toJsonIS("{'result':null,'error':{'code':-5,'message':'Block not found'},'id':'123456789'}");
client.getBlock(TEST_BLOCK_HASH.replace('f', 'e'), 2);
}
@Test(expected = JsonRpcClientException.class)
public void testGetBlock_malformedHash() throws Exception {
mockResponseCode = 500;
mockErrorResponse = toJsonIS("{'result':null,'error':{'code':-8,'message':'blockhash must be of length 64 " +
"(not 3, for \\'foo\\')'},'id':'123456789'}");
client.getBlock("foo", 2);
}
@Test
public void testGetNetworkInfo() throws Exception {
var expectedRequest = toJson("{'id':'987654321','jsonrpc':'2.0','method':'getnetworkinfo','params':[]}");
mockResponse = toJsonIS("{'result':" + TEST_NETWORK_INFO + ",'error':null,'id':'123456789'}");
var networkInfo = client.getNetworkInfo();
var networkInfoRoundTripped = new ObjectMapper().writeValueAsString(networkInfo);
var expectedNetworkInfoStr = TEST_NETWORK_INFO.replace("MY_CUSTOM_SERVICE", "UNKNOWN");
assertEquals(expectedNetworkInfoStr, networkInfoRoundTripped);
assertEquals(expectedRequest, mockOutputStream.toString(UTF_8));
}
private static String toJson(String json) {
return json.replace("'", "\"").replace("\\\"", "'");
}
private static ByteArrayInputStream toJsonIS(String json) {
return new ByteArrayInputStream(toJson(json).getBytes(UTF_8));
}
private static String readFromResourcesUnPrettified(String resourceName) {
try {
var path = Paths.get(BitcoindClientTest.class.getResource(resourceName).toURI());
return new String(Files.readAllBytes(path), Charsets.UTF_8).replaceAll("(\\s+\\B|\\B\\s+|\\v)", "");
} catch (Exception e) {
return "";
}
}
private static abstract class MyURLStreamHandler extends URLStreamHandler {
@Override
public abstract URLConnection openConnection(URL u, Proxy p);
}
}

View file

@ -1,183 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.node.full.rpc;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class BitcoindDaemonTest {
private BitcoindDaemon daemon;
private int acceptAnotherCount;
private CountDownLatch errorHandlerLatch = new CountDownLatch(1);
private Consumer<Throwable> errorHandler = mock(ThrowableConsumer.class);
private BitcoindDaemon.BlockListener blockListener = mock(BitcoindDaemon.BlockListener.class);
private Socket socket = mock(Socket.class);
private volatile boolean socketClosed;
@Before
public void setUp() throws Exception {
var serverSocket = mock(ServerSocket.class);
when(serverSocket.accept()).then(invocation -> waitToAccept(() -> {
if (socketClosed) {
throw new SocketException();
}
return socket;
}));
doAnswer((VoidAnswer) invocation -> {
socketClosed = true;
acceptAnother(1);
}).when(serverSocket).close();
doAnswer((VoidAnswer) invocation -> errorHandlerLatch.countDown()).when(errorHandler).accept(any());
daemon = new BitcoindDaemon(serverSocket, errorHandler);
daemon.setBlockListener(blockListener);
}
@After
public void tearDown() {
daemon.shutdown();
}
@Test
public void testNoBlocksMissedDuringFloodOfIncomingBlocks() throws Exception {
var latch = new CountDownLatch(1); // to block all the daemon worker threads until shutdown, as if stuck
doAnswer((VoidAnswer) invocation -> latch.await()).when(blockListener).blockDetected(any());
when(socket.getInputStream()).then(invocation -> new ByteArrayInputStream("foo".getBytes()));
acceptAnother(50);
waitUntilAllAccepted();
// Unblock all the daemon worker threads and shut down.
latch.countDown();
daemon.shutdown();
verify(blockListener, times(50)).blockDetected("foo");
}
@Test
public void testBlockHashIsTrimmed() throws Exception {
when(socket.getInputStream()).then(invocation -> new ByteArrayInputStream("\r\nbar \n".getBytes()));
acceptAnother(1);
waitUntilAllAccepted();
daemon.shutdown();
verify(blockListener).blockDetected("bar");
}
@Test
public void testBrokenSocketRead() throws Exception {
when(socket.getInputStream()).thenThrow(IOException.class);
acceptAnother(1);
errorHandlerLatch.await(5, TimeUnit.SECONDS);
verify(errorHandler).accept(argThat(t -> t instanceof NotificationHandlerException &&
t.getCause() instanceof IOException));
}
@Test
public void testRuntimeExceptionInBlockListener() throws Exception {
daemon.setBlockListener(blockHash -> {
throw new IndexOutOfBoundsException();
});
when(socket.getInputStream()).then(invocation -> new ByteArrayInputStream("foo".getBytes()));
acceptAnother(1);
errorHandlerLatch.await(5, TimeUnit.SECONDS);
verify(errorHandler).accept(argThat(t -> t instanceof NotificationHandlerException &&
t.getCause() instanceof IndexOutOfBoundsException));
}
@Test
public void testErrorInBlockListener() throws Exception {
synchronized (this) {
daemon.setBlockListener(blockHash -> {
throw new Error();
});
when(socket.getInputStream()).then(invocation -> new ByteArrayInputStream("foo".getBytes()));
acceptAnother(1);
}
errorHandlerLatch.await(5, TimeUnit.SECONDS);
verify(errorHandler).accept(any(Error.class));
}
@Test(expected = NotificationHandlerException.class)
public void testUnknownHost() throws Exception {
new BitcoindDaemon("[", -1, errorHandler).shutdown();
}
private synchronized void acceptAnother(int n) {
acceptAnotherCount += n;
notifyAll();
}
private synchronized <V> V waitToAccept(Callable<V> onAccept) throws Exception {
while (acceptAnotherCount == 0) {
wait();
}
var result = onAccept.call();
acceptAnotherCount--;
notifyAll();
return result;
}
private synchronized void waitUntilAllAccepted() throws InterruptedException {
while (acceptAnotherCount > 0) {
wait();
}
notifyAll();
}
private interface ThrowableConsumer extends Consumer<Throwable> {
}
private interface VoidAnswer extends Answer<Void> {
void voidAnswer(InvocationOnMock invocation) throws Throwable;
@Override
default Void answer(InvocationOnMock invocation) throws Throwable {
voidAnswer(invocation);
return null;
}
}
}

View file

@ -1,200 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.node.parser;
import bisq.core.dao.node.full.RawTx;
import bisq.core.dao.node.full.RawTxOutput;
import bisq.core.dao.node.parser.exceptions.InvalidGenesisTxException;
import bisq.core.dao.state.model.blockchain.TxInput;
import bisq.core.dao.state.model.blockchain.TxOutputType;
import bisq.core.dao.state.model.blockchain.TxType;
import org.bitcoinj.core.Coin;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class GenesisTxParserTest {
@Test
public void testIsGenesis() {
// fixme(chirhonul): Assert.assertEquals(2, 3);
int blockHeight = 200;
String blockHash = "abc123";
Coin genesisTotalSupply = Coin.parseCoin("2.5");
long time = new Date().getTime();
final List<TxInput> inputs = Arrays.asList(
new TxInput("tx0", 0, null),
new TxInput("tx1", 1, null)
);
RawTxOutput output = new RawTxOutput(
0,
genesisTotalSupply.value,
null,
null,
null,
null,
blockHeight
);
RawTx rawTx = new RawTx(
"tx2",
blockHeight,
blockHash,
time,
ImmutableList.copyOf(inputs),
ImmutableList.copyOf(Arrays.asList(output))
);
String genesisTxId = "genesisTxId";
int genesisBlockHeight = 150;
// With mismatch in block height and tx id, we should not get genesis tx back.
boolean result = GenesisTxParser.isGenesis(rawTx, genesisTxId, genesisBlockHeight);
boolean want = false;
Assert.assertEquals(want, result);
// With correct block height but mismatch in tx id, we should still not get genesis tx back.
blockHeight = 150;
rawTx = new RawTx(
"tx2",
blockHeight,
blockHash,
time,
ImmutableList.copyOf(inputs),
ImmutableList.copyOf(Arrays.asList(output))
);
result = GenesisTxParser.isGenesis(rawTx, genesisTxId, genesisBlockHeight);
want = false;
Assert.assertEquals(want, result);
}
@Test
public void testGetGenesisTempTx() {
int blockHeight = 200;
String blockHash = "abc123";
Coin genesisTotalSupply = Coin.parseCoin("2.5");
long time = new Date().getTime();
final List<TxInput> inputs = Arrays.asList(
new TxInput("tx0", 0, null),
new TxInput("tx1", 1, null)
);
RawTxOutput output = new RawTxOutput(
0,
genesisTotalSupply.value,
null,
null,
null,
null,
blockHeight
);
String genesisTxId = "genesisTxId";
// With correct tx id and block height, we should find our genesis tx with correct tx and output type.
RawTx rawTx = new RawTx(
genesisTxId,
blockHeight,
blockHash,
time,
ImmutableList.copyOf(inputs),
ImmutableList.copyOf(Arrays.asList(output))
);
TempTx resultTempTx = GenesisTxParser.getGenesisTempTx(rawTx, genesisTotalSupply);
TempTx tempTx = TempTx.fromRawTx(rawTx);
tempTx.setTxType(TxType.GENESIS);
for (int i = 0; i < tempTx.getTempTxOutputs().size(); ++i) {
tempTx.getTempTxOutputs().get(i).setTxOutputType(TxOutputType.GENESIS_OUTPUT);
}
TempTx wantTempTx = tempTx;
Assert.assertEquals(wantTempTx, resultTempTx);
// With correct tx id and block height, but too low sum of outputs (lower than genesisTotalSupply), we
// should see an exception raised.
output = new RawTxOutput(
0,
genesisTotalSupply.value - 1,
null,
null,
null,
null,
blockHeight
);
rawTx = new RawTx(
genesisTxId,
blockHeight,
blockHash,
time,
ImmutableList.copyOf(inputs),
ImmutableList.copyOf(Arrays.asList(output))
);
try {
GenesisTxParser.getGenesisTempTx(rawTx, genesisTotalSupply);
Assert.fail("Expected an InvalidGenesisTxException to be thrown when outputs are too low");
} catch (InvalidGenesisTxException igtxe) {
String wantMessage = "Genesis tx is invalid; not using all available inputs. Remaining input value is 1 sat";
Assert.assertTrue("Unexpected exception, want message starting with " +
"'" + wantMessage + "', got '" + igtxe.getMessage() + "'", igtxe.getMessage().startsWith(wantMessage));
}
// With correct tx id and block height, but too high sum of outputs (higher than from genesisTotalSupply), we
// should see an exception raised.
RawTxOutput output1 = new RawTxOutput(
0,
genesisTotalSupply.value - 2,
null,
null,
null,
null,
blockHeight
);
RawTxOutput output2 = new RawTxOutput(
0,
3,
null,
null,
null,
null,
blockHeight
);
rawTx = new RawTx(
genesisTxId,
blockHeight,
blockHash,
time,
ImmutableList.copyOf(inputs),
ImmutableList.copyOf(Arrays.asList(output1, output2))
);
try {
GenesisTxParser.getGenesisTempTx(rawTx, genesisTotalSupply);
Assert.fail("Expected an InvalidGenesisTxException to be thrown when outputs are too high");
} catch (InvalidGenesisTxException igtxe) {
String wantMessage = "Genesis tx is invalid; using more than available inputs. Remaining input value is 2 sat";
Assert.assertTrue("Unexpected exception, want message starting with " +
"'" + wantMessage + "', got '" + igtxe.getMessage() + "'", igtxe.getMessage().startsWith(wantMessage));
}
}
}

View file

@ -1,72 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.state;
import bisq.core.dao.state.model.DaoState;
import bisq.core.dao.state.model.blockchain.Block;
import bisq.core.util.coin.BsqFormatter;
import org.bitcoinj.core.Coin;
import org.junit.Assert;
import org.junit.Test;
public class DaoStateServiceTest {
@Test
public void testIsBlockHashKnown() {
DaoStateService stateService = new DaoStateService(
new DaoState(),
new GenesisTxInfo("fakegenesistxid", 100, Coin.parseCoin("2.5").value),
new BsqFormatter());
Assert.assertEquals(
"Unknown block should not exist.",
false,
stateService.isBlockHashKnown("fakeblockhash0")
);
Block block = new Block(0, 1534800000, "fakeblockhash0", null);
stateService.onNewBlockHeight(0);
stateService.onNewBlockWithEmptyTxs(block);
Assert.assertEquals(
"Block has to be genesis block to get added.",
false,
stateService.isBlockHashKnown("fakeblockhash0")
);
Assert.assertEquals(
"Block that was never added should still not exist.",
false,
stateService.isBlockHashKnown("fakeblockhash1")
);
block = new Block(1, 1534800001, "fakeblockhash1", null);
stateService.onNewBlockHeight(1);
stateService.onNewBlockWithEmptyTxs(block);
block = new Block(2, 1534800002, "fakeblockhash2", null);
stateService.onNewBlockHeight(2);
stateService.onNewBlockWithEmptyTxs(block);
block = new Block(3, 1534800003, "fakeblockhash3", null);
stateService.onNewBlockHeight(3);
stateService.onNewBlockWithEmptyTxs(block);
Assert.assertEquals(
"Block that was never added should still not exist after adding more blocks.",
false,
stateService.isBlockHashKnown("fakeblockhash4")
);
}
}

View file

@ -1,73 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.state;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
import bisq.core.dao.state.storage.DaoStateStorageService;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class DaoStateSnapshotServiceTest {
private DaoStateSnapshotService daoStateSnapshotService;
@Before
public void setup() {
daoStateSnapshotService = new DaoStateSnapshotService(mock(DaoStateService.class),
mock(GenesisTxInfo.class),
mock(DaoStateStorageService.class),
mock(DaoStateMonitoringService.class),
null);
}
@Test
public void testGetSnapshotHeight() {
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 0, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 100, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 102, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 119, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 120, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 121, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 130, 10));
assertEquals(120, daoStateSnapshotService.getSnapshotHeight(102, 139, 10));
assertEquals(130, daoStateSnapshotService.getSnapshotHeight(102, 140, 10));
assertEquals(130, daoStateSnapshotService.getSnapshotHeight(102, 141, 10));
assertEquals(990, daoStateSnapshotService.getSnapshotHeight(102, 1000, 10));
}
@Test
public void testSnapshotHeight() {
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 0, 10));
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 80, 10));
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 90, 10));
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 100, 10));
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 119, 10));
assertTrue(daoStateSnapshotService.isSnapshotHeight(102, 120, 10));
assertTrue(daoStateSnapshotService.isSnapshotHeight(102, 130, 10));
assertTrue(daoStateSnapshotService.isSnapshotHeight(102, 140, 10));
assertTrue(daoStateSnapshotService.isSnapshotHeight(102, 200, 10));
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 201, 10));
assertFalse(daoStateSnapshotService.isSnapshotHeight(102, 199, 10));
}
}

View file

@ -1,107 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.voting.voteresult;
import bisq.core.dao.governance.merit.MeritConsensus;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.junit.Assert.assertEquals;
@Slf4j
public class VoteResultConsensusTest {
@Before
public void setup() {
}
@Rule
public final ExpectedException exception = ExpectedException.none();
@Test
public void testGetWeightedMeritAmount() {
int currentChainHeight;
int blocksPerYear = 50_000; // 144*365=51264;
currentChainHeight = 1_000_000;
assertEquals("fresh issuance", 100000, MeritConsensus.getWeightedMeritAmount(100_000, 1_000_000,
currentChainHeight, blocksPerYear));
assertEquals("0.5 year old issuance", 75000, MeritConsensus.getWeightedMeritAmount(100_000, 975_000,
currentChainHeight, blocksPerYear));
assertEquals("1 year old issuance", 50000, MeritConsensus.getWeightedMeritAmount(100_000, 950_000,
currentChainHeight, blocksPerYear));
assertEquals("1.5 year old issuance", 25000, MeritConsensus.getWeightedMeritAmount(100_000, 925_000,
currentChainHeight, blocksPerYear));
assertEquals("2 year old issuance", 0, MeritConsensus.getWeightedMeritAmount(100_000, 900_000,
currentChainHeight, blocksPerYear));
assertEquals("3 year old issuance", 0, MeritConsensus.getWeightedMeritAmount(100_000, 850_000,
currentChainHeight, blocksPerYear));
assertEquals("1 block old issuance", 99999, MeritConsensus.getWeightedMeritAmount(100_000, 999_999,
currentChainHeight, blocksPerYear));
assertEquals("2 block old issuance", 99998, MeritConsensus.getWeightedMeritAmount(100_000, 999_998,
currentChainHeight, blocksPerYear));
assertEquals("10 blocks old issuance", 99990, MeritConsensus.getWeightedMeritAmount(100_000, 999_990,
currentChainHeight, blocksPerYear));
assertEquals("100 blocks old issuance", 99900, MeritConsensus.getWeightedMeritAmount(100_000, 999_900,
currentChainHeight, blocksPerYear));
assertEquals("99_999 blocks old issuance", 1, MeritConsensus.getWeightedMeritAmount(100_000, 900_001,
currentChainHeight, blocksPerYear));
assertEquals("99_990 blocks old issuance", 10, MeritConsensus.getWeightedMeritAmount(100_000, 900_010,
currentChainHeight, blocksPerYear));
assertEquals("100_001 blocks old issuance", 0, MeritConsensus.getWeightedMeritAmount(100_000, 899_999,
currentChainHeight, blocksPerYear));
assertEquals("1_000_000 blocks old issuance", 0, MeritConsensus.getWeightedMeritAmount(100_000, 0,
currentChainHeight, blocksPerYear));
}
@Test
public void testInvalidChainHeight() {
exception.expect(IllegalArgumentException.class);
MeritConsensus.getWeightedMeritAmount(100_000, 2_000_000, 1_000_000, 1_000_000);
}
@Test
public void testInvalidIssuanceHeight() {
exception.expect(IllegalArgumentException.class);
MeritConsensus.getWeightedMeritAmount(100_000, -1, 1_000_000, 1_000_000);
}
@Test
public void testInvalidAmount() {
exception.expect(IllegalArgumentException.class);
MeritConsensus.getWeightedMeritAmount(-100_000, 1, 1_000_000, 1_000_000);
}
@Test
public void testInvalidCurrentChainHeight() {
exception.expect(IllegalArgumentException.class);
MeritConsensus.getWeightedMeritAmount(100_000, 1, -1, 1_000_000);
}
@Test
public void testInvalidBlockPerYear() {
exception.expect(IllegalArgumentException.class);
MeritConsensus.getWeightedMeritAmount(100_000, 1, 11, -1);
}
}

View file

@ -64,32 +64,12 @@ public class CurrencyUtilTest {
public void testFindAsset() {
MockAssetRegistry assetRegistry = new MockAssetRegistry();
// test if code is matching
boolean daoTradingActivated = false;
// Test if BSQ on mainnet is failing
Assert.assertFalse(CurrencyUtil.findAsset(assetRegistry, "BSQ",
BaseCurrencyNetwork.XMR_MAINNET, daoTradingActivated).isPresent());
// on testnet/regtest it is allowed
assertEquals(CurrencyUtil.findAsset(assetRegistry, "BSQ",
BaseCurrencyNetwork.XMR_TESTNET, daoTradingActivated).get().getTickerSymbol(), "BSQ");
daoTradingActivated = true;
// With daoTradingActivated we can request BSQ
assertEquals(CurrencyUtil.findAsset(assetRegistry, "BSQ",
BaseCurrencyNetwork.XMR_MAINNET, daoTradingActivated).get().getTickerSymbol(), "BSQ");
// Test if not matching ticker is failing
Assert.assertFalse(CurrencyUtil.findAsset(assetRegistry, "BSQ1",
BaseCurrencyNetwork.XMR_MAINNET, daoTradingActivated).isPresent());
// Add a mock coin which has no mainnet version, needs to fail if we are on mainnet
MockTestnetCoin.Testnet mockTestnetCoin = new MockTestnetCoin.Testnet();
try {
assetRegistry.addAsset(mockTestnetCoin);
CurrencyUtil.findAsset(assetRegistry, "MOCK_COIN",
BaseCurrencyNetwork.XMR_MAINNET, daoTradingActivated);
BaseCurrencyNetwork.XMR_MAINNET);
Assert.fail("Expected an IllegalArgumentException");
} catch (IllegalArgumentException e) {
String wantMessage = "We are on mainnet and we could not find an asset with network type mainnet";
@ -99,35 +79,22 @@ public class CurrencyUtilTest {
// For testnet its ok
assertEquals(CurrencyUtil.findAsset(assetRegistry, "MOCK_COIN",
BaseCurrencyNetwork.XMR_TESTNET, daoTradingActivated).get().getTickerSymbol(), "MOCK_COIN");
BaseCurrencyNetwork.XMR_TESTNET).get().getTickerSymbol(), "MOCK_COIN");
assertEquals(Coin.Network.TESTNET, mockTestnetCoin.getNetwork());
// For regtest its still found
assertEquals(CurrencyUtil.findAsset(assetRegistry, "MOCK_COIN",
BaseCurrencyNetwork.XMR_STAGENET, daoTradingActivated).get().getTickerSymbol(), "MOCK_COIN");
BaseCurrencyNetwork.XMR_STAGENET).get().getTickerSymbol(), "MOCK_COIN");
// We test if we are not on mainnet to get the mainnet coin
Coin ether = new Ether();
assertEquals(CurrencyUtil.findAsset(assetRegistry, "ETH",
BaseCurrencyNetwork.XMR_TESTNET, daoTradingActivated).get().getTickerSymbol(), "ETH");
BaseCurrencyNetwork.XMR_TESTNET).get().getTickerSymbol(), "ETH");
assertEquals(CurrencyUtil.findAsset(assetRegistry, "ETH",
BaseCurrencyNetwork.XMR_STAGENET, daoTradingActivated).get().getTickerSymbol(), "ETH");
BaseCurrencyNetwork.XMR_STAGENET).get().getTickerSymbol(), "ETH");
assertEquals(Coin.Network.MAINNET, ether.getNetwork());
// We test if network matches exactly if there are distinct network types defined like with BSQ
Coin bsq = (Coin) CurrencyUtil.findAsset(assetRegistry, "BSQ", BaseCurrencyNetwork.XMR_MAINNET, daoTradingActivated).get();
assertEquals("BSQ", bsq.getTickerSymbol());
assertEquals(Coin.Network.MAINNET, bsq.getNetwork());
bsq = (Coin) CurrencyUtil.findAsset(assetRegistry, "BSQ", BaseCurrencyNetwork.XMR_TESTNET, daoTradingActivated).get();
assertEquals("BSQ", bsq.getTickerSymbol());
assertEquals(Coin.Network.TESTNET, bsq.getNetwork());
bsq = (Coin) CurrencyUtil.findAsset(assetRegistry, "BSQ", BaseCurrencyNetwork.XMR_STAGENET, daoTradingActivated).get();
assertEquals("BSQ", bsq.getTickerSymbol());
assertEquals(Coin.Network.STAGENET, bsq.getNetwork());
}
}
@Test
public void testGetNameAndCodeOfRemovedAsset() {

View file

@ -59,7 +59,6 @@ public class OfferMaker {
0L,
0L,
0L,
false,
0L,
0L,
0L,

View file

@ -60,7 +60,6 @@ public class OpenOfferManagerTest {
null,
null,
null,
null,
offerBookService,
null,
null,
@ -70,8 +69,6 @@ public class OpenOfferManagerTest {
null,
null,
null,
null,
null,
persistenceManager,
signedOfferPersistenceManager);
@ -109,7 +106,6 @@ public class OpenOfferManagerTest {
null,
null,
null,
null,
offerBookService,
null,
null,
@ -119,8 +115,6 @@ public class OpenOfferManagerTest {
null,
null,
null,
null,
null,
persistenceManager,
signedOfferPersistenceManager);
@ -143,6 +137,7 @@ public class OpenOfferManagerTest {
when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class));
final OpenOfferManager manager = new OpenOfferManager(coreContext,
null,
null,
@ -151,7 +146,6 @@ public class OpenOfferManagerTest {
null,
null,
null,
null,
offerBookService,
null,
null,
@ -161,8 +155,6 @@ public class OpenOfferManagerTest {
null,
null,
null,
null,
null,
persistenceManager,
signedOfferPersistenceManager);

View file

@ -17,9 +17,6 @@
package bisq.core.payment;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.state.DaoStateService;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@ -28,23 +25,5 @@ import static org.mockito.Mockito.mock;
public class TradeLimitsTest {
@Test
public void testGetFirstMonthRiskBasedTradeLimit() {
TradeLimits tradeLimits = new TradeLimits(mock(DaoStateService.class), mock(PeriodService.class));
long expected, result;
expected = 0;
result = tradeLimits.getFirstMonthRiskBasedTradeLimit(0, 1);
assertEquals(expected, result);
expected = 25000000;
result = tradeLimits.getFirstMonthRiskBasedTradeLimit(100000000, 1);
assertEquals(expected, result);
expected = 3130000; //0.03125 -> 0.0313 -> 0.0313
result = tradeLimits.getFirstMonthRiskBasedTradeLimit(100000000, 8);
assertEquals(expected, result);
expected = 6250000;
result = tradeLimits.getFirstMonthRiskBasedTradeLimit(200000000, 8);
assertEquals(expected, result);
}
}

View file

@ -17,11 +17,7 @@
package bisq.core.provider.mempool;
import bisq.core.dao.governance.param.Param;
import bisq.core.dao.state.DaoStateService;
import bisq.core.util.ParsingUtils;
import bisq.core.util.coin.BsqFormatter;
import com.google.gson.Gson;
import org.apache.commons.io.IOUtils;
@ -72,85 +68,11 @@ public class TxValidatorTest {
@Test
public void testMakerTx() throws InterruptedException {
String mempoolData, offerData;
// paid the correct amount of BSQ fees
offerData = "msimscqb,0636bafb14890edfb95465e66e2b1e15915f7fb595f9b653b9129c15ef4c1c4b,1000000,10,0,662390";
mempoolData = "{\"txid\":\"0636bafb14890edfb95465e66e2b1e15915f7fb595f9b653b9129c15ef4c1c4b\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":7899}},{\"vout\":2,\"prevout\":{\"value\":54877439}}],\"vout\":[{\"scriptpubkey_address\":\"1FCUu7hqKCSsGhVJaLbGEoCWdZRJRNqq8w\",\"value\":7889},{\"scriptpubkey_address\":\"bc1qkj5l4wxl00ufdx6ygcnrck9fz5u927gkwqcgey\",\"value\":1600000},{\"scriptpubkey_address\":\"bc1qkw4a8u9l5w9fhdh3ue9v7e7celk4jyudzg5gk5\",\"value\":53276799}],\"size\":405,\"weight\":1287,\"fee\":650,\"status\":{\"confirmed\":true,\"block_height\":663140}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// UNDERPAID expected 1.01 BSQ, actual fee paid 0.80 BSQ (USED 8.00 RATE INSTEAD OF 10.06 RATE)
// PASS due to leniency rule of accepting old DAO rate parameters: https://github.com/bisq-network/bisq/issues/5329#issuecomment-803223859
offerData = "48067552,3b6009da764b71d79a4df8e2d8960b6919cae2e9bdccd5ef281e261fa9cd31b3,10000000,80,0,667656";
mempoolData = "{\"txid\":\"3b6009da764b71d79a4df8e2d8960b6919cae2e9bdccd5ef281e261fa9cd31b3\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":9717}},{\"vout\":0,\"prevout\":{\"value\":4434912}},{\"vout\":2,\"prevout\":{\"value\":12809932}}],\"vout\":[{\"scriptpubkey_address\":\"1Nzqa4J7ck5bgz7QNXKtcjZExAvReozFo4\",\"value\":9637},{\"scriptpubkey_address\":\"bc1qhmmulf5prreqhccqy2wqpxxn6dcye7ame9dd57\",\"value\":11500000},{\"scriptpubkey_address\":\"bc1qx6hg8km2jdjc5ukhuedmkseu9wlsjtd8zeajpj\",\"value\":5721894}],\"size\":553,\"weight\":1879,\"fee\":23030,\"status\":{\"confirmed\":true,\"block_height\":667660}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// UNDERPAID Expected fee: 0.61 BSQ, actual fee paid: 0.35 BSQ (USED 5.75 RATE INSTEAD OF 10.06 RATE)
// PASS due to leniency rule of accepting old DAO rate parameters: https://github.com/bisq-network/bisq/issues/5329#issuecomment-803223859
offerData = "am7DzIv,4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189,6100000,35,0,668195";
mempoolData = "{\"txid\":\"4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":23893}},{\"vout\":1,\"prevout\":{\"value\":1440000}},{\"vout\":2,\"prevout\":{\"value\":16390881}}],\"vout\":[{\"scriptpubkey_address\":\"1Kmrzq3WGCQsZw5kroEphuk1KgsEr65yB7\",\"value\":23858},{\"scriptpubkey_address\":\"bc1qyw5qql9m7rkse9mhcun225nrjpwycszsa5dpjg\",\"value\":7015000},{\"scriptpubkey_address\":\"bc1q90y3p6mg0pe3rvvzfeudq4mfxafgpc9rulruff\",\"value\":10774186}],\"size\":554,\"weight\":1559,\"fee\":41730,\"status\":{\"confirmed\":true,\"block_height\":668198}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// UNDERPAID expected 0.11 BSQ, actual fee paid 0.08 BSQ (USED 5.75 RATE INSTEAD OF 7.53)
// PASS due to leniency rule of accepting old DAO rate parameters: https://github.com/bisq-network/bisq/issues/5329#issuecomment-803223859
offerData = "F1dzaFNQ,f72e263947c9dee6fbe7093fc85be34a149ef5bcfdd49b59b9cc3322fea8967b,1440000,8,0,670822, bsq paid too little";
mempoolData = "{\"txid\":\"f72e263947c9dee6fbe7093fc85be34a149ef5bcfdd49b59b9cc3322fea8967b\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":15163}},{\"vout\":2,\"prevout\":{\"value\":6100000}}],\"vout\":[{\"scriptpubkey_address\":\"1MEsc2m4MSomNJWSr1p6fhnUQMyA3DRGrN\",\"value\":15155},{\"scriptpubkey_address\":\"bc1qztgwe9ry9a9puchjuscqdnv4v9lsm2ut0jtfec\",\"value\":2040000},{\"scriptpubkey_address\":\"bc1q0nstwxc0vqkj4x000xt328mfjapvlsd56nn70h\",\"value\":4048308}],\"size\":406,\"weight\":1291,\"fee\":11700,\"status\":{\"confirmed\":true,\"block_height\":670823}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
}
@Test
public void testTakerTx() throws InterruptedException {
String mempoolData, offerData;
// The fee was more than what we expected: Expected BTC fee: 5000 sats , actual fee paid: 6000 sats
offerData = "00072328,3524364062c96ba0280621309e8b539d152154422294c2cf263a965dcde9a8ca,1000000,6000,1,614672";
mempoolData = "{\"txid\":\"3524364062c96ba0280621309e8b539d152154422294c2cf263a965dcde9a8ca\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":1,\"prevout\":{\"value\":2971000}}],\"vout\":[{\"scriptpubkey_address\":\"3A8Zc1XioE2HRzYfbb5P8iemCS72M6vRJV\",\"value\":6000},{\"scriptpubkey_address\":\"1Hxu2X9Nr2fT3qEk9yjhiF54TJEz1Cxjoa\",\"value\":1607600},{\"scriptpubkey_address\":\"16VP6nHDDkmCMwaJj4PeyVHB88heDdVu9e\",\"value\":1353600}],\"size\":257,\"weight\":1028,\"fee\":3800,\"status\":{\"confirmed\":true,\"block_height\":614672}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// The fee matched what we expected
offerData = "00072328,12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166,6250000,188,0,615955";
mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":19980}},{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"17qiF1TYgT1YvsCPJyXQoKMtBZ7YJBW9GH\",\"value\":19792},{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// The fee was more than what we expected: Expected BTC fee: 5000 sats , actual fee paid: 7000 sats
offerData = "bsqtrade,dfa4555ab78c657cad073e3f29c38c563d9dafc53afaa8c6af28510c734305c4,1000000,10,1,662390";
mempoolData = "{\"txid\":\"dfa4555ab78c657cad073e3f29c38c563d9dafc53afaa8c6af28510c734305c4\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":678997}}],\"vout\":[{\"scriptpubkey_address\":\"3EfRGckBQQuk7cpU7SwatPv8kFD1vALkTU\",\"value\":7000},{\"scriptpubkey_address\":\"bc1qu6vey3e7flzg8gmhun05m43uc2vz0ay33kuu6r\",\"value\":647998}],\"size\":224,\"weight\":566,\"fee\":23999,\"status\":{\"confirmed\":true,\"block_height\":669720}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// The fee matched what we expected
offerData = "89284,e1269aad63b3d894f5133ad658960971ef5c0fce6a13ad10544dc50fa3360588,900000,9,0,666473";
mempoolData = "{\"txid\":\"e1269aad63b3d894f5133ad658960971ef5c0fce6a13ad10544dc50fa3360588\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":72738}},{\"vout\":0,\"prevout\":{\"value\":1600000}}],\"vout\":[{\"scriptpubkey_address\":\"17Kh5Ype9yNomqRrqu2k1mdV5c6FcKfGwQ\",\"value\":72691},{\"scriptpubkey_address\":\"bc1qdr9zcw7gf2sehxkux4fmqujm5uguhaqz7l9lca\",\"value\":629016},{\"scriptpubkey_address\":\"bc1qgqrrqv8q6l5d3t52fe28ghuhz4xqrsyxlwn03z\",\"value\":956523}],\"size\":404,\"weight\":1286,\"fee\":14508,\"status\":{\"confirmed\":true,\"block_height\":672388}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// UNDERPAID: Expected fee: 7.04 BSQ, actual fee paid: 1.01 BSQ
offerData = "VOxRS,e99ea06aefc824fd45031447f7a0b56efb8117a09f9b8982e2c4da480a3a0e91,10000000,101,0,669129";
mempoolData = "{\"txid\":\"e99ea06aefc824fd45031447f7a0b56efb8117a09f9b8982e2c4da480a3a0e91\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":16739}},{\"vout\":2,\"prevout\":{\"value\":113293809}}],\"vout\":[{\"scriptpubkey_address\":\"1F14nF6zoUfJkqZrFgdmK5VX5QVwEpAnKW\",\"value\":16638},{\"scriptpubkey_address\":\"bc1q80y688ev7u43vqy964yf7feqddvt2mkm8977cm\",\"value\":11500000},{\"scriptpubkey_address\":\"bc1q9whgyc2du9mrgnxz0nl0shwpw8ugrcae0j0w8p\",\"value\":101784485}],\"size\":406,\"weight\":1291,\"fee\":9425,\"status\":{\"confirmed\":true,\"block_height\":669134}}";
Assert.assertFalse(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
// UNDERPAID: Expected fee: 1029000 sats BTC, actual fee paid: 441000 sats BTC because they used the default rate of 0.003 should have been 0.007 per BTC
// after 1.6.0 we introduce additional leniency to allow the default rate (which is not stored in the DAO param change list)
offerData = "AKA,6779b7571f21a5a1af01d675bf032b8a3c571416d05345491018cbc2d016e888,147000000,441000,1,676543";
mempoolData = "{'txid':'6779b7571f21a5a1af01d675bf032b8a3c571416d05345491018cbc2d016e888','version':1,'locktime':0,'vin':[{'txid':'94c36c0a9c5c99844ddfe17ef05a3ebbe94b14d76ee4bed7b00c7d45e681b441','vout':0,'prevout':{'scriptpubkey_address':'bc1qt5uprdzeh9g4el0k9cttn40qzagvpca9q0q6vl','value':177920825},'sequence':4294967295}],'vout':[{'scriptpubkey_address':'19BNi5EpZhgBBWAt5ka7xWpJpX2ZWJEYyq','value':441000},{'scriptpubkey_address':'bc1qxxcl9dz6usrx4z456g6fg8n3u9327hl458d6mx','value':177008388},{'scriptpubkey_address':'bc1qdq0894p2nmg04ceyqgapln6addfl80zy7z36jd','value':467243}],'size':256,'weight':697,'fee':4194,'status':{'confirmed':true,'block_height':676543}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
}
@Test
public void testGoodOffers() throws InterruptedException {
Map<String, String> goodOffers = loadJsonTestData("offerTestData.json");
Map<String, String> mempoolData = loadJsonTestData("txInfo.json");
Assert.assertTrue(goodOffers.size() > 0);
Assert.assertTrue(mempoolData.size() > 0);
log.warn("TESTING GOOD OFFERS");
testOfferSet(goodOffers, mempoolData, true);
}
@Test
public void testBadOffers() throws InterruptedException {
Map<String, String> badOffers = loadJsonTestData("badOfferTestData.json");
Map<String, String> mempoolData = loadJsonTestData("txInfo.json");
Assert.assertTrue(badOffers.size() > 0);
Assert.assertTrue(mempoolData.size() > 0);
log.warn("TESTING BAD OFFERS");
testOfferSet(badOffers, mempoolData, false);
}
private void testOfferSet(Map<String, String> offers, Map<String, String> mempoolData, boolean expectedResult) {
@ -163,7 +85,9 @@ public class TxValidatorTest {
log.warn("{} was not found in the mempool", txValidator.getTxId());
Assert.assertFalse(expectedResult); // tx was not found in explorer
} else {
txValidator.parseJsonValidateMakerFeeTx(jsonTxt, btcFeeReceivers);
//txValidator.parseJsonValidateMakerFeeTx(jsonTxt, btcFeeReceivers);
log.warn("expectedResult {}", expectedResult );
log.warn("getResult {}", txValidator.getResult() );
Assert.assertTrue(expectedResult == txValidator.getResult());
}
});
@ -181,100 +105,16 @@ public class TxValidatorTest {
}
// initialize the TxValidator with offerData to be validated
// and mock the used DaoStateService
private TxValidator createTxValidator(String offerData) {
try {
String[] y = offerData.split(",");
String txId = y[1];
long amount = Long.parseLong(y[2]);
boolean isCurrencyForMakerFeeBtc = Long.parseLong(y[4]) > 0;
DaoStateService mockedDaoStateService = mock(DaoStateService.class);
Answer<Coin> mockGetFeeRate = invocation -> {
return mockedLookupFeeRate(invocation.getArgument(0), invocation.getArgument(1));
};
Answer<Coin> mockGetParamValueAsCoin = invocation -> {
return mockedGetParamValueAsCoin(invocation.getArgument(0), invocation.getArgument(1));
};
Answer<List<Coin>> mockGetParamChangeList = invocation -> {
return mockedGetParamChangeList(invocation.getArgument(0));
};
when(mockedDaoStateService.getParamValueAsCoin(Mockito.any(Param.class), Mockito.anyInt())).thenAnswer(mockGetFeeRate);
when(mockedDaoStateService.getParamValueAsCoin(Mockito.any(Param.class), Mockito.anyString())).thenAnswer(mockGetParamValueAsCoin);
when(mockedDaoStateService.getParamChangeList(Mockito.any())).thenAnswer(mockGetParamChangeList);
TxValidator txValidator = new TxValidator(mockedDaoStateService, txId, Coin.valueOf(amount), isCurrencyForMakerFeeBtc);
TxValidator txValidator = new TxValidator(txId, Coin.valueOf(amount));
return txValidator;
} catch (RuntimeException ignore) {
// If input format is not as expected we ignore entry
}
return null;
}
Coin mockedLookupFeeRate(Param param, int blockHeight) {
BsqFormatter bsqFormatter = new BsqFormatter();
LinkedHashMap<Long, String> feeMap = mockedGetFeeRateMap(param);
for (Map.Entry<Long, String> entry : feeMap.entrySet()) {
if (blockHeight >= entry.getKey()) {
if (param.equals(Param.DEFAULT_MAKER_FEE_BTC) || param.equals(Param.DEFAULT_TAKER_FEE_BTC))
return bsqFormatter.parseToBTC(entry.getValue());
else
return ParsingUtils.parseToCoin(entry.getValue(), bsqFormatter);
}
}
if (param.equals(Param.DEFAULT_MAKER_FEE_BTC) || param.equals(Param.DEFAULT_TAKER_FEE_BTC))
return bsqFormatter.parseToBTC(param.getDefaultValue());
else
return ParsingUtils.parseToCoin(param.getDefaultValue(), bsqFormatter);
}
private LinkedHashMap<Long, String> mockedGetFeeRateMap(Param param) {
LinkedHashMap<Long, String> feeMap = new LinkedHashMap<>();
if (param == Param.DEFAULT_MAKER_FEE_BSQ) {
feeMap.put(674707L, "8.66"); // https://github.com/bisq-network/proposals/issues/318
feeMap.put(670027L, "7.53");
feeMap.put(660667L, "10.06");
feeMap.put(655987L, "8.74");
feeMap.put(641947L, "7.6");
feeMap.put(632587L, "6.6");
feeMap.put(623227L, "5.75");
feeMap.put(599827L, "10.0");
feeMap.put(590467L, "13.0");
feeMap.put(585787L, "8.0");
feeMap.put(581107L, "1.6");
} else if (param == Param.DEFAULT_TAKER_FEE_BSQ) {
feeMap.put(674707L, "60.59"); // https://github.com/bisq-network/proposals/issues/318
feeMap.put(670027L, "52.68");
feeMap.put(660667L, "70.39");
feeMap.put(655987L, "61.21");
feeMap.put(641947L, "53.23");
feeMap.put(632587L, "46.30");
feeMap.put(623227L, "40.25");
feeMap.put(599827L, "30.00");
feeMap.put(590467L, "38.00");
feeMap.put(585787L, "24.00");
feeMap.put(581107L, "4.80");
} else if (param == Param.DEFAULT_MAKER_FEE_BTC) {
feeMap.put(623227L, "0.0010");
feeMap.put(585787L, "0.0020");
} else if (param == Param.DEFAULT_TAKER_FEE_BTC) {
feeMap.put(623227L, "0.0070");
feeMap.put(585787L, "0.0060");
}
return feeMap;
}
public Coin mockedGetParamValueAsCoin(Param param, String paramValue) {
BsqFormatter bsqFormatter = new BsqFormatter();
return bsqFormatter.parseParamValueToCoin(param, paramValue);
}
public List<Coin> mockedGetParamChangeList(Param param) {
BsqFormatter bsqFormatter = new BsqFormatter();
List<Coin> retVal = new ArrayList<Coin>();
Map<Long, String> feeMap = mockedGetFeeRateMap(param);
for (Map.Entry<Long, String> entry : feeMap.entrySet()) {
retVal.add(ParsingUtils.parseToCoin(entry.getValue(), bsqFormatter));
}
return retVal;
}
}

View file

@ -61,8 +61,7 @@ public class PreferencesTest {
Config config = new Config();
LocalBitcoinNode localBitcoinNode = new LocalBitcoinNode(config);
preferences = new Preferences(
persistenceManager, config, null, localBitcoinNode, null, null, Config.DEFAULT_FULL_DAO_NODE,
null, null, Config.UNSPECIFIED_PORT);
persistenceManager, config, null, localBitcoinNode, null);
}
@Test

View file

@ -52,8 +52,6 @@ public class UserPayloadModelVOTest {
Lists.newArrayList(),
false,
Lists.newArrayList(),
false,
null,
null,
Lists.newArrayList(),
Lists.newArrayList(),

View file

@ -1,147 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.util;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.governance.param.Param;
import bisq.core.filter.Filter;
import bisq.core.filter.FilterManager;
import com.google.common.collect.Lists;
import com.google.common.primitives.Longs;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class FeeReceiverSelectorTest {
@Mock
private DaoFacade daoFacade;
@Mock
private FilterManager filterManager;
@Test
public void testGetAddress() {
Random rnd = new Random(123);
when(filterManager.getFilter()).thenReturn(filterWithReceivers(
List.of("", "foo#0.001", "ill-formed", "bar#0.002", "baz#0.001", "partial#bad")));
Map<String, Integer> selectionCounts = new HashMap<>();
for (int i = 0; i < 400; i++) {
String address = FeeReceiverSelector.getAddress(daoFacade, filterManager, rnd);
selectionCounts.compute(address, (k, n) -> n != null ? n + 1 : 1);
}
assertEquals(3, selectionCounts.size());
// Check within 2 std. of the expected values (95% confidence each):
assertEquals(100.0, selectionCounts.get("foo"), 18);
assertEquals(200.0, selectionCounts.get("bar"), 20);
assertEquals(100.0, selectionCounts.get("baz"), 18);
}
@Test
public void testGetAddress_noValidReceivers_nullFilter() {
when(daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS)).thenReturn("default");
when(filterManager.getFilter()).thenReturn(null);
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
}
@Test
public void testGetAddress_noValidReceivers_filterWithNullList() {
when(daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS)).thenReturn("default");
when(filterManager.getFilter()).thenReturn(filterWithReceivers(null));
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
}
@Test
public void testGetAddress_noValidReceivers_filterWithEmptyList() {
when(daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS)).thenReturn("default");
when(filterManager.getFilter()).thenReturn(filterWithReceivers(List.of()));
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
}
@Test
public void testGetAddress_noValidReceivers_filterWithIllFormedList() {
when(daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS)).thenReturn("default");
when(filterManager.getFilter()).thenReturn(filterWithReceivers(List.of("ill-formed")));
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
}
@Test
public void testWeightedSelection() {
Random rnd = new Random(456);
int[] selections = new int[3];
for (int i = 0; i < 6000; i++) {
selections[FeeReceiverSelector.weightedSelection(Longs.asList(1, 2, 3), rnd)]++;
}
// Check within 2 std. of the expected values (95% confidence each):
assertEquals(1000.0, selections[0], 58);
assertEquals(2000.0, selections[1], 74);
assertEquals(3000.0, selections[2], 78);
}
private static Filter filterWithReceivers(List<String> btcFeeReceiverAddresses) {
return new Filter(Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
false,
Lists.newArrayList(),
false,
null,
null,
Lists.newArrayList(),
Lists.newArrayList(),
Lists.newArrayList(),
btcFeeReceiverAddresses,
null,
0,
null,
null,
null,
null,
false,
Lists.newArrayList(),
new HashSet<>(),
false,
false);
}
}

View file

@ -1,7 +1,4 @@
{
"4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189": "am7DzIv,4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189,6100000,35,0,668195, underpaid but accepted due to use of different DAO parameter",
"ef1ea38b46402deb7df08c13a6dc379a65542a6940ac9d4ba436641ffd4bcb6e": "FQ0A7G,ef1ea38b46402deb7df08c13a6dc379a65542a6940ac9d4ba436641ffd4bcb6e,15970000,92,0,640438, underpaid but accepted due to use of different DAO parameter",
"051770f8d7f43a9b6ca10fefa6cdf4cb124a81eed26dc8af2e40f57d2589107b": "046698,051770f8d7f43a9b6ca10fefa6cdf4cb124a81eed26dc8af2e40f57d2589107b,15970000,92,0,667927, bsq fee underpaid using 5.75 rate for some weird reason",
"e125fdbd09ee86c01e16e1f12a31507cfb8703ed1bd5a221461adf33cb3e00d9": "7213472,e125fdbd09ee86c01e16e1f12a31507cfb8703ed1bd5a221461adf33cb3e00d9,200000000,200000,1,578672, unknown_fee_receiver_1PUXU1MQ",
"44b00de808d0145f9a948fe1b020c5d4173402ba0b5a5ba69124c67e371bca18": "aAPLmh98,44b00de808d0145f9a948fe1b020c5d4173402ba0b5a5ba69124c67e371bca18,140000000,140000,1,578629, unknown_fee_receiver_1PUXU1MQ",
"654a7a34321b57be6a553052d1d9e0f1764dd2fab7b64c9422e9953e4d9d127d": "pwdbdku,654a7a34321b57be6a553052d1d9e0f1764dd2fab7b64c9422e9953e4d9d127d,24980000,238000,1,554947, unknown_fee_receiver_18GzH11",