Skip to content

Commit

Permalink
AKI-407: utility for managing unity fork point
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandraRoatis committed Oct 18, 2019
1 parent 305a3da commit 64881af
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.aion.zero.impl.core.FastImportResult;
import org.aion.zero.impl.core.ImportResult;
import org.aion.zero.impl.db.TransactionStore;
import org.aion.zero.impl.forks.ForkUtility;
import org.aion.zero.impl.trie.Trie;
import org.aion.zero.impl.trie.TrieImpl;
import org.aion.zero.impl.trie.TrieNodeResult;
Expand Down Expand Up @@ -121,13 +122,13 @@ public class AionBlockchainImpl implements IAionBlockchain {
private static final int DIFFICULTY_BYTES = 16;
private static final Logger LOGGER_VM = AionLoggerFactory.getLogger(LogEnum.VM.toString());
static long fork040BlockNumber = -1L;
private static long FORK_5_BLOCK_NUMBER = Long.MAX_VALUE;
private static boolean fork040Enable;
private final GrandParentBlockHeaderValidator preUnityGrandParentBlockHeaderValidator;
private final GreatGrandParentBlockHeaderValidator unityGreatGrandParentBlockHeaderValidator;
private final ParentBlockHeaderValidator preUnityParentBlockHeaderValidator;
private final ParentBlockHeaderValidator unityParentBlockHeaderValidator;
private final StakingContractHelper stakingContractHelper;
public final ForkUtility forkUtility;
public final BeaconHashValidator beaconHashValidator;

/**
Expand Down Expand Up @@ -230,16 +231,16 @@ protected AionBlockchainImpl(
}
this.energyLimitStrategy = config.getEnergyLimitStrategy();

// initialize fork utility
this.forkUtility = new ForkUtility(); // forks are disabled by default
Optional<Long> maybeFork050 = load050ForkNumberFromConfig(CfgAion.inst());
if(! maybeFork050.isPresent()) {
this.beaconHashValidator = new BeaconHashValidator(this,
BeaconHashValidator.FORK_050_DISABLED);
} else {
this.beaconHashValidator = new BeaconHashValidator(this,
maybeFork050.get());
FORK_5_BLOCK_NUMBER = maybeFork050.get();
if (maybeFork050.isPresent()) {
this.forkUtility.enableUnityFork(maybeFork050.get());
}


// initialize beacon hash validator
this.beaconHashValidator = new BeaconHashValidator(this, this.forkUtility);

stakingContractHelper =
new StakingContractHelper(
forTest
Expand Down Expand Up @@ -621,7 +622,7 @@ private State pushState(byte[] bestBlockHash) {

if (bestBlock.getHeader().getSealType() == BlockSealType.SEAL_POW_BLOCK) {
bestMiningBlock = (AionBlock) bestBlock;
if (bestBlock.getNumber() > getUnityForkNumber()) {
if (forkUtility.isUnityForkActive(bestBlock.getNumber())) {
bestStakingBlock = (StakingBlock) getBlockStore().getBlockByHash(bestBlock.getParentHash());
} else {
bestStakingBlock = null;
Expand Down Expand Up @@ -766,7 +767,7 @@ public void loadBestStakingBlock() {
long bestBlockNumber = bestBlock.getNumber();

if (bestStakingBlock == null) {
if (bestBlockNumber <= getUnityForkNumber()) {
if (!forkUtility.isUnityForkActive(bestBlockNumber)) {
bestStakingBlock = CfgAion.inst().getGenesisStakingBlock();
} else {
if (bestBlock.getHeader().getSealType() == BlockSealType.SEAL_POS_BLOCK) {
Expand Down Expand Up @@ -1165,7 +1166,7 @@ BlockContext createNewMiningBlockInternal(

// We want the fork block itself to be a PoW block subject to the old pre-Unity rules,
// so we use a strict greater than here
if (block.getNumber() > FORK_5_BLOCK_NUMBER) {
if (forkUtility.isUnityForkActive(block.getNumber())) {
if (parentHdr.getSealType() == BlockSealType.SEAL_POW_BLOCK) {
LOG.error("Tried to create 2 PoW block in a row");
return null;
Expand Down Expand Up @@ -1198,7 +1199,7 @@ private StakingBlock createNewStakingBlock(
Block parent, List<AionTransaction> txs, byte[] newSeed, byte[] signingPublicKey, byte[] coinbase) {
BlockHeader parentHdr = parent.getHeader();

if (parentHdr.getNumber() < FORK_5_BLOCK_NUMBER) {
if (!forkUtility.isUnityForkActive(parentHdr.getNumber() + 1)) {
LOG.debug("Unity fork has not been enabled! Can't create the staking blocks");
return null;
}
Expand All @@ -1211,7 +1212,7 @@ private StakingBlock createNewStakingBlock(
return null;
} else if (parentHdr.getSealType() == BlockSealType.SEAL_POW_BLOCK) {

if (parentHdr.getNumber() == FORK_5_BLOCK_NUMBER) {
if (forkUtility.isUnityForkBlock(parentHdr.getNumber())) {
// this is the first PoS block
parentStakingBlock = CfgAion.inst().getGenesisStakingBlock().getHeader();
} else {
Expand Down Expand Up @@ -1521,9 +1522,7 @@ public boolean isValid(BlockHeader header) {

Block grandParent = getParent(parent.getHeader());
if (header.getSealType() == BlockSealType.SEAL_POW_BLOCK) {
// We want the fork block itself to be a PoW block subject to the old pre-Unity rules,
// so we use a strict greater than here
if (header.getNumber() > FORK_5_BLOCK_NUMBER) {
if (forkUtility.isUnityForkActive(header.getNumber())) {
if (grandParent == null) {
return false;
}
Expand All @@ -1540,7 +1539,7 @@ public boolean isValid(BlockHeader header) {
preUnityGrandParentBlockHeaderValidator.validate(parent.getHeader(), grandParent == null ? null : grandParent.getHeader(), header, LOG);
}
} else if (header.getSealType() == BlockSealType.SEAL_POS_BLOCK) {
if (header.getNumber() <= FORK_5_BLOCK_NUMBER) {
if (!forkUtility.isUnityForkActive(header.getNumber())) {
return false;
}

Expand Down Expand Up @@ -1614,7 +1613,7 @@ private boolean isValid(Block block) {

Map<AionAddress, BigInteger> nonceCache = new HashMap<>();

boolean unityForkEnabled = block.getHeader().getNumber() >= FORK_5_BLOCK_NUMBER;
boolean unityForkEnabled = forkUtility.isUnityForkActive(block.getNumber());
if (txs.parallelStream()
.anyMatch(
tx ->
Expand Down Expand Up @@ -1719,7 +1718,7 @@ private RetValidPreBlock generatePreBlock(Block block) {
getPostExecutionWorkForGeneratePreBlock(repository),
BlockCachingContext.PENDING,
bestBlock.getNumber(),
isUnityForkEnabled());
forkUtility.isUnityForkActive(block.getNumber()));

for (AionTxExecSummary summary : executionSummaries) {
if (!summary.isRejected()) {
Expand Down Expand Up @@ -1778,7 +1777,7 @@ private AionBlockSummary applyBlock(Block block) {
getPostExecutionWorkForApplyBlock(repository),
executionTypeForAVM,
cachedBlockNumberForAVM,
isUnityForkEnabled());
forkUtility.isUnityForkActive(block.getNumber()));

for (AionTxExecSummary summary : executionSummaries) {
receipts.add(summary.getReceipt());
Expand Down Expand Up @@ -2499,22 +2498,9 @@ public boolean isMainChain(byte[] hash) {
return getBlockStore().isMainChain(hash);
}


@VisibleForTesting
@Override
public void setUnityForkNumber(long unityForkNumber) {
LOG.info("Unity enabled at fork number " + unityForkNumber);
FORK_5_BLOCK_NUMBER = unityForkNumber;
}

@Override
public long getUnityForkNumber() {
return FORK_5_BLOCK_NUMBER;
}

@Override
public boolean isUnityForkEnabled() {
return bestBlockNumber.get() >= FORK_5_BLOCK_NUMBER;
public boolean isUnityForkEnabledAtNextBlock() {
return forkUtility.isUnityForkActive(bestBlockNumber.get() + 1);
}

/**
Expand Down
11 changes: 10 additions & 1 deletion modAionImpl/src/org/aion/zero/impl/blockchain/AionHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ public BlockContext getNewMiningBlockTemplate(BlockContext oldBlockTemplate, lon
context =
blockchain.createNewMiningBlockContext(
bestBlock, new ArrayList<>(ret), false);
} else if (systemTime > oldBlockTemplate.block.getTimestamp() && blockchain.isUnityForkEnabled()) {
} else if (systemTime > oldBlockTemplate.block.getTimestamp() && blockchain.isUnityForkEnabledAtNextBlock()) {
A0BlockHeader newHeader = oldBlockTemplate.block.getHeader().updateTimestamp(System.currentTimeMillis() / 1000);
AionBlock newBlock = new AionBlock(newHeader, oldBlockTemplate.block.getTransactionsList());
context = new BlockContext(newBlock, oldBlockTemplate.baseBlockReward, oldBlockTemplate.transactionFee);
Expand All @@ -641,4 +641,13 @@ public StakingBlock getStakingBlockTemplate(byte[] newSeed, byte[] signingPublic

return blockTemplate;
}

public void enableUnityFork(long unityForkNumber) {
this.blockchain.forkUtility.enableUnityFork(unityForkNumber);
}

@VisibleForTesting
public void disableUnityFork() {
this.blockchain.forkUtility.disableUnityFork();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.aion.zero.impl.blockchain;

import com.google.common.annotations.VisibleForTesting;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -192,10 +191,5 @@ void dropImported(

void loadBestStakingBlock();

boolean isUnityForkEnabled();

@VisibleForTesting
void setUnityForkNumber(long blockNumber);

long getUnityForkNumber();
boolean isUnityForkEnabledAtNextBlock();
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ private AionTxReceipt callConstant(AionTransaction tx)
, block.getNrgLimit()
, BlockCachingContext.CALL.avmType
, 0
, chain.isUnityForkEnabled());
, chain.forkUtility.isUnityForkActive(block.getNumber()));

return summaries.get(0).getReceipt();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,6 @@ public Builder withAccount(ByteArrayWrapper publicKey, AccountState accState) {
return this;
}

private long unityForkNumber = Long.MAX_VALUE;

public Builder withUnityForkNumber(long unityForkNumber) {
this.unityForkNumber = unityForkNumber;
return this;
}

private AionBlock best = null, parentBest = null;
private byte[] trieData = null;
private BigInteger totalDiff = null, totalDiffParent = null;
Expand Down Expand Up @@ -529,7 +522,7 @@ public AionBlock createBlock(
boolean waitUntilBlockTime,
long currTimeSeconds) {

boolean unityForkEnabled = (parent.getHeader().getNumber() + 1) >= getUnityForkNumber();
boolean unityForkEnabled = forkUtility.isUnityForkActive(parent.getNumber() + 1);
for (AionTransaction tx : txs) {
if (unityForkEnabled ? !TXValidator.isValidAfterUnity(tx): !TXValidator.isValid(tx)) {
throw new InvalidParameterException("invalid transaction input! " + tx.toString());
Expand Down
46 changes: 46 additions & 0 deletions modAionImpl/src/org/aion/zero/impl/forks/ForkUtility.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.aion.zero.impl.forks;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;

/** Utility for managing the fork checks. Currently implements only Unity fork functionality. */
public class ForkUtility {

// variables used by the Unity fork
private boolean unityForkEnabled = false;
private long unityForkBlockHeight = Long.MAX_VALUE;

/**
* Enables the Unity fork after the given block number.
*
* @param unityForkBlockHeight the height of the block after which Unity behaviour is applied
*/
public void enableUnityFork(long unityForkBlockHeight) {
Preconditions.checkArgument(unityForkBlockHeight >= 2, "Invalid fork0.5.0 (Unity) block number: must be >= 2");
this.unityForkBlockHeight = unityForkBlockHeight;
this.unityForkEnabled = true;
}

/** Disables the Unity fork. */
@VisibleForTesting
public void disableUnityFork() {
this.unityForkBlockHeight = Long.MAX_VALUE;
this.unityForkEnabled = false;
}

/**
* Returns a boolean value indicating if the Unity fork is active for the given context (block
* number). We want the fork block itself to be a PoW block subject to the old pre-Unity rules,
* so we use a strict greater than comparison.
*
* @return {@code true} if the unity fork is active for the given context (block number), {@code
* false} otherwise
*/
public boolean isUnityForkActive(long contextBlockNumber) {
return unityForkEnabled && (contextBlockNumber > unityForkBlockHeight);
}

public boolean isUnityForkBlock(long contextBlockNumber) {
return unityForkEnabled && (contextBlockNumber == unityForkBlockHeight);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public TransactionSortedSet() {

private final int MAX_REPLAY_TX_BUFFER_SIZE = MAX_VALIDATED_PENDING_TXS >> 2;

private IAionBlockchain blockchain;
private AionBlockchainImpl blockchain;

private TransactionStore transactionStore;

Expand Down Expand Up @@ -434,7 +434,7 @@ public synchronized TxResponse addPendingTransaction(AionTransaction tx) {
}

public boolean isValid(AionTransaction tx) {
return (blockchain.isUnityForkEnabled() ? TXValidator.isValidAfterUnity(tx) : TXValidator.isValid(tx))
return (blockchain.isUnityForkEnabledAtNextBlock() ? TXValidator.isValidAfterUnity(tx) : TXValidator.isValid(tx))
&& TransactionTypeValidator.isValid(tx)
&& beaconHashValidator.validateTxForPendingState(tx);
}
Expand Down Expand Up @@ -1113,7 +1113,7 @@ private AionTxExecSummary executeTx(AionTransaction tx, boolean inPool) {
LOGGER_VM,
BlockCachingContext.PENDING,
bestBlk.getNumber(),
blockchain.isUnityForkEnabled());
blockchain.forkUtility.isUnityForkActive(currentBlockNumber));
} catch (VmFatalException e) {
LOGGER_VM.error("Shutdown due to a VM fatal error.", e);
System.exit(SystemExitCodes.FATAL_VM_ERROR);
Expand Down
36 changes: 8 additions & 28 deletions modAionImpl/src/org/aion/zero/impl/valid/BeaconHashValidator.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.aion.zero.impl.valid;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.aion.base.AionTransaction;
import org.aion.log.LogEnum;
import org.aion.mcf.blockchain.Block;
import org.aion.util.bytes.ByteUtil;
import org.aion.zero.impl.blockchain.IAionBlockchain;
import org.aion.zero.impl.forks.ForkUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -15,32 +15,20 @@
/** Validates beacon hash of transaction */
public class BeaconHashValidator {
private final IAionBlockchain blockchain;
private final long fork050Number;
private final ForkUtility forkUtility;
private static final Logger TX_LOG = LoggerFactory.getLogger(LogEnum.TX.name());

/**
* The value to use for fork050Number when calling constructor {@link
* #BeaconHashValidator(IAionBlockchain, long)} if beacon hash validation is
* disabled.
*/
public static final long FORK_050_DISABLED = Long.MAX_VALUE;

/**
* Constructor.
*
* @param blockchain blockchain
* @param fork050Number the block number at which hard fork 0.5.0 takes effect. Use
* {@link #FORK_050_DISABLED} if validation should be disabled;
* i.e. behave as if fork050 never happens and always return true
* when {@link #validateTxForBlock(AionTransaction, Block)} or
* {@link #validateTxForPendingState(AionTransaction)} is called
*/
public BeaconHashValidator(IAionBlockchain blockchain, long fork050Number) {
Preconditions.checkNotNull(blockchain, "Blockstore can't be null");
Preconditions.checkArgument(fork050Number >= 0, "Invalid fork0.5.0 block number: must be >= 0");
public BeaconHashValidator(IAionBlockchain blockchain, ForkUtility forkUtility) {
Preconditions.checkNotNull(blockchain, "Blockchain cannot be null");
Preconditions.checkNotNull(forkUtility, "Unity fork utility cannot be null");

this.blockchain = blockchain;
this.fork050Number = fork050Number;
this.forkUtility = forkUtility;
}

/**
Expand Down Expand Up @@ -69,7 +57,7 @@ public boolean validateTxForBlock(AionTransaction tx, Block block) {
return true;
}

if (!isAfterFork050(block.getNumber()) && beaconHash != null) {
if (!forkUtility.isUnityForkActive(block.getNumber()) && beaconHash != null) {
return false;
}

Expand Down Expand Up @@ -123,7 +111,7 @@ public boolean validateTxForPendingState(AionTransaction tx) {
// the next block number might be larger than (current best + 1), but
// we will tolerate false negatives
long minNextBlockNumber = blockchain.getBestBlock().getNumber() + 1;
if (!isAfterFork050(minNextBlockNumber) && beaconHash != null) {
if (!forkUtility.isUnityForkActive(minNextBlockNumber) && beaconHash != null) {
return false;
}

Expand All @@ -137,14 +125,6 @@ public boolean validateTxForPendingState(AionTransaction tx) {
}
}

/**
* @return true if blockNumber >= fork050Number and fork050 not disabled;
* false in all other cases
*/
@VisibleForTesting boolean isAfterFork050(long blockNumber) {
return blockNumber >= fork050Number && fork050Number != FORK_050_DISABLED;
}

private boolean checkSideChain(byte[] beaconHash, Block sideChainHead) {
Block beaconBlock = blockchain.getBlockByHash(beaconHash);
if(beaconBlock == null) {
Expand Down
Loading

0 comments on commit 64881af

Please sign in to comment.