mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-05-30 20:14:25 -04:00
remove DAO
Co-authored-by: premek <1145361+premek@users.noreply.github.com>
This commit is contained in:
parent
f9f2cd07c3
commit
cefba8e4b5
621 changed files with 583 additions and 68805 deletions
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -59,7 +59,6 @@ public class OfferMaker {
|
|||
0L,
|
||||
0L,
|
||||
0L,
|
||||
false,
|
||||
0L,
|
||||
0L,
|
||||
0L,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -52,8 +52,6 @@ public class UserPayloadModelVOTest {
|
|||
Lists.newArrayList(),
|
||||
false,
|
||||
Lists.newArrayList(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue