Complete handling of bonds for roles.

- Add BondedRoleState to reflect all diff. states.
- Show in UI correct state and button state for lockup/revoke
- Rename ProposalService classes to ProposalFactory
This commit is contained in:
Manfred Karrer 2018-11-02 16:09:53 -05:00
parent 10b14a69cc
commit 8ce8813e89
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
34 changed files with 321 additions and 249 deletions

View file

@ -42,14 +42,14 @@ import bisq.core.dao.governance.proposal.ProposalListPresentation;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.governance.proposal.compensation.CompensationConsensus; import bisq.core.dao.governance.proposal.compensation.CompensationConsensus;
import bisq.core.dao.governance.proposal.compensation.CompensationProposalService; import bisq.core.dao.governance.proposal.compensation.CompensationProposalFactory;
import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondProposalService; import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondProposalFactory;
import bisq.core.dao.governance.proposal.generic.GenericProposalService; import bisq.core.dao.governance.proposal.generic.GenericProposalFactory;
import bisq.core.dao.governance.proposal.param.ChangeParamProposalService; import bisq.core.dao.governance.proposal.param.ChangeParamProposalFactory;
import bisq.core.dao.governance.proposal.reimbursement.ReimbursementConsensus; import bisq.core.dao.governance.proposal.reimbursement.ReimbursementConsensus;
import bisq.core.dao.governance.proposal.reimbursement.ReimbursementProposalService; import bisq.core.dao.governance.proposal.reimbursement.ReimbursementProposalFactory;
import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetProposalService; import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetProposalFactory;
import bisq.core.dao.governance.proposal.role.RoleProposalService; import bisq.core.dao.governance.proposal.role.RoleProposalFactory;
import bisq.core.dao.state.DaoStateListener; import bisq.core.dao.state.DaoStateListener;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.DaoStateStorageService; import bisq.core.dao.state.DaoStateStorageService;
@ -89,6 +89,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -108,13 +109,13 @@ public class DaoFacade implements DaoSetupService {
private final PeriodService periodService; private final PeriodService periodService;
private final MyBlindVoteListService myBlindVoteListService; private final MyBlindVoteListService myBlindVoteListService;
private final MyVoteListService myVoteListService; private final MyVoteListService myVoteListService;
private final CompensationProposalService compensationProposalService; private final CompensationProposalFactory compensationProposalFactory;
private final ReimbursementProposalService reimbursementProposalService; private final ReimbursementProposalFactory reimbursementProposalFactory;
private final ChangeParamProposalService changeParamProposalService; private final ChangeParamProposalFactory changeParamProposalFactory;
private final ConfiscateBondProposalService confiscateBondProposalService; private final ConfiscateBondProposalFactory confiscateBondProposalFactory;
private final RoleProposalService roleProposalService; private final RoleProposalFactory roleProposalFactory;
private final GenericProposalService genericProposalService; private final GenericProposalFactory genericProposalFactory;
private final RemoveAssetProposalService removeAssetProposalService; private final RemoveAssetProposalFactory removeAssetProposalFactory;
private final BondedRolesService bondedRolesService; private final BondedRolesService bondedRolesService;
private final BondedReputationService bondedReputationService; private final BondedReputationService bondedReputationService;
private final LockupService lockupService; private final LockupService lockupService;
@ -132,13 +133,13 @@ public class DaoFacade implements DaoSetupService {
PeriodService periodService, PeriodService periodService,
MyBlindVoteListService myBlindVoteListService, MyBlindVoteListService myBlindVoteListService,
MyVoteListService myVoteListService, MyVoteListService myVoteListService,
CompensationProposalService compensationProposalService, CompensationProposalFactory compensationProposalFactory,
ReimbursementProposalService reimbursementProposalService, ReimbursementProposalFactory reimbursementProposalFactory,
ChangeParamProposalService changeParamProposalService, ChangeParamProposalFactory changeParamProposalFactory,
ConfiscateBondProposalService confiscateBondProposalService, ConfiscateBondProposalFactory confiscateBondProposalFactory,
RoleProposalService roleProposalService, RoleProposalFactory roleProposalFactory,
GenericProposalService genericProposalService, GenericProposalFactory genericProposalFactory,
RemoveAssetProposalService removeAssetProposalService, RemoveAssetProposalFactory removeAssetProposalFactory,
BondedRolesService bondedRolesService, BondedRolesService bondedRolesService,
BondedReputationService bondedReputationService, BondedReputationService bondedReputationService,
LockupService lockupService, LockupService lockupService,
@ -152,13 +153,13 @@ public class DaoFacade implements DaoSetupService {
this.periodService = periodService; this.periodService = periodService;
this.myBlindVoteListService = myBlindVoteListService; this.myBlindVoteListService = myBlindVoteListService;
this.myVoteListService = myVoteListService; this.myVoteListService = myVoteListService;
this.compensationProposalService = compensationProposalService; this.compensationProposalFactory = compensationProposalFactory;
this.reimbursementProposalService = reimbursementProposalService; this.reimbursementProposalFactory = reimbursementProposalFactory;
this.changeParamProposalService = changeParamProposalService; this.changeParamProposalFactory = changeParamProposalFactory;
this.confiscateBondProposalService = confiscateBondProposalService; this.confiscateBondProposalFactory = confiscateBondProposalFactory;
this.roleProposalService = roleProposalService; this.roleProposalFactory = roleProposalFactory;
this.genericProposalService = genericProposalService; this.genericProposalFactory = genericProposalFactory;
this.removeAssetProposalService = removeAssetProposalService; this.removeAssetProposalFactory = removeAssetProposalFactory;
this.bondedRolesService = bondedRolesService; this.bondedRolesService = bondedRolesService;
this.bondedReputationService = bondedReputationService; this.bondedReputationService = bondedReputationService;
this.lockupService = lockupService; this.lockupService = lockupService;
@ -229,7 +230,7 @@ public class DaoFacade implements DaoSetupService {
String link, String link,
Coin requestedBsq) Coin requestedBsq)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return compensationProposalService.createProposalWithTransaction(name, return compensationProposalFactory.createProposalWithTransaction(name,
link, link,
requestedBsq); requestedBsq);
} }
@ -238,7 +239,7 @@ public class DaoFacade implements DaoSetupService {
String link, String link,
Coin requestedBsq) Coin requestedBsq)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return reimbursementProposalService.createProposalWithTransaction(name, return reimbursementProposalFactory.createProposalWithTransaction(name,
link, link,
requestedBsq); requestedBsq);
} }
@ -248,7 +249,7 @@ public class DaoFacade implements DaoSetupService {
Param param, Param param,
String paramValue) String paramValue)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return changeParamProposalService.createProposalWithTransaction(name, return changeParamProposalFactory.createProposalWithTransaction(name,
link, link,
param, param,
paramValue); paramValue);
@ -258,31 +259,31 @@ public class DaoFacade implements DaoSetupService {
String link, String link,
byte[] hash) byte[] hash)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return confiscateBondProposalService.createProposalWithTransaction(name, return confiscateBondProposalFactory.createProposalWithTransaction(name,
link, link,
hash); hash);
} }
public ProposalWithTransaction getBondedRoleProposalWithTransaction(Role role) public ProposalWithTransaction getBondedRoleProposalWithTransaction(Role role)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return roleProposalService.createProposalWithTransaction(role); return roleProposalFactory.createProposalWithTransaction(role);
} }
public ProposalWithTransaction getGenericProposalWithTransaction(String name, public ProposalWithTransaction getGenericProposalWithTransaction(String name,
String link) String link)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return genericProposalService.createProposalWithTransaction(name, link); return genericProposalFactory.createProposalWithTransaction(name, link);
} }
public ProposalWithTransaction getRemoveAssetProposalWithTransaction(String name, public ProposalWithTransaction getRemoveAssetProposalWithTransaction(String name,
String link, String link,
Asset asset) Asset asset)
throws ValidationException, InsufficientMoneyException, TxException { throws ValidationException, InsufficientMoneyException, TxException {
return removeAssetProposalService.createProposalWithTransaction(name, link, asset); return removeAssetProposalFactory.createProposalWithTransaction(name, link, asset);
} }
public Collection<BondedRole> getBondedRoleStates() { public Collection<BondedRole> getBondedRoles() {
return bondedRolesService.getBondedRoleStates(); return bondedRolesService.getBondedRoles();
} }
public List<BondedReputation> getBondedReputationList() { public List<BondedReputation> getBondedReputationList() {
@ -487,11 +488,11 @@ public class DaoFacade implements DaoSetupService {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondWithHash bondWithHash, public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondWithHash bondWithHash,
ResultHandler resultHandler, ExceptionHandler exceptionHandler) { Consumer<String> resultHandler, ExceptionHandler exceptionHandler) {
lockupService.publishLockupTx(lockupAmount, lockTime, lockupType, bondWithHash, resultHandler, exceptionHandler); lockupService.publishLockupTx(lockupAmount, lockTime, lockupType, bondWithHash, resultHandler, exceptionHandler);
} }
public void publishUnlockTx(String lockupTxId, ResultHandler resultHandler, public void publishUnlockTx(String lockupTxId, Consumer<String> resultHandler,
ExceptionHandler exceptionHandler) { ExceptionHandler exceptionHandler) {
unlockService.publishUnlockTx(lockupTxId, resultHandler, exceptionHandler); unlockService.publishUnlockTx(lockupTxId, resultHandler, exceptionHandler);
} }
@ -656,4 +657,8 @@ public class DaoFacade implements DaoSetupService {
public void resyncDao(Runnable resultHandler) { public void resyncDao(Runnable resultHandler) {
daoStateStorageService.resetDaoState(resultHandler); daoStateStorageService.resetDaoState(resultHandler);
} }
public boolean isMyRole(Role role) {
return bondedRolesService.isMyRole(role);
}
} }

View file

@ -37,19 +37,19 @@ import bisq.core.dao.governance.proposal.MyProposalListService;
import bisq.core.dao.governance.proposal.ProposalListPresentation; import bisq.core.dao.governance.proposal.ProposalListPresentation;
import bisq.core.dao.governance.proposal.ProposalService; import bisq.core.dao.governance.proposal.ProposalService;
import bisq.core.dao.governance.proposal.ProposalValidator; import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.governance.proposal.compensation.CompensationProposalService; import bisq.core.dao.governance.proposal.compensation.CompensationProposalFactory;
import bisq.core.dao.governance.proposal.compensation.CompensationValidator; import bisq.core.dao.governance.proposal.compensation.CompensationValidator;
import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondProposalService; import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondProposalFactory;
import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondValidator; import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondValidator;
import bisq.core.dao.governance.proposal.generic.GenericProposalService; import bisq.core.dao.governance.proposal.generic.GenericProposalFactory;
import bisq.core.dao.governance.proposal.generic.GenericProposalValidator; import bisq.core.dao.governance.proposal.generic.GenericProposalValidator;
import bisq.core.dao.governance.proposal.param.ChangeParamProposalService; import bisq.core.dao.governance.proposal.param.ChangeParamProposalFactory;
import bisq.core.dao.governance.proposal.param.ChangeParamValidator; import bisq.core.dao.governance.proposal.param.ChangeParamValidator;
import bisq.core.dao.governance.proposal.reimbursement.ReimbursementProposalService; import bisq.core.dao.governance.proposal.reimbursement.ReimbursementProposalFactory;
import bisq.core.dao.governance.proposal.reimbursement.ReimbursementValidator; import bisq.core.dao.governance.proposal.reimbursement.ReimbursementValidator;
import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetProposalService; import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetProposalFactory;
import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetValidator; import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetValidator;
import bisq.core.dao.governance.proposal.role.RoleProposalService; import bisq.core.dao.governance.proposal.role.RoleProposalFactory;
import bisq.core.dao.governance.proposal.role.RoleValidator; import bisq.core.dao.governance.proposal.role.RoleValidator;
import bisq.core.dao.governance.proposal.storage.appendonly.ProposalStorageService; import bisq.core.dao.governance.proposal.storage.appendonly.ProposalStorageService;
import bisq.core.dao.governance.proposal.storage.appendonly.ProposalStore; import bisq.core.dao.governance.proposal.storage.appendonly.ProposalStore;
@ -132,25 +132,25 @@ public class DaoModule extends AppModule {
bind(ProposalValidator.class).in(Singleton.class); bind(ProposalValidator.class).in(Singleton.class);
bind(CompensationValidator.class).in(Singleton.class); bind(CompensationValidator.class).in(Singleton.class);
bind(CompensationProposalService.class).in(Singleton.class); bind(CompensationProposalFactory.class).in(Singleton.class);
bind(ReimbursementValidator.class).in(Singleton.class); bind(ReimbursementValidator.class).in(Singleton.class);
bind(ReimbursementProposalService.class).in(Singleton.class); bind(ReimbursementProposalFactory.class).in(Singleton.class);
bind(ChangeParamValidator.class).in(Singleton.class); bind(ChangeParamValidator.class).in(Singleton.class);
bind(ChangeParamProposalService.class).in(Singleton.class); bind(ChangeParamProposalFactory.class).in(Singleton.class);
bind(RoleValidator.class).in(Singleton.class); bind(RoleValidator.class).in(Singleton.class);
bind(RoleProposalService.class).in(Singleton.class); bind(RoleProposalFactory.class).in(Singleton.class);
bind(ConfiscateBondValidator.class).in(Singleton.class); bind(ConfiscateBondValidator.class).in(Singleton.class);
bind(ConfiscateBondProposalService.class).in(Singleton.class); bind(ConfiscateBondProposalFactory.class).in(Singleton.class);
bind(GenericProposalValidator.class).in(Singleton.class); bind(GenericProposalValidator.class).in(Singleton.class);
bind(GenericProposalService.class).in(Singleton.class); bind(GenericProposalFactory.class).in(Singleton.class);
bind(RemoveAssetValidator.class).in(Singleton.class); bind(RemoveAssetValidator.class).in(Singleton.class);
bind(RemoveAssetProposalService.class).in(Singleton.class); bind(RemoveAssetProposalFactory.class).in(Singleton.class);
// Ballot // Ballot

View file

@ -30,32 +30,20 @@ import javax.annotation.Nullable;
@Getter @Getter
public class BondedRole { public class BondedRole {
private final Role role; private final Role role;
@Setter
private long startDate;
// LockupTxId is null as long the bond holder has not been accepted by voting and made the lockup tx.
// It will get set after the proposal has been accepted and the lockup tx is confirmed.
@Setter @Setter
@Nullable @Nullable
private String lockupTxId; private String lockupTxId;
// Date when role has been revoked
@Setter
private long revokeDate;
@Setter @Setter
@Nullable @Nullable
private String unlockTxId; private String unlockTxId;
@Setter @Setter
private boolean isUnlocking; private long startDate;
@Setter
private long revokeDate;
@Setter
private BondedRoleState bondedRoleState = BondedRoleState.READY_FOR_LOCKUP;
BondedRole(Role role) { BondedRole(Role role) {
this.role = role; this.role = role;
} }
public boolean isLockedUp() {
return lockupTxId != null;
}
public boolean isUnlocked() {
return unlockTxId != null;
}
} }

View file

@ -0,0 +1,29 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.dao.governance.bond;
// Used in string properties ("dao.bond.bondedRoleState.*")
public enum BondedRoleState {
READY_FOR_LOCKUP, // Accepted by voting but no lockup tx made yet.
LOCKUP_TX_PENDING, // Tx broadcasted but not confirmed. Used only by tx publisher.
LOCKUP_TX_CONFIRMED,
UNLOCK_TX_PENDING, // Tx broadcasted but not confirmed. Used only by tx publisher.
UNLOCK_TX_CONFIRMED,
UNLOCKING, // lock time not expired
UNLOCKED,
}

View file

@ -17,7 +17,9 @@
package bisq.core.dao.governance.bond; package bisq.core.dao.governance.bond;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.governance.bonding.BondingConsensus; import bisq.core.dao.governance.bonding.BondingConsensus;
import bisq.core.dao.governance.bonding.bond.BondWithHash;
import bisq.core.dao.state.DaoStateListener; import bisq.core.dao.state.DaoStateListener;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.BaseTxOutput; import bisq.core.dao.state.model.blockchain.BaseTxOutput;
@ -25,9 +27,15 @@ import bisq.core.dao.state.model.blockchain.Block;
import bisq.core.dao.state.model.blockchain.SpentInfo; import bisq.core.dao.state.model.blockchain.SpentInfo;
import bisq.core.dao.state.model.blockchain.TxType; import bisq.core.dao.state.model.blockchain.TxType;
import bisq.core.dao.state.model.governance.BondedRoleType; import bisq.core.dao.state.model.governance.BondedRoleType;
import bisq.core.dao.state.model.governance.Proposal;
import bisq.core.dao.state.model.governance.Role; import bisq.core.dao.state.model.governance.Role;
import bisq.core.dao.state.model.governance.RoleProposal; import bisq.core.dao.state.model.governance.RoleProposal;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Arrays; import java.util.Arrays;
@ -35,7 +43,9 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -49,9 +59,10 @@ import static com.google.common.base.Preconditions.checkArgument;
@Slf4j @Slf4j
public class BondedRolesService implements DaoStateListener { public class BondedRolesService implements DaoStateListener {
private final DaoStateService daoStateService; private final DaoStateService daoStateService;
private final BsqWalletService bsqWalletService;
// This map is just for convenience. The data which are used to fill the map are store din the DaoState (role, txs). // This map is just for convenience. The data which are used to fill the map are store din the DaoState (role, txs).
private final Map<String, BondedRole> bondedRoleStateMap = new HashMap<>(); private final Map<String, BondedRole> bondedRoleByRoleUidMap = new HashMap<>();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -59,8 +70,9 @@ public class BondedRolesService implements DaoStateListener {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public BondedRolesService(DaoStateService daoStateService) { public BondedRolesService(DaoStateService daoStateService, BsqWalletService bsqWalletService) {
this.daoStateService = daoStateService; this.daoStateService = daoStateService;
this.bsqWalletService = bsqWalletService;
daoStateService.addBsqStateListener(this); daoStateService.addBsqStateListener(this);
} }
@ -78,8 +90,8 @@ public class BondedRolesService implements DaoStateListener {
public void onParseTxsComplete(Block block) { public void onParseTxsComplete(Block block) {
// TODO optimize to not re-write the whole map at each block // TODO optimize to not re-write the whole map at each block
getBondedRoleStream().forEach(bondedRole -> { getBondedRoleStream().forEach(bondedRole -> {
bondedRoleStateMap.putIfAbsent(bondedRole.getUid(), new BondedRole(bondedRole)); bondedRoleByRoleUidMap.putIfAbsent(bondedRole.getUid(), new BondedRole(bondedRole));
BondedRole bondedRoleState = bondedRoleStateMap.get(bondedRole.getUid()); BondedRole bondedRoleState = bondedRoleByRoleUidMap.get(bondedRole.getUid());
// Lets see if we have a lock up tx. // Lets see if we have a lock up tx.
daoStateService.getLockupTxOutputs().forEach(lockupTxOutput -> { daoStateService.getLockupTxOutputs().forEach(lockupTxOutput -> {
@ -94,17 +106,10 @@ public class BondedRolesService implements DaoStateListener {
byte[] hash = BondingConsensus.getHashFromOpReturnData(opReturnData); byte[] hash = BondingConsensus.getHashFromOpReturnData(opReturnData);
Optional<Role> candidate = getBondedRoleFromHash(hash); Optional<Role> candidate = getBondedRoleFromHash(hash);
if (candidate.isPresent() && bondedRole.equals(candidate.get())) { if (candidate.isPresent() && bondedRole.equals(candidate.get())) {
if (bondedRoleState.getLockupTxId() == null) { bondedRoleState.setBondedRoleState(BondedRoleState.LOCKUP_TX_CONFIRMED);
bondedRoleState.setLockupTxId(lockupTxId); bondedRoleState.setLockupTxId(lockupTxId);
// We use the tx time as we want to have a unique time for all users // We use the tx time as we want to have a unique time for all users
bondedRoleState.setStartDate(lockupTx.getTime()); bondedRoleState.setStartDate(lockupTx.getTime());
} else {
checkArgument(bondedRoleState.getLockupTxId().equals(lockupTxId),
"We have already the lockup tx set in bondedRoleState " +
"but it is different to the one we found in the daoState transactions. " +
"That should not happen. bondedRole={}, bondedRoleState={}",
bondedRole, bondedRoleState);
}
if (!daoStateService.isUnspent(lockupTxOutput.getKey())) { if (!daoStateService.isUnspent(lockupTxOutput.getKey())) {
// Lockup is already spent (in unlock tx) // Lockup is already spent (in unlock tx)
@ -115,26 +120,24 @@ public class BondedRolesService implements DaoStateListener {
.ifPresent(unlockTx -> { .ifPresent(unlockTx -> {
// cross check if it is in daoStateService.getUnlockTxOutputs() ? // cross check if it is in daoStateService.getUnlockTxOutputs() ?
String unlockTxId = unlockTx.getId(); String unlockTxId = unlockTx.getId();
if (bondedRoleState.getUnlockTxId() == null) {
bondedRoleState.setUnlockTxId(unlockTxId); bondedRoleState.setUnlockTxId(unlockTxId);
bondedRoleState.setBondedRoleState(BondedRoleState.UNLOCK_TX_CONFIRMED);
bondedRoleState.setRevokeDate(unlockTx.getTime()); bondedRoleState.setRevokeDate(unlockTx.getTime());
bondedRoleState.setUnlocking(daoStateService.isUnlocking(unlockTxId)); boolean unlocking = daoStateService.isUnlocking(unlockTxId);
//TODO after locktime set to false or maybe better use states for lock state if (unlocking) {
bondedRoleState.setBondedRoleState(BondedRoleState.UNLOCKING);
} else { } else {
checkArgument(bondedRoleState.getUnlockTxId().equals(unlockTxId), bondedRoleState.setBondedRoleState(BondedRoleState.UNLOCKED);
"We have already the unlock tx set in bondedRoleState " +
"but it is different to the one we found in the daoState transactions. " +
"That should not happen. bondedRole={}, bondedRoleState={}",
bondedRole, bondedRoleState);
} }
});
}
}
});
});
});
// TODO check lock time updateBondedRoleStateFromUnconfirmedLockupTxs();
}); updateBondedRoleStateFromUnconfirmedUnlockTxs();
}
}
});
});
});
} }
@ -155,8 +158,8 @@ public class BondedRolesService implements DaoStateListener {
return getBondedRoleStream().collect(Collectors.toList()); return getBondedRoleStream().collect(Collectors.toList());
} }
public Collection<BondedRole> getBondedRoleStates() { public Collection<BondedRole> getBondedRoles() {
return bondedRoleStateMap.values(); return bondedRoleByRoleUidMap.values();
} }
// bonded roles which are active and can be confiscated // bonded roles which are active and can be confiscated
@ -165,6 +168,46 @@ public class BondedRolesService implements DaoStateListener {
return getBondedRoleList(); return getBondedRoleList();
} }
private void updateBondedRoleStateFromUnconfirmedLockupTxs() {
getBondedRoleStream().filter(this::isLockupTxUnconfirmed)
.map(role -> bondedRoleByRoleUidMap.get(role.getUid()))
.filter(bondedRole -> bondedRole.getBondedRoleState() == BondedRoleState.READY_FOR_LOCKUP)
.forEach(bondedRole -> bondedRole.setBondedRoleState(BondedRoleState.LOCKUP_TX_PENDING));
}
private void updateBondedRoleStateFromUnconfirmedUnlockTxs() {
getBondedRoleStream().filter(this::isUnlockTxUnconfirmed)
.map(role -> bondedRoleByRoleUidMap.get(role.getUid()))
.filter(bondedRole -> bondedRole.getBondedRoleState() == BondedRoleState.LOCKUP_TX_CONFIRMED)
.forEach(bondedRole -> bondedRole.setBondedRoleState(BondedRoleState.UNLOCK_TX_PENDING));
}
private boolean isLockupTxUnconfirmed(BondWithHash bondWithHash) {
return bsqWalletService.getWalletTransactions().stream()
.filter(transaction -> transaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING)
.map(transaction -> transaction.getOutputs().get(transaction.getOutputs().size() - 1))
.filter(lastOutput -> lastOutput.getScriptPubKey().isOpReturn())
.map(lastOutput -> lastOutput.getScriptPubKey().getChunks())
.filter(chunks -> chunks.size() > 1)
.map(chunks -> chunks.get(1).data)
.anyMatch(data -> Arrays.equals(BondingConsensus.getHashFromOpReturnData(data), bondWithHash.getHash()));
}
private boolean isUnlockTxUnconfirmed(BondWithHash bondWithHash) {
return bsqWalletService.getWalletTransactions().stream()
.filter(transaction -> transaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING)
.filter(transaction -> transaction.getInputs().size() > 1)
.map(transaction -> transaction.getInputs().get(0))
.map(TransactionInput::getConnectedOutput)
.filter(Objects::nonNull)
.map(TransactionOutput::getParentTransaction)
.filter(Objects::nonNull)
.map(Transaction::getHashAsString)
.flatMap(lockupTxId -> daoStateService.getLockupOpReturnTxOutput(lockupTxId).stream())
.map(BaseTxOutput::getOpReturnData)
.anyMatch(data -> Arrays.equals(BondingConsensus.getHashFromOpReturnData(data), bondWithHash.getHash()));
}
public Optional<Role> getBondedRoleFromHash(byte[] hash) { public Optional<Role> getBondedRoleFromHash(byte[] hash) {
return getBondedRoleStream() return getBondedRoleStream()
.filter(bondedRole -> { .filter(bondedRole -> {
@ -180,7 +223,7 @@ public class BondedRolesService implements DaoStateListener {
} }
public Optional<BondedRole> getBondedRoleStateFromLockupTxId(String lockupTxId) { public Optional<BondedRole> getBondedRoleStateFromLockupTxId(String lockupTxId) {
return bondedRoleStateMap.values().stream() return bondedRoleByRoleUidMap.values().stream()
.filter(bondedRoleState -> lockupTxId.equals(bondedRoleState.getLockupTxId())) .filter(bondedRoleState -> lockupTxId.equals(bondedRoleState.getLockupTxId()))
.findAny(); .findAny();
} }
@ -204,32 +247,25 @@ public class BondedRolesService implements DaoStateListener {
.map(e -> ((RoleProposal) e.getProposal()).getRole()); .map(e -> ((RoleProposal) e.getProposal()).getRole());
} }
private Stream<RoleProposal> getBondedRoleProposalStream() {
private Optional<byte[]> getOpReturnData(String lockUpTxId) { return daoStateService.getEvaluatedProposalList().stream()
return daoStateService.getLockupOpReturnTxOutput(lockUpTxId).map(BaseTxOutput::getOpReturnData); .filter(evaluatedProposal -> evaluatedProposal.getProposal() instanceof RoleProposal)
.map(e -> ((RoleProposal) e.getProposal()));
} }
public boolean wasRoleAlreadyBonded(Role role) { public boolean wasRoleAlreadyBonded(Role role) {
BondedRole bondedRole = bondedRoleStateMap.get(role.getUid()); BondedRole bondedRole = bondedRoleByRoleUidMap.get(role.getUid());
return bondedRole != null && bondedRole.getLockupTxId() != null; checkArgument(bondedRole != null, "bondedRole must not be null");
return bondedRole.getLockupTxId() != null;
} }
public boolean isMyRole(Role role) {
/* private Optional<LockupType> getOptionalLockupType(String lockUpTxId) { Set<String> myWalletTransactionIds = bsqWalletService.getWalletTransactions().stream()
return getOpReturnData(lockUpTxId) .map(Transaction::getHashAsString)
.flatMap(BondingConsensus::getLockupType); .collect(Collectors.toSet());
}*/ return getBondedRoleProposalStream()
.filter(roleProposal -> roleProposal.getRole().equals(role))
/*public static Optional<Role> getBondedRoleByLockupTxId(String lockupTxId) { .map(Proposal::getTxId)
return bondedRoles.stream() .anyMatch(myWalletTransactionIds::contains);
.filter(bondedRole -> bondedRole.getLockupTxId().equals(lockupTxId)). }
findAny();
}*/
/*
public static Optional<Role> getBondedRoleByHashOfBondId(byte[] hash) {
return Optional.empty();
*//* bondedRoles.stream()
.filter(bondedRole -> Arrays.equals(bondedRole.getHash(), hash))
.findAny();*//*
}*/
} }

View file

@ -31,7 +31,6 @@ import bisq.core.dao.governance.bonding.bond.BondWithHash;
import bisq.core.dao.state.model.governance.Role; import bisq.core.dao.state.model.governance.Role;
import bisq.common.handlers.ExceptionHandler; import bisq.common.handlers.ExceptionHandler;
import bisq.common.handlers.ResultHandler;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException; import org.bitcoinj.core.InsufficientMoneyException;
@ -41,6 +40,8 @@ import javax.inject.Inject;
import java.io.IOException; import java.io.IOException;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
@ -69,10 +70,9 @@ public class LockupService {
} }
public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondWithHash bondWithHash, public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondWithHash bondWithHash,
ResultHandler resultHandler, ExceptionHandler exceptionHandler) { Consumer<String> resultHandler, ExceptionHandler exceptionHandler) {
checkArgument(lockTime <= BondingConsensus.getMaxLockTime() && checkArgument(lockTime <= BondingConsensus.getMaxLockTime() &&
lockTime >= BondingConsensus.getMinLockTime(), "lockTime not in rage"); lockTime >= BondingConsensus.getMinLockTime(), "lockTime not in rage");
if (bondWithHash instanceof Role) { if (bondWithHash instanceof Role) {
Role role = (Role) bondWithHash; Role role = (Role) bondWithHash;
if (bondedRolesService.wasRoleAlreadyBonded(role)) { if (bondedRolesService.wasRoleAlreadyBonded(role)) {
@ -81,17 +81,16 @@ public class LockupService {
} }
} }
try {
byte[] hash = BondingConsensus.getHash(bondWithHash); byte[] hash = BondingConsensus.getHash(bondWithHash);
try {
byte[] opReturnData = BondingConsensus.getLockupOpReturnData(lockTime, lockupType, hash); byte[] opReturnData = BondingConsensus.getLockupOpReturnData(lockTime, lockupType, hash);
final Transaction lockupTx = getLockupTx(lockupAmount, opReturnData); final Transaction lockupTx = createLockupTx(lockupAmount, opReturnData);
//noinspection Duplicates //noinspection Duplicates
walletsManager.publishAndCommitBsqTx(lockupTx, new TxBroadcaster.Callback() { walletsManager.publishAndCommitBsqTx(lockupTx, new TxBroadcaster.Callback() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {
resultHandler.handleResult(); resultHandler.accept(transaction.getHashAsString());
} }
@Override @Override
@ -111,7 +110,7 @@ public class LockupService {
} }
} }
private Transaction getLockupTx(Coin lockupAmount, byte[] opReturnData) private Transaction createLockupTx(Coin lockupAmount, byte[] opReturnData)
throws InsufficientMoneyException, WalletException, TransactionVerificationException { throws InsufficientMoneyException, WalletException, TransactionVerificationException {
Transaction preparedTx = bsqWalletService.getPreparedLockupTx(lockupAmount); Transaction preparedTx = bsqWalletService.getPreparedLockupTx(lockupAmount);
Transaction txWithBtcFee = btcWalletService.completePreparedBsqTx(preparedTx, true, opReturnData); Transaction txWithBtcFee = btcWalletService.completePreparedBsqTx(preparedTx, true, opReturnData);

View file

@ -29,13 +29,14 @@ import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.TxOutput; import bisq.core.dao.state.model.blockchain.TxOutput;
import bisq.common.handlers.ExceptionHandler; import bisq.common.handlers.ExceptionHandler;
import bisq.common.handlers.ResultHandler;
import org.bitcoinj.core.InsufficientMoneyException; import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@ -61,7 +62,7 @@ public class UnlockService {
this.daoStateService = daoStateService; this.daoStateService = daoStateService;
} }
public void publishUnlockTx(String lockupTxId, ResultHandler resultHandler, public void publishUnlockTx(String lockupTxId, Consumer<String> resultHandler,
ExceptionHandler exceptionHandler) { ExceptionHandler exceptionHandler) {
try { try {
TxOutput lockupTxOutput = daoStateService.getLockupTxOutput(lockupTxId).get(); TxOutput lockupTxOutput = daoStateService.getLockupTxOutput(lockupTxId).get();
@ -71,7 +72,7 @@ public class UnlockService {
walletsManager.publishAndCommitBsqTx(unlockTx, new TxBroadcaster.Callback() { walletsManager.publishAndCommitBsqTx(unlockTx, new TxBroadcaster.Callback() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {
resultHandler.handleResult(); resultHandler.accept(transaction.getHashAsString());
} }
@Override @Override

View file

@ -37,10 +37,11 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
* Base class for proposalService classes. Provides creation of a transaction. * Base class for proposalFactory classes. Provides creation of a transaction. Proposal creation is delegated to
* concrete classes.
*/ */
@Slf4j @Slf4j
public abstract class BaseProposalService<R extends Proposal> { public abstract class BaseProposalFactory<R extends Proposal> {
protected final BsqWalletService bsqWalletService; protected final BsqWalletService bsqWalletService;
protected final BtcWalletService btcWalletService; protected final BtcWalletService btcWalletService;
protected final DaoStateService daoStateService; protected final DaoStateService daoStateService;
@ -55,7 +56,7 @@ public abstract class BaseProposalService<R extends Proposal> {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public BaseProposalService(BsqWalletService bsqWalletService, public BaseProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
ProposalValidator proposalValidator) { ProposalValidator proposalValidator) {

View file

@ -22,7 +22,7 @@ import bisq.core.btc.exceptions.WalletException;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalConsensus; import bisq.core.dao.governance.proposal.ProposalConsensus;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
@ -45,13 +45,13 @@ import lombok.extern.slf4j.Slf4j;
* Creates the CompensationProposal and the transaction. * Creates the CompensationProposal and the transaction.
*/ */
@Slf4j @Slf4j
public class CompensationProposalService extends BaseProposalService<CompensationProposal> { public class CompensationProposalFactory extends BaseProposalFactory<CompensationProposal> {
private Coin requestedBsq; private Coin requestedBsq;
private String bsqAddress; private String bsqAddress;
@Inject @Inject
public CompensationProposalService(BsqWalletService bsqWalletService, public CompensationProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
CompensationValidator proposalValidator) { CompensationValidator proposalValidator) {

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal.confiscatebond;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
@ -36,7 +36,7 @@ import lombok.extern.slf4j.Slf4j;
* Creates ConfiscateBondProposal and transaction. * Creates ConfiscateBondProposal and transaction.
*/ */
@Slf4j @Slf4j
public class ConfiscateBondProposalService extends BaseProposalService<ConfiscateBondProposal> { public class ConfiscateBondProposalFactory extends BaseProposalFactory<ConfiscateBondProposal> {
private byte[] hash; private byte[] hash;
@ -45,7 +45,7 @@ public class ConfiscateBondProposalService extends BaseProposalService<Confiscat
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public ConfiscateBondProposalService(BsqWalletService bsqWalletService, public ConfiscateBondProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
ConfiscateBondValidator proposalValidator) { ConfiscateBondValidator proposalValidator) {

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal.generic;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
@ -36,7 +36,7 @@ import lombok.extern.slf4j.Slf4j;
* Creates GenericProposal and transaction. * Creates GenericProposal and transaction.
*/ */
@Slf4j @Slf4j
public class GenericProposalService extends BaseProposalService<GenericProposal> { public class GenericProposalFactory extends BaseProposalFactory<GenericProposal> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -44,7 +44,7 @@ public class GenericProposalService extends BaseProposalService<GenericProposal>
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public GenericProposalService(BsqWalletService bsqWalletService, public GenericProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
GenericProposalValidator proposalValidator) { GenericProposalValidator proposalValidator) {

View file

@ -21,7 +21,7 @@ import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.param.Param; import bisq.core.dao.governance.param.Param;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
@ -37,7 +37,7 @@ import lombok.extern.slf4j.Slf4j;
* Creates ChangeParamProposal and transaction. * Creates ChangeParamProposal and transaction.
*/ */
@Slf4j @Slf4j
public class ChangeParamProposalService extends BaseProposalService<ChangeParamProposal> { public class ChangeParamProposalFactory extends BaseProposalFactory<ChangeParamProposal> {
private Param param; private Param param;
private String paramValue; private String paramValue;
@ -47,7 +47,7 @@ public class ChangeParamProposalService extends BaseProposalService<ChangeParamP
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public ChangeParamProposalService(BsqWalletService bsqWalletService, public ChangeParamProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
ChangeParamValidator proposalValidator) { ChangeParamValidator proposalValidator) {

View file

@ -22,7 +22,7 @@ import bisq.core.btc.exceptions.WalletException;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalConsensus; import bisq.core.dao.governance.proposal.ProposalConsensus;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
@ -45,13 +45,13 @@ import lombok.extern.slf4j.Slf4j;
* Creates the ReimbursementProposal and the transaction. * Creates the ReimbursementProposal and the transaction.
*/ */
@Slf4j @Slf4j
public class ReimbursementProposalService extends BaseProposalService<ReimbursementProposal> { public class ReimbursementProposalFactory extends BaseProposalFactory<ReimbursementProposal> {
private Coin requestedBsq; private Coin requestedBsq;
private String bsqAddress; private String bsqAddress;
@Inject @Inject
public ReimbursementProposalService(BsqWalletService bsqWalletService, public ReimbursementProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
ReimbursementValidator proposalValidator) { ReimbursementValidator proposalValidator) {

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal.removeAsset;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
@ -38,7 +38,7 @@ import lombok.extern.slf4j.Slf4j;
* Creates RemoveAssetProposal and transaction. * Creates RemoveAssetProposal and transaction.
*/ */
@Slf4j @Slf4j
public class RemoveAssetProposalService extends BaseProposalService<RemoveAssetProposal> { public class RemoveAssetProposalFactory extends BaseProposalFactory<RemoveAssetProposal> {
private Asset asset; private Asset asset;
@ -47,7 +47,7 @@ public class RemoveAssetProposalService extends BaseProposalService<RemoveAssetP
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public RemoveAssetProposalService(BsqWalletService bsqWalletService, public RemoveAssetProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
RemoveAssetValidator proposalValidator) { RemoveAssetValidator proposalValidator) {

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal.role;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.exceptions.ValidationException; import bisq.core.dao.exceptions.ValidationException;
import bisq.core.dao.governance.proposal.BaseProposalService; import bisq.core.dao.governance.proposal.BaseProposalFactory;
import bisq.core.dao.governance.proposal.ProposalWithTransaction; import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException; import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
@ -37,7 +37,7 @@ import lombok.extern.slf4j.Slf4j;
* Creates RoleProposal and transaction. * Creates RoleProposal and transaction.
*/ */
@Slf4j @Slf4j
public class RoleProposalService extends BaseProposalService<RoleProposal> { public class RoleProposalFactory extends BaseProposalFactory<RoleProposal> {
private Role role; private Role role;
@ -46,7 +46,7 @@ public class RoleProposalService extends BaseProposalService<RoleProposal> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public RoleProposalService(BsqWalletService bsqWalletService, public RoleProposalFactory(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
DaoStateService daoStateService, DaoStateService daoStateService,
RoleValidator proposalValidator) { RoleValidator proposalValidator) {

View file

@ -687,7 +687,11 @@ public class DaoStateService implements DaoSetupService {
return opTxOutput.isPresent() && isUnlockingOutput(opTxOutput.get()); return opTxOutput.isPresent() && isUnlockingOutput(opTxOutput.get());
} }
// TODO SQ i changed the code here. i think it was wrong before public boolean isUnlocking(String unlockTxId) {
Optional<Tx> optionalTx = getTx(unlockTxId);
return optionalTx.isPresent() && isUnlockingOutput(optionalTx.get().getTxOutputs().get(0));
}
public boolean isUnlockingOutput(TxOutput unlockTxOutput) { public boolean isUnlockingOutput(TxOutput unlockTxOutput) {
return unlockTxOutput.getTxOutputType() == TxOutputType.UNLOCK_OUTPUT && return unlockTxOutput.getTxOutputType() == TxOutputType.UNLOCK_OUTPUT &&
!isLockTimeOverForUnlockTxOutput(unlockTxOutput); !isLockTimeOverForUnlockTxOutput(unlockTxOutput);
@ -756,11 +760,6 @@ public class DaoStateService implements DaoSetupService {
// txOutput.setTxOutputType(TxOutputType.BTC_OUTPUT); // txOutput.setTxOutputType(TxOutputType.BTC_OUTPUT);
} }
public boolean isUnlocking(String unlockTxId) {
Optional<Tx> optionalTx = getTx(unlockTxId);
return optionalTx.isPresent() && isUnlockingOutput(optionalTx.get().getTxOutputs().get(0));
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Param // Param

View file

@ -1382,7 +1382,7 @@ dao.bond.bondedReputation=Bonded Reputation
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Name dao.bond.table.column.header.name=Name
dao.bond.table.column.header.linkToAccount=Account dao.bond.table.column.header.link=Link
dao.bond.table.column.header.bondedRoleType=Role dao.bond.table.column.header.bondedRoleType=Role
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID
@ -1397,6 +1397,21 @@ dao.bond.table.lockedUp=Bond locked up
dao.bond.table.unlocking=Bond unlocking dao.bond.table.unlocking=Bond unlocking
dao.bond.table.unlocked=Bond unlocked dao.bond.table.unlocked=Bond unlocked
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.READY_FOR_LOCKUP=Not bonded yet
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.LOCKUP_TX_PENDING=Lockup pending
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.LOCKUP_TX_CONFIRMED=Bond locked up
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.UNLOCK_TX_PENDING=Unlock pending
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.UNLOCK_TX_CONFIRMED=Unlock tx confirmed
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.UNLOCKING=Bond unlocking
# suppress inspection "UnusedProperty"
dao.bond.bondedRoleState.UNLOCKED=Bond unlocked
# suppress inspection "UnusedProperty" # suppress inspection "UnusedProperty"
dao.phase.UNDEFINED=Undefined dao.phase.UNDEFINED=Undefined
# suppress inspection "UnusedProperty" # suppress inspection "UnusedProperty"

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} Blöcke
dao.bond.table.header=Gekoppelte Rollen dao.bond.table.header=Gekoppelte Rollen
dao.bond.table.column.header.name=Name dao.bond.table.column.header.name=Name
dao.bond.table.column.header.linkToAccount=Konto dao.bond.table.column.header.link=Konto
dao.bond.table.column.header.bondedRoleType=Rolle dao.bond.table.column.header.bondedRoleType=Rolle
dao.bond.table.column.header.startDate=Gestartet dao.bond.table.column.header.startDate=Gestartet
dao.bond.table.column.header.lockupTxId=Sperrung Tx ID dao.bond.table.column.header.lockupTxId=Sperrung Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Όνομα dao.bond.table.column.header.name=Όνομα
dao.bond.table.column.header.linkToAccount=Λογαριασμός dao.bond.table.column.header.link=Λογαριασμός
dao.bond.table.column.header.bondedRoleType=Ρόλος dao.bond.table.column.header.bondedRoleType=Ρόλος
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Nombre dao.bond.table.column.header.name=Nombre
dao.bond.table.column.header.linkToAccount=Cuenta dao.bond.table.column.header.link=Cuenta
dao.bond.table.column.header.bondedRoleType=Rol dao.bond.table.column.header.bondedRoleType=Rol
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=نام dao.bond.table.column.header.name=نام
dao.bond.table.column.header.linkToAccount=حساب dao.bond.table.column.header.link=حساب
dao.bond.table.column.header.bondedRoleType=نقش dao.bond.table.column.header.bondedRoleType=نقش
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Név dao.bond.table.column.header.name=Név
dao.bond.table.column.header.linkToAccount=Fiók dao.bond.table.column.header.link=Fiók
dao.bond.table.column.header.bondedRoleType=Szerep dao.bond.table.column.header.bondedRoleType=Szerep
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Nome dao.bond.table.column.header.name=Nome
dao.bond.table.column.header.linkToAccount=Conta dao.bond.table.column.header.link=Conta
dao.bond.table.column.header.bondedRoleType=Função dao.bond.table.column.header.bondedRoleType=Função
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Nume dao.bond.table.column.header.name=Nume
dao.bond.table.column.header.linkToAccount=Cont dao.bond.table.column.header.link=Cont
dao.bond.table.column.header.bondedRoleType=Rol dao.bond.table.column.header.bondedRoleType=Rol
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} блоков
dao.bond.table.header=Обеспеченные роли dao.bond.table.header=Обеспеченные роли
dao.bond.table.column.header.name=Имя dao.bond.table.column.header.name=Имя
dao.bond.table.column.header.linkToAccount=Счёт dao.bond.table.column.header.link=Счёт
dao.bond.table.column.header.bondedRoleType=Роль dao.bond.table.column.header.bondedRoleType=Роль
dao.bond.table.column.header.startDate=Начато dao.bond.table.column.header.startDate=Начато
dao.bond.table.column.header.lockupTxId=Транз. идент. блокировки dao.bond.table.column.header.lockupTxId=Транз. идент. блокировки

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Ime dao.bond.table.column.header.name=Ime
dao.bond.table.column.header.linkToAccount=Nalog dao.bond.table.column.header.link=Nalog
dao.bond.table.column.header.bondedRoleType=Uloga dao.bond.table.column.header.bondedRoleType=Uloga
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=ชื่อ dao.bond.table.column.header.name=ชื่อ
dao.bond.table.column.header.linkToAccount=บัญชี dao.bond.table.column.header.link=บัญชี
dao.bond.table.column.header.bondedRoleType=บทบาท dao.bond.table.column.header.bondedRoleType=บทบาท
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=Tên dao.bond.table.column.header.name=Tên
dao.bond.table.column.header.linkToAccount=Tài khoản dao.bond.table.column.header.link=Tài khoản
dao.bond.table.column.header.bondedRoleType=Vai trò dao.bond.table.column.header.bondedRoleType=Vai trò
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -1163,7 +1163,7 @@ dao.bond.bondedRoleType.details.blocks={0} blocks
dao.bond.table.header=Bonded roles dao.bond.table.header=Bonded roles
dao.bond.table.column.header.name=名称 dao.bond.table.column.header.name=名称
dao.bond.table.column.header.linkToAccount=账户 dao.bond.table.column.header.link=账户
dao.bond.table.column.header.bondedRoleType=角色 dao.bond.table.column.header.bondedRoleType=角色
dao.bond.table.column.header.startDate=Started dao.bond.table.column.header.startDate=Started
dao.bond.table.column.header.lockupTxId=Lockup Tx ID dao.bond.table.column.header.lockupTxId=Lockup Tx ID

View file

@ -38,7 +38,6 @@ import bisq.core.util.BsqFormatter;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import bisq.common.app.DevEnv; import bisq.common.app.DevEnv;
import bisq.common.handlers.ResultHandler;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException; import org.bitcoinj.core.InsufficientMoneyException;
@ -46,9 +45,12 @@ import org.bitcoinj.core.InsufficientMoneyException;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkArgument;
@Slf4j @Slf4j
public class BondingViewUtils { public class BondingViewUtils {
@ -69,7 +71,7 @@ public class BondingViewUtils {
} }
private void lockupBond(BondWithHash bondWithHash, Coin lockupAmount, int lockupTime, LockupType lockupType, private void lockupBond(BondWithHash bondWithHash, Coin lockupAmount, int lockupTime, LockupType lockupType,
ResultHandler resultHandler) { Consumer<String> resultHandler) {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) { if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
if (!DevEnv.isDevMode()) { if (!DevEnv.isDevMode()) {
new Popup<>().headLine(Res.get("dao.bonding.lock.sendFunds.headline")) new Popup<>().headLine(Res.get("dao.bonding.lock.sendFunds.headline"))
@ -89,41 +91,38 @@ public class BondingViewUtils {
} }
} }
private void publishLockupTx(BondWithHash bondWithHash, Coin lockupAmount, int lockupTime, LockupType lockupType, ResultHandler resultHandler) { private void publishLockupTx(BondWithHash bondWithHash, Coin lockupAmount, int lockupTime, LockupType lockupType, Consumer<String> resultHandler) {
daoFacade.publishLockupTx(lockupAmount, daoFacade.publishLockupTx(lockupAmount,
lockupTime, lockupTime,
lockupType, lockupType,
bondWithHash, bondWithHash,
() -> { txId -> {
if (!DevEnv.isDevMode()) if (!DevEnv.isDevMode())
new Popup<>().feedback(Res.get("dao.tx.published.success")).show(); new Popup<>().feedback(Res.get("dao.tx.published.success")).show();
if (resultHandler != null)
resultHandler.accept(txId);
}, },
this::handleError this::handleError
); );
if (resultHandler != null)
resultHandler.handleResult();
} }
public void lockupBondForBondedRole(Role role, ResultHandler resultHandler) { public void lockupBondForBondedRole(Role role, Consumer<String> resultHandler) {
BondedRoleType bondedRoleType = role.getBondedRoleType(); BondedRoleType bondedRoleType = role.getBondedRoleType();
Coin lockupAmount = Coin.valueOf(bondedRoleType.getRequiredBond()); Coin lockupAmount = Coin.valueOf(bondedRoleType.getRequiredBond());
int lockupTime = bondedRoleType.getUnlockTimeInBlocks(); int lockupTime = bondedRoleType.getUnlockTimeInBlocks();
lockupBond(role, lockupAmount, lockupTime, LockupType.BONDED_ROLE, resultHandler); lockupBond(role, lockupAmount, lockupTime, LockupType.BONDED_ROLE, resultHandler);
} }
public void lockupBondForReputation(Coin lockupAmount, int lockupTime, ResultHandler resultHandler) { public void lockupBondForReputation(Coin lockupAmount, int lockupTime, Consumer<String> resultHandler) {
BondedReputation bondedReputation = BondedReputation.createBondedReputation(); BondedReputation bondedReputation = BondedReputation.createBondedReputation();
lockupBond(bondedReputation, lockupAmount, lockupTime, LockupType.REPUTATION, resultHandler); lockupBond(bondedReputation, lockupAmount, lockupTime, LockupType.REPUTATION, resultHandler);
} }
public void unLock(String lockupTxId, ResultHandler resultHandler) { public void unLock(String lockupTxId, Consumer<String> resultHandler) {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) { if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
Optional<TxOutput> lockupTxOutput = daoFacade.getLockupTxOutput(lockupTxId); Optional<TxOutput> lockupTxOutput = daoFacade.getLockupTxOutput(lockupTxId);
if (!lockupTxOutput.isPresent()) { checkArgument(lockupTxOutput.isPresent(), "Lockup output must be present. TxId=" + lockupTxId);
log.warn("Lockup output not found, txId = ", lockupTxId);
return;
}
Coin unlockAmount = Coin.valueOf(lockupTxOutput.get().getValue()); Coin unlockAmount = Coin.valueOf(lockupTxOutput.get().getValue());
Optional<Integer> opLockTime = daoFacade.getLockTime(lockupTxId); Optional<Integer> opLockTime = daoFacade.getLockTime(lockupTxId);
int lockTime = opLockTime.orElse(-1); int lockTime = opLockTime.orElse(-1);
@ -153,13 +152,14 @@ public class BondingViewUtils {
log.info("unlock tx: {}", lockupTxId); log.info("unlock tx: {}", lockupTxId);
} }
private void publishUnlockTx(String lockupTxId, ResultHandler resultHandler) { private void publishUnlockTx(String lockupTxId, Consumer<String> resultHandler) {
daoFacade.publishUnlockTx(lockupTxId, daoFacade.publishUnlockTx(lockupTxId,
() -> { txId -> {
if (!DevEnv.isDevMode()) if (!DevEnv.isDevMode())
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show(); new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
resultHandler.handleResult(); if (resultHandler != null)
resultHandler.accept(txId);
}, },
errorMessage -> new Popup<>().warning(errorMessage.toString()).show() errorMessage -> new Popup<>().warning(errorMessage.toString()).show()
); );

View file

@ -150,7 +150,7 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
bondedRolesComboBox.setVisible(true); bondedRolesComboBox.setVisible(true);
lockupRows++; lockupRows++;
bondedRolesComboBox.setItems(FXCollections.observableArrayList(daoFacade.getBondedRoleStates())); bondedRolesComboBox.setItems(FXCollections.observableArrayList(daoFacade.getBondedRoles()));
} else { } else {
bondedRolesComboBox.setVisible(false); bondedRolesComboBox.setVisible(false);
bondedRolesComboBox.getItems().clear(); bondedRolesComboBox.getItems().clear();
@ -199,13 +199,13 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
case BONDED_ROLE: case BONDED_ROLE:
if (bondedRolesComboBox.getValue() != null) { if (bondedRolesComboBox.getValue() != null) {
bondingViewUtils.lockupBondForBondedRole(bondedRolesComboBox.getValue().getRole(), bondingViewUtils.lockupBondForBondedRole(bondedRolesComboBox.getValue().getRole(),
() -> bondedRolesComboBox.getSelectionModel().clearSelection()); txId -> bondedRolesComboBox.getSelectionModel().clearSelection());
} }
break; break;
case REPUTATION: case REPUTATION:
bondingViewUtils.lockupBondForReputation(bsqFormatter.parseToCoin(amountInputTextField.getText()), bondingViewUtils.lockupBondForReputation(bsqFormatter.parseToCoin(amountInputTextField.getText()),
Integer.parseInt(timeInputTextField.getText()), Integer.parseInt(timeInputTextField.getText()),
() -> { txId -> {
amountInputTextField.setText(""); amountInputTextField.setText("");
timeInputTextField.setText(""); timeInputTextField.setText("");
}); });

View file

@ -18,9 +18,11 @@
package bisq.desktop.main.dao.bonding.roles; package bisq.desktop.main.dao.bonding.roles;
import bisq.desktop.components.AutoTooltipButton; import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.main.dao.bonding.BondingViewUtils;
import bisq.core.dao.DaoFacade; import bisq.core.dao.DaoFacade;
import bisq.core.dao.governance.bond.BondedRole; import bisq.core.dao.governance.bond.BondedRole;
import bisq.core.dao.governance.bond.BondedRoleState;
import bisq.core.dao.state.DaoStateListener; import bisq.core.dao.state.DaoStateListener;
import bisq.core.dao.state.model.blockchain.Block; import bisq.core.dao.state.model.blockchain.Block;
import bisq.core.dao.state.model.governance.Role; import bisq.core.dao.state.model.governance.Role;
@ -31,37 +33,65 @@ import javafx.scene.control.Label;
import java.util.Date; import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@EqualsAndHashCode @EqualsAndHashCode
@Data
class BondedRolesListItem implements DaoStateListener { class BondedRolesListItem implements DaoStateListener {
@Getter
private final BondedRole bondedRole; private final BondedRole bondedRole;
private final DaoFacade daoFacade; private final DaoFacade daoFacade;
private final BondingViewUtils bondingViewUtils;
private final BsqFormatter bsqFormatter; private final BsqFormatter bsqFormatter;
@Getter
private final AutoTooltipButton button; private final AutoTooltipButton button;
@Getter
private final Label label; private final Label label;
@Getter
private final Role role; private final Role role;
private final boolean isMyRole;
BondedRolesListItem(BondedRole bondedRole, BondedRolesListItem(BondedRole bondedRole,
DaoFacade daoFacade, DaoFacade daoFacade,
BondingViewUtils bondingViewUtils,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
this.bondedRole = bondedRole; this.bondedRole = bondedRole;
this.daoFacade = daoFacade; this.daoFacade = daoFacade;
this.bondingViewUtils = bondingViewUtils;
this.bsqFormatter = bsqFormatter; this.bsqFormatter = bsqFormatter;
role = bondedRole.getRole(); role = bondedRole.getRole();
isMyRole = daoFacade.isMyRole(bondedRole.getRole());
daoFacade.addBsqStateListener(this); daoFacade.addBsqStateListener(this);
button = new AutoTooltipButton(); button = new AutoTooltipButton();
button.setMinWidth(70); button.setMinWidth(70);
label = new Label(); label = new Label();
button.setOnAction(e -> {
if (bondedRole.getBondedRoleState() == BondedRoleState.READY_FOR_LOCKUP) {
bondingViewUtils.lockupBondForBondedRole(role,
txId -> {
bondedRole.setLockupTxId(txId);
bondedRole.setBondedRoleState(BondedRoleState.LOCKUP_TX_PENDING);
update();
button.setDisable(true);
});
} else if (bondedRole.getBondedRoleState() == BondedRoleState.LOCKUP_TX_CONFIRMED) {
bondingViewUtils.unLock(bondedRole.getLockupTxId(),
txId -> {
bondedRole.setUnlockTxId(txId);
bondedRole.setBondedRoleState(BondedRoleState.UNLOCK_TX_PENDING);
update();
button.setDisable(true);
});
}
});
update(); update();
} }
@ -79,48 +109,27 @@ class BondedRolesListItem implements DaoStateListener {
public void cleanup() { public void cleanup() {
daoFacade.removeBsqStateListener(this); daoFacade.removeBsqStateListener(this);
setOnAction(null); button.setOnAction(null);
} }
public void setOnAction(Runnable handler) {
button.setOnAction(e -> handler.run());
}
public boolean isBonded() {
return bondedRole.isLockedUp();
}
private void update() { private void update() {
// We have following state: label.setText(Res.get("dao.bond.bondedRoleState." + bondedRole.getBondedRoleState().name()));
// 1. Not bonded: !isLockedUp, !isUnlocked, !isUnlocking: notBonded
// 2. Locked up: isLockedUp, !isUnlocked, !isUnlocking: lockedUp
// 3. Unlocking: isLockedUp, isUnlocked, isUnlocking: unlocking
// 4. Unlocked: isLockedUp, isUnlocked, !isUnlocking: unlocked
boolean isLockedUp = bondedRole.isLockedUp(); log.error("bondedRole.getLockupTxId()={}, bondedRole.getBondedRoleState()={}", bondedRole.getLockupTxId(), bondedRole.getBondedRoleState());
boolean isUnlocked = bondedRole.isUnlocked(); boolean showLockup = bondedRole.getBondedRoleState() == BondedRoleState.READY_FOR_LOCKUP;
boolean isUnlocking = bondedRole.isUnlocking(); boolean showRevoke = bondedRole.getBondedRoleState() == BondedRoleState.LOCKUP_TX_CONFIRMED;
if (showLockup)
button.updateText(Res.get("dao.bond.table.button.lockup"));
else if (showRevoke)
button.updateText(Res.get("dao.bond.table.button.revoke"));
String text;
if (!isLockedUp)
text = Res.get("dao.bond.table.notBonded");
else if (!isUnlocked)
text = Res.get("dao.bond.table.lockedUp");
else if (isUnlocking)
text = Res.get("dao.bond.table.unlocking");
else
text = Res.get("dao.bond.table.unlocked");
label.setText(text); boolean showButton = isMyRole && (showLockup || showRevoke);
button.setVisible(showButton);
button.updateText(isLockedUp ? Res.get("dao.bond.table.button.revoke") : Res.get("dao.bond.table.button.lockup")); button.setManaged(showButton);
button.setVisible(!isLockedUp || !isUnlocked);
button.setManaged(button.isVisible());
//TODO listen to unconfirmed txs and update button and label state
} }
// DaoStateListener // DaoStateListener
@Override @Override
public void onNewBlockHeight(int blockHeight) { public void onNewBlockHeight(int blockHeight) {

View file

@ -153,8 +153,8 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
private void updateList() { private void updateList() {
observableList.forEach(BondedRolesListItem::cleanup); observableList.forEach(BondedRolesListItem::cleanup);
observableList.setAll(daoFacade.getBondedRoleStates().stream() observableList.setAll(daoFacade.getBondedRoles().stream()
.map(bondedRoleState -> new BondedRolesListItem(bondedRoleState, daoFacade, bsqFormatter)) .map(bondedRole -> new BondedRolesListItem(bondedRole, daoFacade, bondingViewUtils, bsqFormatter))
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
@ -195,7 +195,7 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
}); });
tableView.getColumns().add(column); tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.linkToAccount")); column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.link"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60); column.setMinWidth(60);
column.setCellFactory( column.setCellFactory(
@ -315,7 +315,7 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.lockupTxId")); column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.lockupTxId"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60); column.setMinWidth(80);
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem, new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() { BondedRolesListItem>>() {
@ -357,7 +357,7 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.unlockTxId")); column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.unlockTxId"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60); column.setMinWidth(80);
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem, new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() { BondedRolesListItem>>() {
@ -447,16 +447,6 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
if (item != null && !empty) { if (item != null && !empty) {
if (button == null) { if (button == null) {
button = item.getButton(); button = item.getButton();
item.setOnAction(() -> {
if (item.isBonded())
bondingViewUtils.unLock(item.getBondedRole().getLockupTxId(),
() -> {
// TODO
button.setDisable(true);
});
else
bondingViewUtils.lockupBondForBondedRole(item.getRole(), null);
});
setGraphic(button); setGraphic(button);
} }
} else { } else {

View file

@ -397,7 +397,7 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
if (item != null && !empty) { if (item != null && !empty) {
if (button == null) { if (button == null) {
button = item.getButton(); button = item.getButton();
button.setOnAction(e -> bondingViewUtils.unLock(item.getTxId(), () -> { button.setOnAction(e -> bondingViewUtils.unLock(item.getTxId(), txId -> {
//TODO //TODO
button.setDisable(true); button.setDisable(true);
})); }));