mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-22 14:42:37 +01:00
commit
182158af20
27 changed files with 398 additions and 232 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue