Merge pull request #1445 from sqrrm/fix-parsertest

Fix parsertest
This commit is contained in:
Manfred Karrer 2018-03-09 12:34:57 -05:00 committed by GitHub
commit 182158af20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 398 additions and 232 deletions

View file

@ -18,7 +18,7 @@ public class FunctionalReadWriteLock {
this(new ReentrantReadWriteLock(isFair));
}
public FunctionalReadWriteLock(ReadWriteLock lock) {
private FunctionalReadWriteLock(ReadWriteLock lock) {
readLock = lock.readLock();
writeLock = lock.writeLock();
}

View file

@ -20,8 +20,7 @@ package io.bisq.core.dao;
import com.google.inject.Singleton;
import com.google.inject.name.Names;
import io.bisq.common.app.AppModule;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import io.bisq.core.dao.blockchain.*;
import io.bisq.core.dao.blockchain.json.JsonBlockChainExporter;
import io.bisq.core.dao.node.BsqNodeProvider;
import io.bisq.core.dao.node.consensus.*;
@ -64,6 +63,9 @@ public class DaoModule extends AppModule {
bind(FullNode.class).in(Singleton.class);
bind(BsqNodeProvider.class).in(Singleton.class);
bind(BsqBlockChain.class).in(Singleton.class);
bind(ReadModel.class).in(Singleton.class);
bind(WriteModel.class).in(Singleton.class);
bind(SnapshotManager.class).in(Singleton.class);
bind(BsqBlockChainChangeDispatcher.class).in(Singleton.class);
bind(GenesisTxVerification.class).in(Singleton.class);

View file

@ -98,8 +98,8 @@ public class BsqBlockChain implements PersistableEnvelope {
private Tx genesisTx;
// not impl in PB yet
private Set<Tuple2<Long, Integer>> compensationRequestFees;
private Set<Tuple2<Long, Integer>> votingFees;
private final Set<Tuple2<Long, Integer>> compensationRequestFees;
private final Set<Tuple2<Long, Integer>> votingFees;
// transient
@Nullable
@ -213,7 +213,7 @@ public class BsqBlockChain implements PersistableEnvelope {
// Public write access
///////////////////////////////////////////////////////////////////////////////////////////
public void applySnapshot() {
void applySnapshot() {
lock.write(() -> {
checkNotNull(storage, "storage must not be null");
BsqBlockChain snapshot = storage.initAndGetPersistedWithFileName("BsqBlockChain", 100);
@ -238,11 +238,11 @@ public class BsqBlockChain implements PersistableEnvelope {
});
}
public void setCreateCompensationRequestFee(long fee, int blockHeight) {
void setCreateCompensationRequestFee(long fee, int blockHeight) {
lock.write(() -> compensationRequestFees.add(new Tuple2<>(fee, blockHeight)));
}
public void setVotingFee(long fee, int blockHeight) {
void setVotingFee(long fee, int blockHeight) {
lock.write(() -> votingFees.add(new Tuple2<>(fee, blockHeight)));
}
@ -251,7 +251,8 @@ public class BsqBlockChain implements PersistableEnvelope {
// Package scope write access
///////////////////////////////////////////////////////////////////////////////////////////
public void addBlock(BsqBlock block) throws BlockNotConnectingException {
//TODO refactor logic out
void addBlock(BsqBlock block) throws BlockNotConnectingException {
try {
lock.write2(() -> {
if (!bsqBlocks.contains(block)) {
@ -282,22 +283,22 @@ public class BsqBlockChain implements PersistableEnvelope {
}
}
public void addTxToMap(Tx tx) {
void addTxToMap(Tx tx) {
lock.write(() -> txMap.put(tx.getId(), tx));
}
public void addUnspentTxOutput(TxOutput txOutput) {
void addUnspentTxOutput(TxOutput txOutput) {
lock.write(() -> {
checkArgument(txOutput.isVerified(), "txOutput must be verified at addUnspentTxOutput");
unspentTxOutputsMap.put(txOutput.getTxIdIndexTuple(), txOutput);
});
}
public void removeUnspentTxOutput(TxOutput txOutput) {
void removeUnspentTxOutput(TxOutput txOutput) {
lock.write(() -> unspentTxOutputsMap.remove(txOutput.getTxIdIndexTuple()));
}
public void setGenesisTx(Tx tx) {
void setGenesisTx(Tx tx) {
lock.write(() -> genesisTx = tx);
}
@ -322,7 +323,7 @@ public class BsqBlockChain implements PersistableEnvelope {
return lock.read(() -> (BsqBlockChain) BsqBlockChain.fromProto(bsqBlockChain.getBsqBlockChainBuilder().build()));
}
public boolean containsBlock(BsqBlock bsqBlock) {
boolean containsBlock(BsqBlock bsqBlock) {
return lock.read(() -> bsqBlocks.contains(bsqBlock));
}
@ -364,7 +365,7 @@ public class BsqBlockChain implements PersistableEnvelope {
return lock.read(() -> txMap);
}
public List<BsqBlock> getResetBlocksFrom(int fromBlockHeight) {
List<BsqBlock> getResetBlocksFrom(int fromBlockHeight) {
return lock.read(() -> {
BsqBlockChain clone = getClone();
List<BsqBlock> filtered = clone.bsqBlocks.stream()
@ -404,16 +405,16 @@ public class BsqBlockChain implements PersistableEnvelope {
// Package scope read access
///////////////////////////////////////////////////////////////////////////////////////////
public Optional<TxOutput> getSpendableTxOutput(String txId, int index) {
Optional<TxOutput> getSpendableTxOutput(String txId, int index) {
return lock.read(() -> getSpendableTxOutput(new TxIdIndexTuple(txId, index)));
}
public Optional<TxOutput> getSpendableTxOutput(TxIdIndexTuple txIdIndexTuple) {
Optional<TxOutput> getSpendableTxOutput(TxIdIndexTuple txIdIndexTuple) {
return lock.read(() -> getUnspentTxOutput(txIdIndexTuple)
.filter(this::isTxOutputMature));
}
public long getCreateCompensationRequestFee(int blockHeight) {
long getCreateCompensationRequestFee(int blockHeight) {
return lock.read(() -> {
long fee = -1;
for (Tuple2<Long, Integer> feeAtHeight : compensationRequestFees) {
@ -426,12 +427,12 @@ public class BsqBlockChain implements PersistableEnvelope {
}
//TODO not impl yet
public boolean isCompensationRequestPeriodValid(int blockHeight) {
boolean isCompensationRequestPeriodValid(int blockHeight) {
return lock.read(() -> true);
}
public long getVotingFee(int blockHeight) {
long getVotingFee(int blockHeight) {
return lock.read(() -> {
long fee = -1;
for (Tuple2<Long, Integer> feeAtHeight : votingFees) {
@ -444,17 +445,17 @@ public class BsqBlockChain implements PersistableEnvelope {
}
//TODO not impl yet
public boolean isVotingPeriodValid(int blockHeight) {
boolean isVotingPeriodValid(int blockHeight) {
return lock.read(() -> true);
}
public boolean existsCompensationRequestBtcAddress(String btcAddress) {
boolean existsCompensationRequestBtcAddress(String btcAddress) {
return lock.read(() -> getAllTxOutputs().stream()
.anyMatch(txOutput -> txOutput.isCompensationRequestBtcOutput() &&
btcAddress.equals(txOutput.getAddress())));
}
public Set<TxOutput> findSponsoringBtcOutputsWithSameBtcAddress(String btcAddress) {
Set<TxOutput> findSponsoringBtcOutputsWithSameBtcAddress(String btcAddress) {
return lock.read(() -> getAllTxOutputs().stream()
.filter(txOutput -> txOutput.isSponsoringBtcOutput() &&
btcAddress.equals(txOutput.getAddress()))

View file

@ -0,0 +1,97 @@
/*
* 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 io.bisq.core.dao.blockchain;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import io.bisq.core.dao.blockchain.vo.util.TxIdIndexTuple;
import org.bitcoinj.core.Coin;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* Encapsulates read access to BsqBlockChain.
*/
public class ReadModel {
private BsqBlockChain bsqBlockChain;
@Inject
public ReadModel(BsqBlockChain bsqBlockChain) {
this.bsqBlockChain = bsqBlockChain;
}
public Optional<TxOutput> getSpendableTxOutput(TxIdIndexTuple txIdIndexTuple) {
return bsqBlockChain.getSpendableTxOutput(txIdIndexTuple);
}
public Optional<TxOutput> getSpendableTxOutput(String txId, int index) {
return getSpendableTxOutput(new TxIdIndexTuple(txId, index));
}
public boolean isCompensationRequestPeriodValid(int blockHeight) {
return bsqBlockChain.isCompensationRequestPeriodValid(blockHeight);
}
public long getCreateCompensationRequestFee(int blockHeight) {
return bsqBlockChain.getCreateCompensationRequestFee(blockHeight);
}
public int getChainHeadHeight() {
return bsqBlockChain.getChainHeadHeight();
}
public String getGenesisTxId() {
return bsqBlockChain.getGenesisTxId();
}
public int getGenesisBlockHeight() {
return bsqBlockChain.getGenesisBlockHeight();
}
public boolean containsBlock(BsqBlock bsqBlock) {
return bsqBlockChain.containsBlock(bsqBlock);
}
public List<BsqBlock> getResetBlocksFrom(int fromBlockHeight) {
return bsqBlockChain.getResetBlocksFrom(fromBlockHeight);
}
public Map<String, Tx> getTxMap() {
return bsqBlockChain.getTxMap();
}
public Tx getGenesisTx() {
return bsqBlockChain.getGenesisTx();
}
public Coin getIssuedAmount() {
return bsqBlockChain.getIssuedAmount();
}
public boolean containsTx(String txId) {
return bsqBlockChain.containsTx(txId);
}
public boolean isTxOutputSpendable(String txId, int index) {
return bsqBlockChain.isTxOutputSpendable(txId, index);
}
}

View file

@ -0,0 +1,35 @@
/*
* 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 io.bisq.core.dao.blockchain;
import javax.inject.Inject;
//TODO move snapshot related code from bsqBlockChain here
public class SnapshotManager {
private final BsqBlockChain bsqBlockChain;
@Inject
public SnapshotManager(BsqBlockChain bsqBlockChain) {
this.bsqBlockChain = bsqBlockChain;
}
public void applySnapshot() {
bsqBlockChain.applySnapshot();
}
}

View file

@ -0,0 +1,65 @@
/*
* 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 io.bisq.core.dao.blockchain;
import io.bisq.core.dao.blockchain.exceptions.BlockNotConnectingException;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import javax.inject.Inject;
/**
* Encapsulates write access to BsqBlockChain.
*/
public class WriteModel {
private BsqBlockChain bsqBlockChain;
@Inject
public WriteModel(BsqBlockChain bsqBlockChain) {
this.bsqBlockChain = bsqBlockChain;
}
public void removeUnspentTxOutput(TxOutput spendableTxOutput) {
bsqBlockChain.removeUnspentTxOutput(spendableTxOutput);
}
public void addTxToMap(Tx tx) {
bsqBlockChain.addTxToMap(tx);
}
public void addUnspentTxOutput(TxOutput txOutput) {
bsqBlockChain.addUnspentTxOutput(txOutput);
}
public void setGenesisTx(Tx tx) {
bsqBlockChain.setGenesisTx(tx);
}
public void addBlock(BsqBlock bsqBlock) throws BlockNotConnectingException {
bsqBlockChain.addBlock(bsqBlock);
}
public void setCreateCompensationRequestFee(long value, int genesisBlockHeight) {
bsqBlockChain.setCreateCompensationRequestFee(value, genesisBlockHeight);
}
public void setVotingFee(long value, int genesisBlockHeight) {
bsqBlockChain.setVotingFee(value, genesisBlockHeight);
}
}

View file

@ -19,8 +19,10 @@ package io.bisq.core.dao.node;
import com.google.inject.Inject;
import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.BsqBlockChainListener;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.SnapshotManager;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.provider.fee.FeeService;
import io.bisq.network.p2p.P2PService;
import io.bisq.network.p2p.P2PServiceListener;
@ -40,12 +42,13 @@ public abstract class BsqNode {
@SuppressWarnings("WeakerAccess")
protected final P2PService p2PService;
@SuppressWarnings("WeakerAccess")
protected final BsqBlockChain bsqBlockChain;
protected final ReadModel readModel;
@SuppressWarnings("WeakerAccess")
protected final List<BsqBlockChainListener> bsqBlockChainListeners = new ArrayList<>();
private final String genesisTxId;
private final int genesisBlockHeight;
private final SnapshotManager snapshotManager;
@org.jetbrains.annotations.NotNull
@Getter
protected boolean parseBlockchainComplete;
@SuppressWarnings("WeakerAccess")
@ -57,19 +60,22 @@ public abstract class BsqNode {
@SuppressWarnings("WeakerAccess")
@Inject
public BsqNode(P2PService p2PService,
BsqBlockChain bsqBlockChain,
public BsqNode(WriteModel writeModel,
ReadModel readModel,
SnapshotManager snapshotManager,
P2PService p2PService,
FeeService feeService) {
this.p2PService = p2PService;
this.bsqBlockChain = bsqBlockChain;
this.readModel = readModel;
genesisTxId = bsqBlockChain.getGenesisTxId();
genesisBlockHeight = bsqBlockChain.getGenesisBlockHeight();
genesisTxId = readModel.getGenesisTxId();
genesisBlockHeight = readModel.getGenesisBlockHeight();
this.snapshotManager = snapshotManager;
bsqBlockChain.setCreateCompensationRequestFee(feeService.getCreateCompensationRequestFee().value,
writeModel.setCreateCompensationRequestFee(feeService.getCreateCompensationRequestFee().value,
genesisBlockHeight);
bsqBlockChain.setVotingFee(feeService.getVotingTxFee().value,
writeModel.setVotingFee(feeService.getVotingTxFee().value,
genesisBlockHeight);
}
@ -150,16 +156,16 @@ public abstract class BsqNode {
@SuppressWarnings("WeakerAccess")
protected int getStartBlockHeight() {
final int startBlockHeight = Math.max(genesisBlockHeight, bsqBlockChain.getChainHeadHeight() + 1);
final int startBlockHeight = Math.max(genesisBlockHeight, readModel.getChainHeadHeight() + 1);
log.info("Start parse blocks:\n" +
" Start block height={}\n" +
" Genesis txId={}\n" +
" Genesis block height={}\n" +
" BsqBlockChain block height={}\n",
" Block height={}\n",
startBlockHeight,
genesisTxId,
genesisBlockHeight,
bsqBlockChain.getChainHeadHeight());
readModel.getChainHeadHeight());
return startBlockHeight;
}
@ -182,7 +188,7 @@ public abstract class BsqNode {
///////////////////////////////////////////////////////////////////////////////////////////
private void applySnapshot() {
bsqBlockChain.applySnapshot();
snapshotManager.applySnapshot();
bsqBlockChainListeners.forEach(BsqBlockChainListener::onBsqBlockChainChanged);
}
}

View file

@ -18,7 +18,7 @@
package io.bisq.core.dao.node;
import io.bisq.common.app.DevEnv;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxInput;
import io.bisq.core.dao.node.consensus.BsqTxVerification;
@ -44,7 +44,7 @@ import static com.google.common.base.Preconditions.checkArgument;
@Slf4j
@Immutable
public abstract class BsqParser {
protected final BsqBlockChain bsqBlockChain;
protected final WriteModel writeModel;
private final GenesisTxVerification genesisTxVerification;
private final BsqTxVerification bsqTxVerification;
@ -55,10 +55,10 @@ public abstract class BsqParser {
@SuppressWarnings("WeakerAccess")
@Inject
public BsqParser(BsqBlockChain bsqBlockChain,
public BsqParser(WriteModel writeModel,
GenesisTxVerification genesisTxVerification,
BsqTxVerification bsqTxVerification) {
this.bsqBlockChain = bsqBlockChain;
this.writeModel = writeModel;
this.genesisTxVerification = genesisTxVerification;
this.bsqTxVerification = bsqTxVerification;
}

View file

@ -17,7 +17,6 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxType;
import lombok.Getter;
@ -32,26 +31,17 @@ import javax.inject.Inject;
@Slf4j
public class BsqTxVerification {
private final BsqBlockChain bsqBlockChain;
private final TxInputsVerification txInputsVerification;
private final TxOutputsVerification txOutputsVerification;
@Inject
public BsqTxVerification(BsqBlockChain bsqBlockChain,
TxInputsVerification txInputsVerification,
public BsqTxVerification(TxInputsVerification txInputsVerification,
TxOutputsVerification txOutputsVerification) {
this.bsqBlockChain = bsqBlockChain;
this.txInputsVerification = txInputsVerification;
this.txOutputsVerification = txOutputsVerification;
}
public boolean isBsqTx(int blockHeight, Tx tx) {
return bsqBlockChain.<Boolean>callFunctionWithWriteLock(() -> execute(blockHeight, tx));
}
// Not thread safe wrt bsqBlockChain
// Check if any of the inputs are BSQ inputs and update BsqBlockChain state accordingly
private boolean execute(int blockHeight, Tx tx) {
BsqInputBalance bsqInputBalance = txInputsVerification.getBsqInputBalance(tx, blockHeight);
final boolean bsqInputBalancePositive = bsqInputBalance.isPositive();

View file

@ -18,7 +18,7 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.common.app.Version;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import io.bisq.core.dao.blockchain.vo.TxOutputType;
@ -26,27 +26,30 @@ import io.bisq.core.dao.blockchain.vo.TxType;
import javax.inject.Inject;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Verifies if OP_RETURN data matches rules for a compensation request tx and applies state change.
*/
public class CompensationRequestVerification {
private final BsqBlockChain bsqBlockChain;
private final ReadModel readModel;
@Inject
public CompensationRequestVerification(BsqBlockChain bsqBlockChain) {
this.bsqBlockChain = bsqBlockChain;
public CompensationRequestVerification(ReadModel readModel) {
this.readModel = readModel;
}
public boolean verify(byte[] opReturnData, long bsqFee, int blockHeight, TxOutputsVerification.MutableState mutableState) {
return mutableState.getCompRequestIssuanceOutputCandidate() != null &&
opReturnData.length == 22 &&
Version.COMPENSATION_REQUEST_VERSION == opReturnData[1] &&
bsqFee == bsqBlockChain.getCreateCompensationRequestFee(blockHeight) &&
bsqBlockChain.isCompensationRequestPeriodValid(blockHeight);
bsqFee == readModel.getCreateCompensationRequestFee(blockHeight) &&
readModel.isCompensationRequestPeriodValid(blockHeight);
}
public void applyStateChange(Tx tx, TxOutput opReturnTxOutput, TxOutputsVerification.MutableState mutableState) {
opReturnTxOutput.setTxOutputType(TxOutputType.COMPENSATION_REQUEST_OP_RETURN_OUTPUT);
checkArgument(mutableState.getCompRequestIssuanceOutputCandidate() != null, "mutableState.getCompRequestIssuanceOutputCandidate() must nto be null");
mutableState.getCompRequestIssuanceOutputCandidate().setTxOutputType(TxOutputType.COMPENSATION_REQUEST_ISSUANCE_CANDIDATE_OUTPUT);
tx.setTxType(TxType.COMPENSATION_REQUEST);
}

View file

@ -18,7 +18,7 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.DaoOptionKeys;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxType;
@ -30,15 +30,15 @@ import javax.inject.Named;
*/
public class GenesisTxVerification {
private final BsqBlockChain bsqBlockChain;
private final WriteModel writeModel;
private final String genesisTxId;
private final int genesisBlockHeight;
@Inject
public GenesisTxVerification(BsqBlockChain bsqBlockChain,
public GenesisTxVerification(WriteModel writeModel,
@Named(DaoOptionKeys.GENESIS_TX_ID) String genesisTxId,
@Named(DaoOptionKeys.GENESIS_BLOCK_HEIGHT) int genesisBlockHeight) {
this.bsqBlockChain = bsqBlockChain;
this.writeModel = writeModel;
this.genesisTxId = genesisTxId;
this.genesisBlockHeight = genesisBlockHeight;
}
@ -51,11 +51,11 @@ public class GenesisTxVerification {
tx.getOutputs().forEach(txOutput -> {
txOutput.setUnspent(true);
txOutput.setVerified(true);
bsqBlockChain.addUnspentTxOutput(txOutput);
writeModel.addUnspentTxOutput(txOutput);
});
tx.setTxType(TxType.GENESIS);
bsqBlockChain.setGenesisTx(tx);
bsqBlockChain.addTxToMap(tx);
writeModel.setGenesisTx(tx);
writeModel.addTxToMap(tx);
}
}

View file

@ -17,42 +17,20 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import io.bisq.core.dao.blockchain.vo.TxType;
import io.bisq.core.dao.request.compensation.CompensationRequest;
import io.bisq.core.dao.request.compensation.CompensationRequestManager;
import lombok.extern.slf4j.Slf4j;
import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.Set;
//TODO outdated, ignore
@Slf4j
public class IssuanceVerification {
private static final long MIN_BSQ_ISSUANCE_AMOUNT = 1000;
private static final long MAX_BSQ_ISSUANCE_AMOUNT = 10_000_000;
private final BsqBlockChain bsqBlockChain;
private final PeriodVerification periodVerification;
private final VotingVerification votingVerification;
private final CompensationRequestManager compensationRequestManager;
/* private static final long MIN_BSQ_ISSUANCE_AMOUNT = 1000;
private static final long MAX_BSQ_ISSUANCE_AMOUNT = 10_000_000;*/
@Inject
public IssuanceVerification(BsqBlockChain bsqBlockChain,
PeriodVerification periodVerification,
VotingVerification votingVerification,
CompensationRequestManager compensationRequestManager) {
this.bsqBlockChain = bsqBlockChain;
this.periodVerification = periodVerification;
this.votingVerification = votingVerification;
this.compensationRequestManager = compensationRequestManager;
public IssuanceVerification() {
}
public boolean maybeProcessData(Tx tx) {
/* public boolean maybeProcessData(Tx tx) {
List<TxOutput> outputs = tx.getOutputs();
if (outputs.size() >= 2) {
TxOutput bsqTxOutput = outputs.get(0);
@ -91,5 +69,5 @@ public class IssuanceVerification {
}
}
return false;
}
}*/
}

View file

@ -17,20 +17,11 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import javax.inject.Inject;
public class PeriodVerification {
private final BsqBlockChain bsqBlockChain;
@Inject
public PeriodVerification(BsqBlockChain bsqBlockChain) {
this.bsqBlockChain = bsqBlockChain;
}
// TODO
public boolean isInSponsorPeriod(int blockHeight) {
return true;
public PeriodVerification() {
}
}

View file

@ -17,7 +17,8 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.vo.SpentInfo;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxInput;
@ -34,23 +35,25 @@ import java.util.Optional;
@Slf4j
public class TxInputVerification {
private final BsqBlockChain bsqBlockChain;
private final WriteModel writeModel;
private final ReadModel readModel;
@Inject
public TxInputVerification(BsqBlockChain bsqBlockChain) {
this.bsqBlockChain = bsqBlockChain;
public TxInputVerification(WriteModel writeModel, ReadModel readModel) {
this.writeModel = writeModel;
this.readModel = readModel;
}
Optional<TxOutput> getOptionalSpendableTxOutput(TxInput input) {
// TODO check if Tuple indexes of inputs outputs are not messed up...
// Get spendable BSQ output for txIdIndexTuple... (get output used as input in tx if it's spendable BSQ)
return bsqBlockChain.getSpendableTxOutput(input.getTxIdIndexTuple());
return readModel.getSpendableTxOutput(input.getTxIdIndexTuple());
}
void applyStateChange(TxInput input, TxOutput spendableTxOutput, int blockHeight, Tx tx, int inputIndex) {
// The output is BSQ, set it as spent, update bsqBlockChain and add to available BSQ for this tx
spendableTxOutput.setUnspent(false);
bsqBlockChain.removeUnspentTxOutput(spendableTxOutput);
writeModel.removeUnspentTxOutput(spendableTxOutput);
spendableTxOutput.setSpentInfo(new SpentInfo(blockHeight, tx.getId(), inputIndex));
input.setConnectedTxOutput(spendableTxOutput);
}

View file

@ -17,7 +17,7 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxInput;
import io.bisq.core.dao.blockchain.vo.TxOutput;
@ -32,12 +32,12 @@ import java.util.Optional;
@Slf4j
public class TxInputsVerification {
private final BsqBlockChain bsqBlockChain;
private final WriteModel writeModel;
private final TxInputVerification txInputVerification;
@Inject
public TxInputsVerification(BsqBlockChain bsqBlockChain, TxInputVerification txInputVerification) {
this.bsqBlockChain = bsqBlockChain;
public TxInputsVerification(WriteModel writeModel, TxInputVerification txInputVerification) {
this.writeModel = writeModel;
this.txInputVerification = txInputVerification;
}
@ -55,6 +55,6 @@ public class TxInputsVerification {
}
void applyStateChange(Tx tx) {
bsqBlockChain.addTxToMap(tx);
writeModel.addTxToMap(tx);
}
}

View file

@ -17,7 +17,7 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import io.bisq.core.dao.blockchain.vo.TxOutputType;
@ -34,13 +34,12 @@ import static com.google.common.base.Preconditions.checkArgument;
@Slf4j
public class TxOutputVerification {
private final BsqBlockChain bsqBlockChain;
private final WriteModel writeModel;
private final OpReturnVerification opReturnVerification;
@Inject
public TxOutputVerification(BsqBlockChain bsqBlockChain,
OpReturnVerification opReturnVerification) {
this.bsqBlockChain = bsqBlockChain;
public TxOutputVerification(WriteModel writeModel, OpReturnVerification opReturnVerification) {
this.writeModel = writeModel;
this.opReturnVerification = opReturnVerification;
}
@ -100,7 +99,7 @@ public class TxOutputVerification {
txOutput.setVerified(true);
txOutput.setUnspent(true);
txOutput.setTxOutputType(TxOutputType.BSQ_OUTPUT);
bsqBlockChain.addUnspentTxOutput(txOutput);
writeModel.addUnspentTxOutput(txOutput);
}
private void applyStateChangeForBtcOutput(TxOutput txOutput) {

View file

@ -23,6 +23,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.List;
@ -52,7 +53,9 @@ public class TxOutputsVerification {
@Getter
@Setter
static class MutableState {
@Nullable
private TxOutput compRequestIssuanceOutputCandidate;
@Nullable
private TxOutput bsqOutput;
MutableState() {

View file

@ -17,54 +17,14 @@
package io.bisq.core.dao.node.consensus;
import io.bisq.common.app.Version;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import io.bisq.core.dao.blockchain.vo.TxOutputType;
import io.bisq.core.dao.blockchain.vo.TxType;
import io.bisq.core.dao.request.compensation.CompensationRequest;
import lombok.extern.slf4j.Slf4j;
import javax.inject.Inject;
//TODO outdated, ignore
@SuppressWarnings("unused")
@Slf4j
public class VotingVerification {
private final BsqBlockChain bsqBlockChain;
private final PeriodVerification periodVerification;
@Inject
public VotingVerification(BsqBlockChain bsqBlockChain,
PeriodVerification periodVerification) {
this.bsqBlockChain = bsqBlockChain;
this.periodVerification = periodVerification;
}
public boolean isCompensationRequestAccepted(CompensationRequest compensationRequest) {
return true;
}
public boolean isConversionRateValid(int blockHeight, long btcAmount, long bsqAmount) {
return false;
}
public boolean isOpReturn(Tx tx, byte[] opReturnData, TxOutput txOutput, long bsqFee, int blockHeight, TxOutput bsqOutput) {
if (Version.VOTING_VERSION == opReturnData[1] && opReturnData.length > 22) {
final int sizeOfCompRequestsVotes = (int) opReturnData[22];
if (bsqOutput != null &&
sizeOfCompRequestsVotes % 2 == 0 &&
opReturnData.length % 2 == 1 &&
opReturnData.length >= 23 + sizeOfCompRequestsVotes * 2 &&
bsqFee == bsqBlockChain.getVotingFee(blockHeight) &&
bsqBlockChain.isVotingPeriodValid(blockHeight)) {
txOutput.setTxOutputType(TxOutputType.VOTE_OP_RETURN_OUTPUT);
tx.setTxType(TxType.VOTE);
// TODO use bsqOutput as weight
return true;
}
}
return false;
public VotingVerification() {
}
}

View file

@ -20,8 +20,10 @@ package io.bisq.core.dao.node.full;
import com.google.inject.Inject;
import io.bisq.common.UserThread;
import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.BsqBlockChainListener;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.SnapshotManager;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.exceptions.BlockNotConnectingException;
import io.bisq.core.dao.blockchain.json.JsonBlockChainExporter;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
@ -49,14 +51,18 @@ public class FullNode extends BsqNode {
@SuppressWarnings("WeakerAccess")
@Inject
public FullNode(P2PService p2PService,
public FullNode(WriteModel writeModel,
ReadModel readModel,
SnapshotManager snapshotManager,
P2PService p2PService,
FullNodeExecutor bsqFullNodeExecutor,
BsqBlockChain bsqBlockChain,
JsonBlockChainExporter jsonBlockChainExporter,
FeeService feeService,
FullNodeNetworkManager fullNodeNetworkManager) {
super(p2PService,
bsqBlockChain,
super(writeModel,
readModel,
snapshotManager,
p2PService,
feeService);
this.bsqFullNodeExecutor = bsqFullNodeExecutor;
this.jsonBlockChainExporter = jsonBlockChainExporter;

View file

@ -20,7 +20,7 @@ package io.bisq.core.dao.node.full;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.neemre.btcdcli4j.core.domain.Block;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.exceptions.BlockNotConnectingException;
import io.bisq.core.dao.blockchain.exceptions.BsqBlockchainException;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
@ -57,10 +57,10 @@ public class FullNodeParser extends BsqParser {
@Inject
public FullNodeParser(RpcService rpcService,
BsqBlockChain bsqBlockChain,
WriteModel writeModel,
GenesisTxVerification genesisTxVerification,
BsqTxVerification bsqTxVerification) {
super(bsqBlockChain, genesisTxVerification, bsqTxVerification);
super(writeModel, genesisTxVerification, bsqTxVerification);
this.rpcService = rpcService;
}
@ -95,7 +95,7 @@ public class FullNodeParser extends BsqParser {
btcdBlock.getHash(),
btcdBlock.getPreviousBlockHash(),
ImmutableList.copyOf(bsqTxsInBlock));
bsqBlockChain.addBlock(bsqBlock);
writeModel.addBlock(bsqBlock);
log.info("parseBlock took {} ms at blockHeight {}; bsqTxsInBlock.size={}",
System.currentTimeMillis() - startTs, bsqBlock.getHeight(), bsqTxsInBlock.size());
return bsqBlock;

View file

@ -3,7 +3,7 @@ package io.bisq.core.dao.node.full.network;
import io.bisq.common.UserThread;
import io.bisq.common.app.Log;
import io.bisq.common.proto.network.NetworkEnvelope;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import io.bisq.core.dao.node.messages.GetBsqBlocksRequest;
import io.bisq.core.dao.node.messages.NewBsqBlockBroadcastMessage;
@ -35,7 +35,7 @@ public class FullNodeNetworkManager implements MessageListener, PeerManager.List
private final NetworkNode networkNode;
private final PeerManager peerManager;
private final Broadcaster broadcaster;
private final BsqBlockChain bsqBlockChain;
private final ReadModel readModel;
// Key is connection UID
private final Map<String, GetBsqBlocksRequestHandler> getBlocksRequestHandlers = new HashMap<>();
@ -50,11 +50,11 @@ public class FullNodeNetworkManager implements MessageListener, PeerManager.List
public FullNodeNetworkManager(NetworkNode networkNode,
PeerManager peerManager,
Broadcaster broadcaster,
BsqBlockChain bsqBlockChain) {
ReadModel readModel) {
this.networkNode = networkNode;
this.peerManager = peerManager;
this.broadcaster = broadcaster;
this.bsqBlockChain = bsqBlockChain;
this.readModel = readModel;
// seedNodeAddresses can be empty (in case there is only 1 seed node, the seed node starting up has no other seed nodes)
networkNode.addMessageListener(this);
@ -113,7 +113,7 @@ public class FullNodeNetworkManager implements MessageListener, PeerManager.List
final String uid = connection.getUid();
if (!getBlocksRequestHandlers.containsKey(uid)) {
GetBsqBlocksRequestHandler requestHandler = new GetBsqBlocksRequestHandler(networkNode,
bsqBlockChain,
readModel,
new GetBsqBlocksRequestHandler.Listener() {
@Override
public void onComplete() {

View file

@ -6,7 +6,7 @@ import com.google.common.util.concurrent.SettableFuture;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.app.Log;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import io.bisq.core.dao.node.messages.GetBsqBlocksRequest;
import io.bisq.core.dao.node.messages.GetBsqBlocksResponse;
@ -43,19 +43,19 @@ class GetBsqBlocksRequestHandler {
///////////////////////////////////////////////////////////////////////////////////////////
private final NetworkNode networkNode;
private final ReadModel readModel;
private final Listener listener;
private Timer timeoutTimer;
private boolean stopped;
private final BsqBlockChain bsqBlockChain;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public GetBsqBlocksRequestHandler(NetworkNode networkNode, BsqBlockChain bsqBlockChain, Listener listener) {
public GetBsqBlocksRequestHandler(NetworkNode networkNode, ReadModel readModel, Listener listener) {
this.networkNode = networkNode;
this.bsqBlockChain = bsqBlockChain;
this.readModel = readModel;
this.listener = listener;
}
@ -66,7 +66,7 @@ class GetBsqBlocksRequestHandler {
public void onGetBsqBlocksRequest(GetBsqBlocksRequest getBsqBlocksRequest, final Connection connection) {
Log.traceCall(getBsqBlocksRequest + "\n\tconnection=" + connection);
List<BsqBlock> bsqBlocks = bsqBlockChain.getResetBlocksFrom(getBsqBlocksRequest.getFromBlockHeight());
List<BsqBlock> bsqBlocks = readModel.getResetBlocksFrom(getBsqBlocksRequest.getFromBlockHeight());
final GetBsqBlocksResponse bsqBlocksResponse = new GetBsqBlocksResponse(bsqBlocks, getBsqBlocksRequest.getNonce());
log.debug("bsqBlocksResponse " + bsqBlocksResponse.getRequestNonce());

View file

@ -20,8 +20,10 @@ package io.bisq.core.dao.node.lite;
import com.google.inject.Inject;
import io.bisq.common.UserThread;
import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.BsqBlockChainListener;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.SnapshotManager;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.exceptions.BlockNotConnectingException;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import io.bisq.core.dao.node.BsqNode;
@ -41,7 +43,7 @@ import java.util.function.Consumer;
/**
* Main class for lite nodes which receive the BSQ transactions from a full node (e.g. seed nodes).
*
* <p>
* Verification of BSQ transactions is done also by the lite node.
*/
@Slf4j
@ -56,13 +58,17 @@ public class LiteNode extends BsqNode {
@SuppressWarnings("WeakerAccess")
@Inject
public LiteNode(P2PService p2PService,
public LiteNode(WriteModel writeModel,
ReadModel readModel,
SnapshotManager snapshotManager,
P2PService p2PService,
LiteNodeExecutor bsqLiteNodeExecutor,
BsqBlockChain bsqBlockChain,
FeeService feeService,
LiteNodeNetworkManager liteNodeNetworkManager) {
super(p2PService,
bsqBlockChain,
super(writeModel,
readModel,
snapshotManager,
p2PService,
feeService);
this.bsqLiteNodeExecutor = bsqLiteNodeExecutor;
this.liteNodeNetworkManager = liteNodeNetworkManager;
@ -144,7 +150,7 @@ public class LiteNode extends BsqNode {
// We reset all mutable data in case the provider would not have done it.
bsqBlock.reset();
log.info("onNewBlockReceived: bsqBlock={}", bsqBlock.getHeight());
if (!bsqBlockChain.containsBlock(bsqBlock)) {
if (!readModel.containsBlock(bsqBlock)) {
bsqLiteNodeExecutor.parseBlock(bsqBlock,
this::notifyListenersOnNewBlock,
getErrorHandler());

View file

@ -24,7 +24,6 @@ import com.google.common.util.concurrent.ListeningExecutorService;
import io.bisq.common.UserThread;
import io.bisq.common.handlers.ResultHandler;
import io.bisq.common.util.Utilities;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
@ -40,7 +39,6 @@ import java.util.function.Consumer;
public class LiteNodeExecutor {
private final LiteNodeParser liteNodeParser;
private final BsqBlockChain bsqBlockChain;
private final ListeningExecutorService parseBlocksExecutor = Utilities.getListeningExecutorService("ParseBlocks", 1, 1, 60);
private final ListeningExecutorService parseBlockExecutor = Utilities.getListeningExecutorService("ParseBlock", 1, 1, 60);
@ -52,9 +50,8 @@ public class LiteNodeExecutor {
@SuppressWarnings("WeakerAccess")
@Inject
public LiteNodeExecutor(LiteNodeParser liteNodeParser, BsqBlockChain bsqBlockChain) {
public LiteNodeExecutor(LiteNodeParser liteNodeParser) {
this.liteNodeParser = liteNodeParser;
this.bsqBlockChain = bsqBlockChain;
}
@ -94,7 +91,6 @@ public class LiteNodeExecutor {
long startTs = System.currentTimeMillis();
liteNodeParser.parseBsqBlock(bsqBlock);
log.info("parseBlocks took {} ms", System.currentTimeMillis() - startTs);
bsqBlockChain.addBlock(bsqBlock);
return null;
});

View file

@ -17,7 +17,7 @@
package io.bisq.core.dao.node.lite;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.exceptions.BlockNotConnectingException;
import io.bisq.core.dao.blockchain.vo.BsqBlock;
import io.bisq.core.dao.blockchain.vo.Tx;
@ -40,10 +40,10 @@ import java.util.function.Consumer;
public class LiteNodeParser extends BsqParser {
@Inject
public LiteNodeParser(BsqBlockChain bsqBlockChain,
public LiteNodeParser(WriteModel writeModel,
GenesisTxVerification genesisTxVerification,
BsqTxVerification bsqTxVerification) {
super(bsqBlockChain, genesisTxVerification, bsqTxVerification);
super(writeModel, genesisTxVerification, bsqTxVerification);
}
void parseBsqBlocks(List<BsqBlock> bsqBlocks,
@ -51,17 +51,17 @@ public class LiteNodeParser extends BsqParser {
throws BlockNotConnectingException {
for (BsqBlock bsqBlock : bsqBlocks) {
parseBsqBlock(bsqBlock);
bsqBlockChain.addBlock(bsqBlock);
newBlockHandler.accept(bsqBlock);
}
}
void parseBsqBlock(BsqBlock bsqBlock) {
void parseBsqBlock(BsqBlock bsqBlock) throws BlockNotConnectingException {
int blockHeight = bsqBlock.getHeight();
log.info("Parse block at height={} ", blockHeight);
List<Tx> txList = new ArrayList<>(bsqBlock.getTxs());
List<Tx> bsqTxsInBlock = new ArrayList<>();
bsqBlock.getTxs().forEach(tx -> checkForGenesisTx(blockHeight, bsqTxsInBlock, tx));
recursiveFindBsqTxs(bsqTxsInBlock, txList, blockHeight, 0, 5300);
writeModel.addBlock(bsqBlock);
}
}

View file

@ -31,9 +31,9 @@ import io.bisq.core.btc.exceptions.WalletException;
import io.bisq.core.btc.wallet.BsqWalletService;
import io.bisq.core.btc.wallet.BtcWalletService;
import io.bisq.core.dao.DaoPeriodService;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import io.bisq.core.dao.blockchain.BsqBlockChainListener;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.request.compensation.consensus.OpReturnData;
import io.bisq.core.dao.request.compensation.consensus.Restrictions;
import io.bisq.core.provider.fee.FeeService;
@ -68,7 +68,7 @@ public class CompensationRequestManager implements PersistedDataHost, BsqBlockCh
private final DaoPeriodService daoPeriodService;
private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService;
private final BsqBlockChain bsqBlockChain;
private final ReadModel readModel;
private final Storage<CompensationRequestList> compensationRequestsStorage;
private final PublicKey signaturePubKey;
private final FeeService feeService;
@ -90,7 +90,7 @@ public class CompensationRequestManager implements PersistedDataHost, BsqBlockCh
BsqWalletService bsqWalletService,
BtcWalletService btcWalletService,
DaoPeriodService daoPeriodService,
BsqBlockChain bsqBlockChain,
ReadModel readModel,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
KeyRing keyRing,
Storage<CompensationRequestList> compensationRequestsStorage,
@ -99,7 +99,7 @@ public class CompensationRequestManager implements PersistedDataHost, BsqBlockCh
this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService;
this.daoPeriodService = daoPeriodService;
this.bsqBlockChain = bsqBlockChain;
this.readModel = readModel;
this.compensationRequestsStorage = compensationRequestsStorage;
this.feeService = feeService;
@ -235,7 +235,7 @@ public class CompensationRequestManager implements PersistedDataHost, BsqBlockCh
}
private boolean isInPhaseOrUnconfirmed(CompensationRequestPayload payload) {
return bsqBlockChain.getTxMap().get(payload.getTxId()) == null || daoPeriodService.isTxInPhase(payload.getTxId(), DaoPeriodService.Phase.COMPENSATION_REQUESTS);
return readModel.getTxMap().get(payload.getTxId()) == null || daoPeriodService.isTxInPhase(payload.getTxId(), DaoPeriodService.Phase.COMPENSATION_REQUESTS);
}
public boolean isMine(CompensationRequest compensationRequest) {
@ -336,7 +336,7 @@ public class CompensationRequestManager implements PersistedDataHost, BsqBlockCh
pastRequests.setPredicate(request -> daoPeriodService.isTxInPastCycle(request.getPayload().getTxId()));
activeRequests.setPredicate(compensationRequest -> {
return daoPeriodService.isTxInCurrentCycle(compensationRequest.getPayload().getTxId()) ||
(bsqBlockChain.getTxMap().get(compensationRequest.getPayload().getTxId()) == null &&
(readModel.getTxMap().get(compensationRequest.getPayload().getTxId()) == null &&
isMine(compensationRequest));
});
}

View file

@ -4,16 +4,17 @@ import com.neemre.btcdcli4j.core.BitcoindException;
import com.neemre.btcdcli4j.core.CommunicationException;
import com.neemre.btcdcli4j.core.domain.Block;
import io.bisq.common.proto.persistable.PersistenceProtoResolver;
import io.bisq.core.dao.DaoOptionKeys;
import io.bisq.core.dao.blockchain.BsqBlockChain;
import io.bisq.core.dao.blockchain.ReadModel;
import io.bisq.core.dao.blockchain.WriteModel;
import io.bisq.core.dao.blockchain.exceptions.BlockNotConnectingException;
import io.bisq.core.dao.blockchain.exceptions.BsqBlockchainException;
import io.bisq.core.dao.blockchain.vo.Tx;
import io.bisq.core.dao.blockchain.vo.TxInput;
import io.bisq.core.dao.blockchain.vo.TxOutput;
import io.bisq.core.dao.blockchain.vo.util.TxIdIndexTuple;
import io.bisq.core.dao.node.consensus.BsqTxVerification;
import io.bisq.core.dao.node.consensus.IssuanceVerification;
import io.bisq.core.dao.node.consensus.OpReturnVerification;
import io.bisq.core.dao.node.consensus.*;
import io.bisq.core.dao.node.full.rpc.RpcService;
import mockit.Expectations;
import mockit.Injectable;
@ -23,6 +24,7 @@ import org.bitcoinj.core.Coin;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.inject.Named;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
@ -33,31 +35,49 @@ import static java.util.Arrays.asList;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
// Intro to jmockit can be found at http://jmockit.github.io/tutorial/Mocking.html
@RunWith(JMockit.class)
public class FullNodeParserTest {
@Tested(availableDuringSetup = true)
BsqBlockChain bsqBlockChain;
// @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)
FullNodeParser fullNodeParser;
@Tested(fullyInitialized = true, availableDuringSetup = true)
BsqTxVerification bsqTxVerification;
BsqBlockChain bsqBlockChain;
@Tested(availableDuringSetup = true)
ReadModel readModel;
// Used by bsqTxVerification
@Tested(fullyInitialized = true, availableDuringSetup = true)
TxInputsVerification txInputsVerification;
@Tested(fullyInitialized = true, availableDuringSetup = true)
TxOutputsVerification txOutputsVerification;
// @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 bsqBlockChain
@Injectable
PersistenceProtoResolver persistenceProtoResolver;
@Injectable
File storageDir;
@Injectable
String genesisId = "genesisId";
String genesisTxId = "genesisTxId";
@Injectable
int genesisBlockHeight = 200;
// Used by fullNodeParser
@Injectable
RpcService rpcService;
@Injectable
OpReturnVerification opReturnVerification;
@Injectable
IssuanceVerification issuanceVerification;
@Tested(fullyInitialized = true, availableDuringSetup = true)
WriteModel writeModel;
@Tested(fullyInitialized = true, availableDuringSetup = true)
GenesisTxVerification genesisTxVerification;
@Tested(fullyInitialized = true, availableDuringSetup = true)
BsqTxVerification bsqTxVerification;
@Test
public void testIsBsqTx() {
@ -74,13 +94,18 @@ public class FullNodeParserTest {
// 1) - null, 0 -> not BSQ transaction
// 2) - 100, null -> BSQ transaction
// 3) - 0, 100 -> BSQ transaction
new Expectations(bsqBlockChain) {{
bsqBlockChain.getSpendableTxOutput(new TxIdIndexTuple("tx1", 0));
new Expectations(readModel) {{
// 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
readModel.getSpendableTxOutput(new TxIdIndexTuple("tx1", 0));
result = Optional.empty();
result = Optional.of(new TxOutput(0, 100, "txout1", null, null, null, height));
result = Optional.of(new TxOutput(0, 0, "txout1", null, null, null, height));
bsqBlockChain.getSpendableTxOutput(new TxIdIndexTuple("tx1", 1));
readModel.getSpendableTxOutput(new TxIdIndexTuple("tx1", 1));
result = Optional.of(new TxOutput(0, 0, "txout2", null, null, null, height));
result = Optional.empty();
result = Optional.of(new TxOutput(0, 100, "txout2", null, null, null, height));
@ -122,10 +147,10 @@ public class FullNodeParserTest {
Tx cbTx200 = new Tx(cbId200, 200, bh200, time,
new ArrayList<TxInput>(),
asList(new TxOutput(0, 25, cbId200, null, null, null, 200)));
Tx genesisTx = new Tx(genesisId, 200, bh200, time,
Tx genesisTx = new Tx(genesisTxId, 200, bh200, time,
asList(new TxInput("someoldtx", 0)),
asList(new TxOutput(0, issuance.getValue(), genesisId, null, null, null, 200)));
Block block200 = new Block(bh200, 10, 10, 200, 2, "root", asList(cbId200, genesisId), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh199, bh201);
asList(new TxOutput(0, issuance.getValue(), genesisTxId, null, null, null, 200)));
Block block200 = new Block(bh200, 10, 10, 200, 2, "root", asList(cbId200, genesisTxId), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh199, bh201);
// Block 201
// Make a bsq transaction
@ -137,7 +162,7 @@ public class FullNodeParserTest {
new ArrayList<TxInput>(),
asList(new TxOutput(0, 25, cbId201, null, null, null, 201)));
Tx bsqTx1 = new Tx(bsqTx1Id, 201, bh201, time,
asList(new TxInput(genesisId, 0)),
asList(new TxInput(genesisTxId, 0)),
asList(new TxOutput(0, bsqTx1Value1, bsqTx1Id, null, null, null, 201),
new TxOutput(1, bsqTx1Value2, bsqTx1Id, null, null, null, 201)));
Block block201 = new Block(bh201, 10, 10, 201, 2, "root", asList(cbId201, bsqTx1Id), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh200, "nextBlockHash");
@ -154,7 +179,7 @@ public class FullNodeParserTest {
result = cbTx199;
rpcService.requestTx(cbId200, genesisHeight);
result = cbTx200;
rpcService.requestTx(genesisId, genesisHeight);
rpcService.requestTx(genesisTxId, genesisHeight);
result = genesisTx;
rpcService.requestTx(cbId201, 201);
result = cbTx201;
@ -167,25 +192,25 @@ public class FullNodeParserTest {
});
// Verify that the genesis tx has been added to the bsq blockchain with the correct issuance amount
assertTrue(bsqBlockChain.getGenesisTx() == genesisTx);
assertTrue(bsqBlockChain.getIssuedAmount().getValue() == issuance.getValue());
assertTrue(readModel.getGenesisTx() == genesisTx);
assertTrue(readModel.getIssuedAmount().getValue() == issuance.getValue());
// And that other txs are not added
assertFalse(bsqBlockChain.containsTx(cbId199));
assertFalse(bsqBlockChain.containsTx(cbId200));
assertFalse(bsqBlockChain.containsTx(cbId201));
assertFalse(readModel.containsTx(cbId199));
assertFalse(readModel.containsTx(cbId200));
assertFalse(readModel.containsTx(cbId201));
// But bsq txs are added
assertTrue(bsqBlockChain.containsTx(bsqTx1Id));
TxOutput bsqOut1 = bsqBlockChain.getSpendableTxOutput(bsqTx1Id, 0).get();
assertTrue(readModel.containsTx(bsqTx1Id));
TxOutput bsqOut1 = readModel.getSpendableTxOutput(bsqTx1Id, 0).get();
assertTrue(bsqOut1.isUnspent());
assertTrue(bsqOut1.getValue() == bsqTx1Value1);
TxOutput bsqOut2 = bsqBlockChain.getSpendableTxOutput(bsqTx1Id, 1).get();
TxOutput bsqOut2 = readModel.getSpendableTxOutput(bsqTx1Id, 1).get();
assertTrue(bsqOut2.isUnspent());
assertTrue(bsqOut2.getValue() == bsqTx1Value2);
assertFalse(bsqBlockChain.isTxOutputSpendable(genesisId, 0));
assertTrue(bsqBlockChain.isTxOutputSpendable(bsqTx1Id, 0));
assertTrue(bsqBlockChain.isTxOutputSpendable(bsqTx1Id, 1));
assertFalse(readModel.isTxOutputSpendable(genesisTxId, 0));
assertTrue(readModel.isTxOutputSpendable(bsqTx1Id, 0));
assertTrue(readModel.isTxOutputSpendable(bsqTx1Id, 1));
}
}