Handle cycles in case of applying a empty snapshot

This commit is contained in:
Manfred Karrer 2018-12-12 13:35:13 +01:00
parent 6ad2c1e324
commit 5bf7ba46a7
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
2 changed files with 38 additions and 27 deletions

View file

@ -68,7 +68,7 @@ public class CycleService implements DaoStateListener, DaoSetupService {
@Override
public void start() {
daoStateService.getCycles().add(getFirstCycle());
addFirstCycle();
}
@ -96,6 +96,28 @@ public class CycleService implements DaoStateListener, DaoSetupService {
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void addFirstCycle() {
daoStateService.getCycles().add(getFirstCycle());
}
public int getCycleIndex(Cycle cycle) {
return (cycle.getHeightOfFirstBlock() - genesisBlockHeight) / cycle.getDuration();
}
public boolean isTxInCycle(Cycle cycle, String txId) {
return daoStateService.getTx(txId).filter(tx -> isBlockHeightInCycle(tx.getBlockHeight(), cycle)).isPresent();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private boolean isBlockHeightInCycle(int blockHeight, Cycle cycle) {
return blockHeight >= cycle.getHeightOfFirstBlock() &&
blockHeight <= cycle.getHeightOfLastBlock();
}
private Optional<Cycle> maybeCreateNewCycle(int blockHeight, LinkedList<Cycle> cycles) {
// We want to set the correct phase and cycle before we start parsing a new block.
// For Genesis block we did it already in the start method.
@ -128,24 +150,6 @@ public class CycleService implements DaoStateListener, DaoSetupService {
return new Cycle(genesisBlockHeight, ImmutableList.copyOf(daoPhasesWithDefaultDuration));
}
public int getCycleIndex(Cycle cycle) {
return (cycle.getHeightOfFirstBlock() - genesisBlockHeight) / cycle.getDuration();
}
public boolean isTxInCycle(Cycle cycle, String txId) {
return daoStateService.getTx(txId).filter(tx -> isBlockHeightInCycle(tx.getBlockHeight(), cycle)).isPresent();
}
private boolean isBlockHeightInCycle(int blockHeight, Cycle cycle) {
return blockHeight >= cycle.getHeightOfFirstBlock() &&
blockHeight <= cycle.getHeightOfLastBlock();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private Cycle createNewCycle(int blockHeight, Cycle previousCycle) {
List<DaoPhase> daoPhaseList = previousCycle.getDaoPhaseList().stream()
.map(daoPhase -> {

View file

@ -17,6 +17,7 @@
package bisq.core.dao.state;
import bisq.core.dao.governance.period.CycleService;
import bisq.core.dao.state.model.DaoState;
import bisq.core.dao.state.model.blockchain.Block;
@ -41,6 +42,7 @@ public class DaoStateSnapshotService implements DaoStateListener {
private final DaoStateService daoStateService;
private final GenesisTxInfo genesisTxInfo;
private final CycleService cycleService;
private final DaoStateStorageService daoStateStorageService;
private DaoState snapshotCandidate;
@ -53,9 +55,11 @@ public class DaoStateSnapshotService implements DaoStateListener {
@Inject
public DaoStateSnapshotService(DaoStateService daoStateService,
GenesisTxInfo genesisTxInfo,
CycleService cycleService,
DaoStateStorageService daoStateStorageService) {
this.daoStateService = daoStateService;
this.genesisTxInfo = genesisTxInfo;
this.cycleService = cycleService;
this.daoStateStorageService = daoStateStorageService;
this.daoStateService.addBsqStateListener(this);
@ -128,19 +132,13 @@ public class DaoStateSnapshotService implements DaoStateListener {
log.warn("We applied already a snapshot with chainHeight {}. We will reset the daoState and " +
"start over from the genesis transaction again.", chainHeightOfLastApplySnapshot);
persisted = new DaoState();
int genesisBlockHeight = genesisTxInfo.getGenesisBlockHeight();
persisted.setChainHeight(genesisBlockHeight);
chainHeightOfLastApplySnapshot = genesisBlockHeight;
daoStateService.applySnapshot(persisted);
applyEmptySnapshot(persisted);
}
}
} else if (fromReorg) {
log.info("We got a reorg and we want to apply the snapshot but it is empty. That is expected in the first blocks until the " +
"first snapshot has been created. We use our applySnapshot method and restart from the genesis tx");
int genesisBlockHeight = genesisTxInfo.getGenesisBlockHeight();
persisted.setChainHeight(genesisBlockHeight);
chainHeightOfLastApplySnapshot = genesisBlockHeight;
daoStateService.applySnapshot(persisted);
applyEmptySnapshot(persisted);
}
} else {
log.info("Try to apply snapshot but no stored snapshot available. That is expected at first blocks.");
@ -152,6 +150,15 @@ public class DaoStateSnapshotService implements DaoStateListener {
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void applyEmptySnapshot(DaoState persisted) {
int genesisBlockHeight = genesisTxInfo.getGenesisBlockHeight();
persisted.setChainHeight(genesisBlockHeight);
chainHeightOfLastApplySnapshot = genesisBlockHeight;
daoStateService.applySnapshot(persisted);
// In case we apply an empty snapshot we need to trigger the cycleService.addFirstCycle method
cycleService.addFirstCycle();
}
@VisibleForTesting
int getSnapshotHeight(int genesisHeight, int height, int grid) {
return Math.round(Math.max(genesisHeight + 3 * grid, height) / grid) * grid - grid;