Use block height of proposal tx if available

To be able to apply the validation also on past cycles we need to use
the block height if the proposal tx and not the current one. Just in
case the tx is not confirmed (when temp proposal gets published) we use
the current height, but that would anyway match the cycle.
In a past cycle params could have been different and validation need to
use the correct param value from that cycle.
This commit is contained in:
Manfred Karrer 2019-03-18 23:39:57 -05:00
parent dbf3ebadea
commit ff5d18a493
No known key found for this signature in database
GPG Key ID: 401250966A6B2C46
11 changed files with 73 additions and 64 deletions

View File

@ -19,6 +19,7 @@ package bisq.core.dao.governance.proposal;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.BaseTx;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.core.dao.state.model.blockchain.TxType;
import bisq.core.dao.state.model.governance.CompensationProposal;
@ -135,4 +136,12 @@ public abstract class ProposalValidator {
return false;
}
}
protected Integer getBlockHeight(Proposal proposal) {
// When we receive a temp proposal the tx is usually not confirmed so we cannot lookup the block height of
// the tx. We take the current block height in that case as it would be in the same cycle anyway.
return daoStateService.getTx(proposal.getTxId())
.map(BaseTx::getBlockHeight)
.orElseGet(daoStateService::getChainHeight);
}
}

View File

@ -24,14 +24,7 @@ import bisq.core.dao.governance.proposal.param.ChangeParamValidator;
import bisq.core.dao.governance.proposal.reimbursement.ReimbursementValidator;
import bisq.core.dao.governance.proposal.removeAsset.RemoveAssetValidator;
import bisq.core.dao.governance.proposal.role.RoleValidator;
import bisq.core.dao.state.model.governance.ChangeParamProposal;
import bisq.core.dao.state.model.governance.CompensationProposal;
import bisq.core.dao.state.model.governance.ConfiscateBondProposal;
import bisq.core.dao.state.model.governance.GenericProposal;
import bisq.core.dao.state.model.governance.Proposal;
import bisq.core.dao.state.model.governance.ReimbursementProposal;
import bisq.core.dao.state.model.governance.RemoveAssetProposal;
import bisq.core.dao.state.model.governance.RoleProposal;
import javax.inject.Inject;
@ -65,21 +58,26 @@ public class ProposalValidatorProvider {
}
public ProposalValidator getValidator(Proposal proposal) {
if (proposal instanceof CompensationProposal)
return compensationValidator;
else if (proposal instanceof ConfiscateBondProposal)
return confiscateBondValidator;
else if (proposal instanceof GenericProposal)
return genericProposalValidator;
else if (proposal instanceof ChangeParamProposal)
return changeParamValidator;
else if (proposal instanceof ReimbursementProposal)
return reimbursementValidator;
else if (proposal instanceof RemoveAssetProposal)
return removeAssetValidator;
else if (proposal instanceof RoleProposal)
return roleValidator;
else
throw new RuntimeException("");
return getValidator(proposal.getType());
}
public ProposalValidator getValidator(ProposalType proposalType) {
switch (proposalType) {
case COMPENSATION_REQUEST:
return compensationValidator;
case REIMBURSEMENT_REQUEST:
return reimbursementValidator;
case CHANGE_PARAM:
return changeParamValidator;
case BONDED_ROLE:
return roleValidator;
case CONFISCATE_BOND:
return confiscateBondValidator;
case GENERIC:
return genericProposalValidator;
case REMOVE_ASSET:
return removeAssetValidator;
}
throw new RuntimeException("Proposal type " + proposalType.name() + " was not covered by switch case.");
}
}

View File

@ -17,8 +17,8 @@
package bisq.core.dao.governance.proposal.compensation;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.CompensationProposal;
@ -53,13 +53,15 @@ public class CompensationValidator extends ProposalValidator {
compensationProposal.getAddress(); // throws AddressFormatException if wrong address
Coin requestedBsq = compensationProposal.getRequestedBsq();
Coin maxCompensationRequestAmount = CompensationConsensus.getMaxCompensationRequestAmount(daoStateService, periodService.getChainHeight());
int chainHeight = getBlockHeight(proposal);
Coin maxCompensationRequestAmount = CompensationConsensus.getMaxCompensationRequestAmount(daoStateService, chainHeight);
checkArgument(requestedBsq.compareTo(maxCompensationRequestAmount) <= 0,
"Requested BSQ must not exceed " + (maxCompensationRequestAmount.value / 100L) + " BSQ");
Coin minCompensationRequestAmount = CompensationConsensus.getMinCompensationRequestAmount(daoStateService, periodService.getChainHeight());
Coin minCompensationRequestAmount = CompensationConsensus.getMinCompensationRequestAmount(daoStateService, chainHeight);
checkArgument(requestedBsq.compareTo(minCompensationRequestAmount) >= 0,
"Requested BSQ must not be less than " + (minCompensationRequestAmount.value / 100L) + " BSQ");
} catch (ProposalValidationException e) {
throw e;
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}

View File

@ -17,8 +17,8 @@
package bisq.core.dao.governance.proposal.confiscatebond;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.ConfiscateBondProposal;
@ -28,6 +28,8 @@ import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import static org.apache.commons.lang3.Validate.notEmpty;
@Slf4j
public class ConfiscateBondValidator extends ProposalValidator {
@ -40,9 +42,10 @@ public class ConfiscateBondValidator extends ProposalValidator {
public void validateDataFields(Proposal proposal) throws ProposalValidationException {
try {
super.validateDataFields(proposal);
ConfiscateBondProposal confiscateBondProposal = (ConfiscateBondProposal) proposal;
//TODO
notEmpty(confiscateBondProposal.getLockupTxId(), "LockupTxId must not be empty");
} catch (ProposalValidationException e) {
throw e;
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}

View File

@ -17,11 +17,10 @@
package bisq.core.dao.governance.proposal.generic;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.GenericProposal;
import bisq.core.dao.state.model.governance.Proposal;
import javax.inject.Inject;
@ -40,9 +39,8 @@ public class GenericProposalValidator extends ProposalValidator {
public void validateDataFields(Proposal proposal) throws ProposalValidationException {
try {
super.validateDataFields(proposal);
GenericProposal genericProposalProposal = (GenericProposal) proposal;
//TODO
} catch (ProposalValidationException e) {
throw e;
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}

View File

@ -24,7 +24,6 @@ import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.BaseTx;
import bisq.core.dao.state.model.governance.ChangeParamProposal;
import bisq.core.dao.state.model.governance.Proposal;
import bisq.core.locale.Res;
@ -86,14 +85,10 @@ public class ChangeParamValidator extends ProposalValidator {
public void validateDataFields(Proposal proposal) throws ProposalValidationException {
try {
super.validateDataFields(proposal);
ChangeParamProposal changeParamProposal = (ChangeParamProposal) proposal;
// When we receive a temp proposal the tx is usually not confirmed so we cannot lookup the block height of
// the tx. We take the current block height in that case as it would be in the same cycle anyway.
int blockHeight = daoStateService.getTx(proposal.getTxId())
.map(BaseTx::getBlockHeight)
.orElseGet(daoStateService::getChainHeight);
validateParamValue(changeParamProposal.getParam(), changeParamProposal.getParamValue(), blockHeight);
validateParamValue(changeParamProposal.getParam(), changeParamProposal.getParamValue(), getBlockHeight(proposal));
} catch (ProposalValidationException e) {
throw e;
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}
@ -104,7 +99,7 @@ public class ChangeParamValidator extends ProposalValidator {
validateParamValue(param, inputValue, blockHeight);
}
public void validateParamValue(Param param, String inputValue, int blockHeight) throws ParamValidationException {
private void validateParamValue(Param param, String inputValue, int blockHeight) throws ParamValidationException {
String currentParamValue = daoStateService.getParamValue(param, blockHeight);
validateParamValue(param, currentParamValue, inputValue);
}

View File

@ -17,9 +17,10 @@
package bisq.core.dao.governance.proposal.reimbursement;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.governance.proposal.compensation.CompensationConsensus;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.Proposal;
import bisq.core.dao.state.model.governance.ReimbursementProposal;
@ -53,12 +54,15 @@ public class ReimbursementValidator extends ProposalValidator {
reimbursementProposal.getAddress(); // throws AddressFormatException if wrong address
Coin requestedBsq = reimbursementProposal.getRequestedBsq();
Coin maxReimbursementRequestAmount = ReimbursementConsensus.getMaxReimbursementRequestAmount(daoStateService, periodService.getChainHeight());
checkArgument(requestedBsq.compareTo(maxReimbursementRequestAmount) <= 0,
"Requested BSQ must not exceed " + (maxReimbursementRequestAmount.value / 100L) + " BSQ");
Coin minReimbursementRequestAmount = ReimbursementConsensus.getMinReimbursementRequestAmount(daoStateService, periodService.getChainHeight());
checkArgument(requestedBsq.compareTo(minReimbursementRequestAmount) >= 0,
"Requested BSQ must not be less than " + (minReimbursementRequestAmount.value / 100L) + " BSQ");
int chainHeight = getBlockHeight(proposal);
Coin maxCompensationRequestAmount = CompensationConsensus.getMaxCompensationRequestAmount(daoStateService, chainHeight);
checkArgument(requestedBsq.compareTo(maxCompensationRequestAmount) <= 0,
"Requested BSQ must not exceed " + (maxCompensationRequestAmount.value / 100L) + " BSQ");
Coin minCompensationRequestAmount = CompensationConsensus.getMinCompensationRequestAmount(daoStateService, chainHeight);
checkArgument(requestedBsq.compareTo(minCompensationRequestAmount) >= 0,
"Requested BSQ must not be less than " + (minCompensationRequestAmount.value / 100L) + " BSQ");
} catch (ProposalValidationException e) {
throw e;
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}

View File

@ -17,8 +17,8 @@
package bisq.core.dao.governance.proposal.removeAsset;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.Proposal;
@ -28,6 +28,8 @@ import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import static org.apache.commons.lang3.Validate.notEmpty;
@Slf4j
public class RemoveAssetValidator extends ProposalValidator {
@ -42,7 +44,9 @@ public class RemoveAssetValidator extends ProposalValidator {
super.validateDataFields(proposal);
RemoveAssetProposal removeAssetProposal = (RemoveAssetProposal) proposal;
//TODO
notEmpty(removeAssetProposal.getTickerSymbol(), "TickerSymbol must not be empty");
} catch (ProposalValidationException e) {
throw e;
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}

View File

@ -17,19 +17,18 @@
package bisq.core.dao.governance.proposal.role;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.period.PeriodService;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalValidator;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.governance.Proposal;
import bisq.core.dao.state.model.governance.Role;
import bisq.core.dao.state.model.governance.RoleProposal;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import static org.apache.commons.lang3.Validate.notEmpty;
import static org.apache.commons.lang3.Validate.notNull;
@Slf4j
public class RoleValidator extends ProposalValidator {
@ -45,11 +44,7 @@ public class RoleValidator extends ProposalValidator {
super.validateDataFields(proposal);
RoleProposal roleProposal = (RoleProposal) proposal;
Role role = roleProposal.getRole();
//TODO
notEmpty(role.getName(), "role.name must not be empty");
notNull(roleProposal.getRole(), "Bonded role must not be null");
} catch (Throwable throwable) {
throw new ProposalValidationException(throwable);
}

View File

@ -51,6 +51,7 @@ public abstract class Proposal implements PersistablePayload, NetworkPayload, Co
protected final String link;
protected final byte version;
protected final long creationDate;
@Nullable
protected final String txId;
protected Proposal(String name,

View File

@ -33,10 +33,10 @@ import bisq.core.btc.exceptions.InsufficientBsqException;
import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.bond.Bond;
import bisq.core.dao.governance.param.Param;
import bisq.core.dao.governance.proposal.ProposalType;
import bisq.core.dao.governance.proposal.ProposalValidationException;
import bisq.core.dao.governance.proposal.ProposalWithTransaction;
import bisq.core.dao.governance.proposal.TxException;
import bisq.core.dao.governance.proposal.param.ChangeParamValidator;
@ -358,14 +358,14 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
}
@Nullable
private ProposalWithTransaction getProposalWithTransaction(ProposalType type)
private ProposalWithTransaction getProposalWithTransaction(ProposalType proposalType)
throws InsufficientMoneyException, ProposalValidationException, TxException {
checkNotNull(proposalDisplay, "proposalDisplay must not be null");
String link = proposalDisplay.linkInputTextField.getText();
String name = proposalDisplay.nameTextField.getText();
switch (type) {
switch (proposalType) {
case COMPENSATION_REQUEST:
checkNotNull(proposalDisplay.requestedBsqTextField,
"proposalDisplay.requestedBsqTextField must not be null");