mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 18:03:12 +01:00
Use lockup txid to track confiscation
1. Every bond is defined by its lockup transaction. To make it easy to track which bonds are confiscated it's easier to track them by only one txid instead of using a map with a mix of lockup txoutputs and unlock txoutputs. To check if a txoutput has been confiscated it has to be checked against the originiating lockup txid. 2. Minor fixes of naming lockedup -> lockup and comments.
This commit is contained in:
parent
aa27d443a4
commit
e815c4b105
@ -1473,7 +1473,7 @@ message BsqState {
|
||||
map<string, BaseTxOutput> unspent_tx_output_map = 4;
|
||||
map<string, BaseTxOutput> non_bsq_tx_output_map = 5;
|
||||
map<string, Issuance> issuance_map = 6;
|
||||
map<string, BaseTxOutput> confiscated_tx_output_map = 7;
|
||||
repeated string confiscated_lockup_tx_list = 7;
|
||||
map<string, SpentInfo> spent_info_map = 8;
|
||||
repeated ParamChange param_change_list = 9;
|
||||
repeated EvaluatedProposal evaluated_proposal_list = 10;
|
||||
|
@ -615,14 +615,14 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
||||
// Unlock bond tx
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Transaction getPreparedUnlockTx(TxOutput lockedTxOutput) throws AddressFormatException {
|
||||
public Transaction getPreparedUnlockTx(TxOutput lockupTxOutput) throws AddressFormatException {
|
||||
Transaction tx = new Transaction(params);
|
||||
// Unlocking means spending the full value of the locked txOutput to another txOutput with the same value
|
||||
Coin amountToUnlock = Coin.valueOf(lockedTxOutput.getValue());
|
||||
Coin amountToUnlock = Coin.valueOf(lockupTxOutput.getValue());
|
||||
checkArgument(Restrictions.isAboveDust(amountToUnlock), "The amount is too low (dust limit).");
|
||||
Transaction lockupTx = getTransaction(lockedTxOutput.getTxId());
|
||||
Transaction lockupTx = getTransaction(lockupTxOutput.getTxId());
|
||||
checkNotNull(lockupTx, "lockupTx must not be null");
|
||||
TransactionOutPoint outPoint = new TransactionOutPoint(params, lockedTxOutput.getIndex(), lockupTx);
|
||||
TransactionOutPoint outPoint = new TransactionOutPoint(params, lockupTxOutput.getIndex(), lockupTx);
|
||||
// Input is not signed yet so we use new byte[]{}
|
||||
tx.addInput(new TransactionInput(params, tx, new byte[]{}, outPoint, amountToUnlock));
|
||||
tx.addOutput(new TransactionOutput(params, tx, amountToUnlock, getUnusedAddress()));
|
||||
|
@ -110,8 +110,8 @@ public class DaoStateService implements DaoSetupService {
|
||||
daoState.getUnspentTxOutputMap().clear();
|
||||
daoState.getUnspentTxOutputMap().putAll(snapshot.getUnspentTxOutputMap());
|
||||
|
||||
daoState.getConfiscatedTxOutputMap().clear();
|
||||
daoState.getConfiscatedTxOutputMap().putAll(snapshot.getConfiscatedTxOutputMap());
|
||||
daoState.getConfiscatedLockupTxList().clear();
|
||||
daoState.getConfiscatedLockupTxList().addAll(snapshot.getConfiscatedLockupTxList());
|
||||
|
||||
daoState.getIssuanceMap().clear();
|
||||
daoState.getIssuanceMap().putAll(snapshot.getIssuanceMap());
|
||||
@ -668,6 +668,7 @@ public class DaoStateService implements DaoSetupService {
|
||||
// Returns amount of all LOCKUP txOutputs (they might have been unlocking or unlocked in the meantime)
|
||||
public long getTotalAmountOfLockupTxOutputs() {
|
||||
return getLockupTxOutputs().stream()
|
||||
.filter(txOutput -> !isConfiscatedLockupTxOutput(txOutput.getTxId()))
|
||||
.mapToLong(TxOutput::getValue)
|
||||
.sum();
|
||||
}
|
||||
@ -679,6 +680,11 @@ public class DaoStateService implements DaoSetupService {
|
||||
|
||||
|
||||
// Unlock
|
||||
public boolean isUnlockOutput(TxOutputKey key) {
|
||||
Optional<TxOutput> opTxOutput = getUnspentTxOutput(key);
|
||||
return opTxOutput.isPresent() && isUnlockOutput(opTxOutput.get());
|
||||
}
|
||||
|
||||
public boolean isUnlockOutput(TxOutput txOutput) {
|
||||
return txOutput.getTxOutputType() == TxOutputType.UNLOCK_OUTPUT;
|
||||
}
|
||||
@ -693,6 +699,7 @@ public class DaoStateService implements DaoSetupService {
|
||||
|
||||
public long getTotalAmountOfUnLockingTxOutputs() {
|
||||
return getUnspentUnlockingTxOutputsStream()
|
||||
.filter(txOutput -> !isConfiscatedUnlockTxOutput(txOutput.getTxId()))
|
||||
.mapToLong(TxOutput::getValue)
|
||||
.sum();
|
||||
}
|
||||
@ -713,6 +720,10 @@ public class DaoStateService implements DaoSetupService {
|
||||
!isLockTimeOverForUnlockTxOutput(unlockTxOutput);
|
||||
}
|
||||
|
||||
public Optional<Tx> getLockupTxFromUnlockTxId(String unlockTxId) {
|
||||
return getTx(unlockTxId).flatMap(tx -> getTx(tx.getTxInputs().get(0).getConnectedTxOutputTxId()));
|
||||
}
|
||||
|
||||
// Unlocked
|
||||
public Optional<Integer> getUnlockBlockHeight(String txId) {
|
||||
return getTx(txId).map(Tx::getUnlockBlockHeight);
|
||||
@ -728,23 +739,10 @@ public class DaoStateService implements DaoSetupService {
|
||||
// We don't care here about the unspent state
|
||||
public Stream<TxOutput> getUnlockedTxOutputsStream() {
|
||||
return getTxOutputsByTxOutputType(TxOutputType.UNLOCK_OUTPUT).stream()
|
||||
.filter(txOutput -> !isConfiscatedUnlockTxOutput(txOutput.getTxId()))
|
||||
.filter(this::isLockTimeOverForUnlockTxOutput);
|
||||
}
|
||||
|
||||
// TODO SQ
|
||||
/*public boolean isSpentByUnlockTx(TxOutput txOutput) {
|
||||
log.error("txOutput " + txOutput.getTxId());
|
||||
boolean present = getSpentInfo(txOutput)
|
||||
.map(spentInfo -> {
|
||||
log.error("spentInfo " + spentInfo);
|
||||
return getTx(spentInfo.getTxId());
|
||||
})
|
||||
.filter(Optional::isPresent)
|
||||
.isPresent();
|
||||
log.error("isSpentByUnlockTx present={}", present);
|
||||
return present;
|
||||
}*/
|
||||
|
||||
public long getTotalAmountOfUnLockedTxOutputs() {
|
||||
return getUnlockedTxOutputsStream()
|
||||
.mapToLong(TxOutput::getValue)
|
||||
@ -752,10 +750,11 @@ public class DaoStateService implements DaoSetupService {
|
||||
}
|
||||
|
||||
public long getTotalAmountOfConfiscatedTxOutputs() {
|
||||
return daoState.getConfiscatedTxOutputMap()
|
||||
.values()
|
||||
return daoState.getConfiscatedLockupTxList()
|
||||
.stream()
|
||||
.mapToLong(TxOutput::getValue)
|
||||
.map(txId -> getTx(txId))
|
||||
.filter(tx -> tx.isPresent())
|
||||
.mapToLong(tx -> tx.get().getLockupOutput().getValue())
|
||||
.sum();
|
||||
}
|
||||
|
||||
@ -766,7 +765,7 @@ public class DaoStateService implements DaoSetupService {
|
||||
TxOutput lockupTxOutput = optionalTxOutput.get();
|
||||
if (isUnspent(lockupTxOutput.getKey())) {
|
||||
log.warn("lockupTxOutput {} is still unspent. We confiscate it.", lockupTxOutput.getKey());
|
||||
confiscateBond(lockupTxOutput);
|
||||
doConfiscateBond(lockupTxId);
|
||||
} else {
|
||||
// We lookup for the unlock tx which need to be still in unlocking state
|
||||
Optional<SpentInfo> optionalSpentInfo = getSpentInfo(lockupTxOutput);
|
||||
@ -775,9 +774,7 @@ public class DaoStateService implements DaoSetupService {
|
||||
if (isUnlockingAndUnspent(unlockTxId)) {
|
||||
// We found the unlock tx is still not spend
|
||||
log.warn("lockupTxOutput {} is still unspent. We confiscate it.", lockupTxOutput.getKey());
|
||||
getUnspentUnlockingTxOutputsStream()
|
||||
.filter(txOutput -> txOutput.getTxId().equals(unlockTxId))
|
||||
.forEach(this::confiscateBond);
|
||||
doConfiscateBond(lockupTxId);
|
||||
} else {
|
||||
// We could be more radical here and confiscate the output if it is unspent but lock time is over,
|
||||
// but its probably better to stick to the rules that confiscation can only happen before lock time
|
||||
@ -791,44 +788,33 @@ public class DaoStateService implements DaoSetupService {
|
||||
}
|
||||
}
|
||||
|
||||
private void confiscateBond(TxOutput txOutput) {
|
||||
// Can be txOutput from lockup or unlock tx
|
||||
log.warn("txOutput {} added to confiscatedTxOutputMap.", txOutput.getKey());
|
||||
daoState.getConfiscatedTxOutputMap().put(txOutput.getKey(), txOutput);
|
||||
private void doConfiscateBond(String lockupTxId) {
|
||||
log.warn("TxId {} added to confiscatedLockupTxIdList.", lockupTxId);
|
||||
daoState.getConfiscatedLockupTxList().add(lockupTxId);
|
||||
}
|
||||
|
||||
public boolean isConfiscated(TxOutputKey txOutputKey) {
|
||||
return daoState.getConfiscatedTxOutputMap().containsKey(txOutputKey);
|
||||
if (isLockupOutput(txOutputKey))
|
||||
return isConfiscatedLockupTxOutput(txOutputKey.getTxId());
|
||||
else if (isUnlockOutput(txOutputKey))
|
||||
return isConfiscatedUnlockTxOutput(txOutputKey.getTxId());
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isConfiscated(String lockupTxId) {
|
||||
return daoState.getConfiscatedLockupTxList().contains(lockupTxId);
|
||||
}
|
||||
|
||||
public boolean isConfiscatedLockupTxOutput(String lockupTxId) {
|
||||
return getLockupTxOutput(lockupTxId)
|
||||
.map(lockupTxIdxOutput -> isConfiscated(lockupTxIdxOutput.getKey()))
|
||||
.orElse(false);
|
||||
return isConfiscated(lockupTxId);
|
||||
}
|
||||
|
||||
public boolean isConfiscatedUnlockTxOutput(String unlockTxId) {
|
||||
return getUnlockTxOutputs().stream()
|
||||
.filter(unlockTxOutput -> unlockTxOutput.getTxId().equals(unlockTxId))
|
||||
.map(unlockTxOutput -> isConfiscated(unlockTxOutput.getKey()))
|
||||
.findAny()
|
||||
.orElse(false);
|
||||
return getLockupTxFromUnlockTxId(unlockTxId).
|
||||
map(lockupTx -> isConfiscated(lockupTx.getId())).
|
||||
orElse(false);
|
||||
}
|
||||
|
||||
//TODO do we want to check for both txs?
|
||||
/* public boolean isConfiscatedUnlockTxOutput(String lockupTxId) {
|
||||
boolean present = getLockupTxOutput(lockupTxId)
|
||||
.flatMap(lockupTxIdxOutput -> getSpentInfo(lockupTxIdxOutput)
|
||||
.map(SpentInfo::getTxId)
|
||||
.flatMap(this::getTx)
|
||||
.map(unlockTx -> unlockTx.getTxOutputs().get(0)))
|
||||
.filter(firstTxOutput -> isConfiscated(firstTxOutput.getKey()))
|
||||
.isPresent();
|
||||
log.error("lockupTxId {}, {}", lockupTxId, present);
|
||||
//log.error("daoState.getConfiscatedTxOutputMap() {}", daoState.getConfiscatedTxOutputMap());
|
||||
return present;
|
||||
}*/
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Param
|
||||
|
@ -40,6 +40,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.Getter;
|
||||
@ -75,7 +76,7 @@ public class DaoState implements PersistablePayload {
|
||||
@Getter
|
||||
private final LinkedList<Cycle> cycles;
|
||||
|
||||
// Those maps represent mutual data which can get changed at parsing a transaction
|
||||
// These maps represent mutual data which can get changed at parsing a transaction
|
||||
@Getter
|
||||
private final Map<TxOutputKey, TxOutput> unspentTxOutputMap;
|
||||
@Getter
|
||||
@ -83,9 +84,9 @@ public class DaoState implements PersistablePayload {
|
||||
@Getter
|
||||
private final Map<TxOutputKey, SpentInfo> spentInfoMap;
|
||||
|
||||
// Those maps are related to state change triggered by voting
|
||||
// These maps are related to state change triggered by voting
|
||||
@Getter
|
||||
private final Map<TxOutputKey, TxOutput> confiscatedTxOutputMap;
|
||||
private final List<String> confiscatedLockupTxList;
|
||||
@Getter
|
||||
private final Map<String, Issuance> issuanceMap; // key is txId
|
||||
@Getter
|
||||
@ -112,7 +113,7 @@ public class DaoState implements PersistablePayload {
|
||||
new HashMap<>(),
|
||||
new HashMap<>(),
|
||||
new HashMap<>(),
|
||||
new HashMap<>(),
|
||||
new ArrayList<>(),
|
||||
new HashMap<>(),
|
||||
new ArrayList<>(),
|
||||
new ArrayList<>(),
|
||||
@ -131,7 +132,7 @@ public class DaoState implements PersistablePayload {
|
||||
Map<TxOutputKey, TxOutput> unspentTxOutputMap,
|
||||
Map<TxOutputKey, TxOutput> nonBsqTxOutputMap,
|
||||
Map<TxOutputKey, SpentInfo> spentInfoMap,
|
||||
Map<TxOutputKey, TxOutput> confiscatedTxOutputMap,
|
||||
List<String> confiscatedLockupTxList,
|
||||
Map<String, Issuance> issuanceMap,
|
||||
List<ParamChange> paramChangeList,
|
||||
List<EvaluatedProposal> evaluatedProposalList,
|
||||
@ -144,7 +145,7 @@ public class DaoState implements PersistablePayload {
|
||||
this.nonBsqTxOutputMap = nonBsqTxOutputMap;
|
||||
this.spentInfoMap = spentInfoMap;
|
||||
|
||||
this.confiscatedTxOutputMap = confiscatedTxOutputMap;
|
||||
this.confiscatedLockupTxList = confiscatedLockupTxList;
|
||||
this.issuanceMap = issuanceMap;
|
||||
this.paramChangeList = paramChangeList;
|
||||
this.evaluatedProposalList = evaluatedProposalList;
|
||||
@ -167,8 +168,7 @@ public class DaoState implements PersistablePayload {
|
||||
.collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toProtoMessage())))
|
||||
.putAllSpentInfoMap(spentInfoMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(e -> e.getKey().toString(), entry -> entry.getValue().toProtoMessage())))
|
||||
.putAllUnspentTxOutputMap(confiscatedTxOutputMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toProtoMessage())))
|
||||
.addAllConfiscatedLockupTxList(confiscatedLockupTxList)
|
||||
.putAllIssuanceMap(issuanceMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().toProtoMessage())))
|
||||
.addAllParamChangeList(paramChangeList.stream().map(ParamChange::toProtoMessage).collect(Collectors.toList()))
|
||||
@ -189,8 +189,7 @@ public class DaoState implements PersistablePayload {
|
||||
.collect(Collectors.toMap(e -> TxOutputKey.getKeyFromString(e.getKey()), e -> TxOutput.fromProto(e.getValue())));
|
||||
Map<TxOutputKey, SpentInfo> spentInfoMap = proto.getSpentInfoMapMap().entrySet().stream()
|
||||
.collect(Collectors.toMap(e -> TxOutputKey.getKeyFromString(e.getKey()), e -> SpentInfo.fromProto(e.getValue())));
|
||||
Map<TxOutputKey, TxOutput> confiscatedTxOutputMap = proto.getConfiscatedTxOutputMapMap().entrySet().stream()
|
||||
.collect(Collectors.toMap(e -> TxOutputKey.getKeyFromString(e.getKey()), e -> TxOutput.fromProto(e.getValue())));
|
||||
List<String> confiscatedLockupTxList = proto.getConfiscatedLockupTxListList();
|
||||
Map<String, Issuance> issuanceMap = proto.getIssuanceMapMap().entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> Issuance.fromProto(e.getValue())));
|
||||
List<ParamChange> paramChangeList = proto.getParamChangeListList().stream()
|
||||
@ -205,7 +204,7 @@ public class DaoState implements PersistablePayload {
|
||||
unspentTxOutputMap,
|
||||
nonBsqTxOutputMap,
|
||||
spentInfoMap,
|
||||
confiscatedTxOutputMap,
|
||||
confiscatedLockupTxList,
|
||||
issuanceMap,
|
||||
paramChangeList,
|
||||
evaluatedProposalList,
|
||||
|
Loading…
Reference in New Issue
Block a user