use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class EnergyLimitRuleTest method testEnergyLimitLowerBound.
@Test
public void testEnergyLimitLowerBound() {
final long INITIAL_VAL = 0l;
MiningBlockHeader parentHeader = MiningBlockHeader.Builder.newInstance().withEnergyLimit(0l).withDefaultExtraData().withDefaultCoinbase().withDefaultParentHash().withDefaultNonce().withDefaultLogsBloom().withDefaultSolution().withDefaultDifficulty().withDefaultStateRoot().withDefaultReceiptTrieRoot().withDefaultTxTrieRoot().withTimestamp(0).withEnergyConsumed(21000).withNumber(1).build();
MiningBlockHeader currentHeader = MiningBlockHeader.Builder.newInstance().withEnergyLimit(1l).withDefaultExtraData().withDefaultCoinbase().withDefaultParentHash().withDefaultNonce().withDefaultLogsBloom().withDefaultSolution().withDefaultDifficulty().withDefaultStateRoot().withDefaultReceiptTrieRoot().withDefaultTxTrieRoot().withTimestamp(1).withEnergyConsumed(21000).withNumber(2).build();
List<RuleError> errors = new ArrayList<>();
EnergyLimitRule rule = new EnergyLimitRule(constants.getEnergyDivisorLimitLong(), constants.getEnergyLowerBoundLong());
boolean res = rule.validate(currentHeader, parentHeader, errors);
assertThat(res).isEqualTo(false);
assertThat(errors).isNotEmpty();
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class EnergyLimitRuleTest method testEnergyLimitBounds.
@Test
public void testEnergyLimitBounds() {
final long INITIAL_VAL = 2000000L;
final long DIVISOR = 1024;
EnergyLimitRule rule = new EnergyLimitRule(constants.getEnergyDivisorLimitLong(), constants.getEnergyLowerBoundLong());
MiningBlockHeader parentHeader = MiningBlockHeader.Builder.newInstance().withEnergyLimit(INITIAL_VAL).withNumber(1).withDefaultParentHash().withDefaultCoinbase().withDefaultLogsBloom().withDifficulty(ByteUtil.intToBytes(1)).withDefaultExtraData().withEnergyConsumed(1).withTimestamp(1).withDefaultNonce().withDefaultSolution().withDefaultStateRoot().withDefaultTxTrieRoot().withDefaultReceiptTrieRoot().build();
long boundShiftLimit = INITIAL_VAL / DIVISOR;
MiningBlockHeader upperCurrentBlock = MiningBlockHeader.Builder.newInstance().withEnergyLimit(INITIAL_VAL + boundShiftLimit).withNumber(1).withDefaultParentHash().withDefaultCoinbase().withDefaultLogsBloom().withDifficulty(ByteUtil.intToBytes(1)).withDefaultExtraData().withEnergyConsumed(1).withTimestamp(1).withDefaultNonce().withDefaultSolution().withDefaultStateRoot().withDefaultTxTrieRoot().withDefaultReceiptTrieRoot().build();
List<RuleError> errors = new ArrayList<>();
// upper bound
boolean res = rule.validate(upperCurrentBlock, parentHeader, errors);
assertThat(res).isEqualTo(true);
assertThat(errors).isEmpty();
errors.clear();
MiningBlockHeader invalidCurrentHeader = MiningBlockHeader.Builder.newInstance().withEnergyLimit(INITIAL_VAL + boundShiftLimit + 1).withNumber(1).withDefaultParentHash().withDefaultCoinbase().withDefaultLogsBloom().withDifficulty(ByteUtil.intToBytes(1)).withDefaultExtraData().withEnergyConsumed(1).withTimestamp(1).withDefaultNonce().withDefaultSolution().withDefaultStateRoot().withDefaultTxTrieRoot().withDefaultReceiptTrieRoot().build();
res = rule.validate(invalidCurrentHeader, parentHeader, errors);
assertThat(res).isEqualTo(false);
assertThat(errors).isNotEmpty();
errors.clear();
// lower bound
MiningBlockHeader lowerCurrentHeader = MiningBlockHeader.Builder.newInstance().withEnergyLimit(INITIAL_VAL - boundShiftLimit).withNumber(1).withDefaultParentHash().withDefaultCoinbase().withDefaultLogsBloom().withDifficulty(ByteUtil.intToBytes(1)).withDefaultExtraData().withEnergyConsumed(1).withTimestamp(1).withDefaultNonce().withDefaultSolution().withDefaultStateRoot().withDefaultTxTrieRoot().withDefaultReceiptTrieRoot().build();
res = rule.validate(lowerCurrentHeader, parentHeader, errors);
assertThat(res).isEqualTo(true);
assertThat(errors).isEmpty();
errors.clear();
MiningBlockHeader invalidLowerCurrentHeader = MiningBlockHeader.Builder.newInstance().withEnergyLimit(INITIAL_VAL - boundShiftLimit - 1).withNumber(1).withDefaultParentHash().withDefaultCoinbase().withDefaultLogsBloom().withDifficulty(ByteUtil.intToBytes(1)).withDefaultExtraData().withEnergyConsumed(1).withTimestamp(1).withDefaultNonce().withDefaultSolution().withDefaultStateRoot().withDefaultTxTrieRoot().withDefaultReceiptTrieRoot().build();
res = rule.validate(invalidLowerCurrentHeader, parentHeader, errors);
assertThat(res).isEqualTo(false);
assertThat(errors).isNotEmpty();
errors.clear();
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class AionBlockchainImpl method getListOfHeadersStartFrom.
/**
* Returns up to limit headers found with following search parameters
*
* @param blockNumber Identifier of start block, by number
* @param limit Maximum number of headers in return
* @return {@link MiningBlockHeader}'s list or empty list if none found
*/
@Override
public List<BlockHeader> getListOfHeadersStartFrom(long blockNumber, int limit) {
if (limit <= 0) {
return emptyList();
}
// identifying block we'll move from
Block startBlock = getBlockByNumber(blockNumber);
// if nothing found on main chain, return empty array
if (startBlock == null) {
return emptyList();
}
List<BlockHeader> headers;
long bestNumber = bestBlock.getNumber();
headers = getContinuousHeaders(bestNumber, blockNumber, limit);
return headers;
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class BlockchainForkingTest method testInvalidFirstBlockDifficulty.
/*-
* Test the general forking case, where an incoming block (b) has a greater total
* difficulty than our current block. In this scenario, we should switch to
* the branch (sub-tree) that has (b) at its tip.
*
* This is the simplest case, where the distance between (a) (our current head) and
* (b) is 2. This implies that the common ancestor is directly adjacent to both blocks.
*
* (common ancestor)
* / \
* / \
* / \
* (a)x(low td) (b)o(higher td)
*
* In this simple case:
* b.td > a.td
* a_worldState === b_worldState
*
*/
@Test
public void testInvalidFirstBlockDifficulty() {
StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
StandaloneBlockchain.Bundle b = builder.withValidatorConfiguration("simple").build();
StandaloneBlockchain bc = b.bc;
Block bestBlock = bc.getBestBlock();
MiningBlock standardBlock = bc.createNewMiningBlock(bc.getBestBlock(), Collections.emptyList(), true);
ChainConfiguration cc = new ChainConfiguration();
MiningBlock higherDifficultyBlock = new MiningBlock(standardBlock);
MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(higherDifficultyBlock.getHeader()).withTimestamp(bestBlock.getTimestamp() + 1).build();
higherDifficultyBlock.updateHeader(newBlockHeader);
BigInteger difficulty = cc.getPreUnityDifficultyCalculator().calculateDifficulty(higherDifficultyBlock.getHeader(), bestBlock.getHeader());
assertThat(difficulty).isGreaterThan(standardBlock.getDifficultyBI());
newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(higherDifficultyBlock.getHeader()).withDifficulty(difficulty.toByteArray()).build();
higherDifficultyBlock.updateHeader(newBlockHeader);
System.out.println("before any processing: " + Hex.toHexString(bc.getRepository().getRoot()));
System.out.println("trie: " + bc.getRepository().getWorldState().getTrieDump());
ImportResult result = bc.tryToConnect(standardBlock);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
// check that the correct caching context was used
Pair<Long, BlockCachingContext> cacheContext = bc.getAvmCachingContext();
assertThat(cacheContext.getLeft()).isEqualTo(standardBlock.getNumber() - 1);
assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
// assert that the block we just inserted (best) is the instance that is returned
assertThat(bc.getBestBlock() == standardBlock).isTrue();
System.out.println(Hex.toHexString(bc.getRepository().getRoot()));
ImportResult higherDifficultyResult = bc.tryToConnect(higherDifficultyBlock);
/**
* With our updates to difficulty verification and calculation, this block is now invalid
*/
assertThat(higherDifficultyResult).isEqualTo(ImportResult.INVALID_BLOCK);
assertThat(bc.getBestBlockHash()).isEqualTo(standardBlock.getHash());
// since the block is second for that height, it is assumed as sidechain
cacheContext = bc.getAvmCachingContext();
assertThat(cacheContext.getLeft()).isEqualTo(standardBlock.getNumber() - 1);
assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.SIDECHAIN);
// the object reference here is intentional
assertThat(bc.getBestBlock() == standardBlock).isTrue();
// check for correct state rollback
assertThat(bc.getRepository().getRoot()).isEqualTo(standardBlock.getStateRoot());
assertThat(bc.getTotalDifficulty()).isEqualTo(bc.getTotalDifficultyForHash(standardBlock.getHash()));
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class BlockchainForkingTest method testForkWithRevertOnSmallContractStorage.
/**
* Test the fork case when the block being replaced had contract storage changes that differ
* from the previous block and are replaced by new changes in the updated block.
*
* <p>Ensures that the output of applying the block after the fork is the same as applying the
* block first.
*/
@Test
public void testForkWithRevertOnSmallContractStorage() {
// ****** setup ******
// build a blockchain with CONCURRENT_THREADS_PER_TYPE blocks
List<ECKey> accounts = generateAccounts(10);
StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
StandaloneBlockchain sourceChain = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build().bc;
StandaloneBlockchain testChain = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build().bc;
assertThat(testChain).isNotEqualTo(sourceChain);
assertThat(testChain.genesis).isEqualTo(sourceChain.genesis);
long time = System.currentTimeMillis();
// add a block with contract deploy
ECKey sender = accounts.remove(0);
AionTransaction deployTx = deployContract(sender);
MiningBlock block = sourceChain.createNewMiningBlockInternal(sourceChain.genesis, Arrays.asList(deployTx), true, time / 10_000L).block;
Pair<ImportResult, AionBlockSummary> connectResult = sourceChain.tryToConnectAndFetchSummary(block);
AionTxReceipt receipt = connectResult.getRight().getReceipts().get(0);
assertThat(receipt.isSuccessful()).isTrue();
ImportResult result = connectResult.getLeft();
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
result = testChain.tryToConnect(block);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(testChain.getRepository().getRoot()).isEqualTo(sourceChain.getRepository().getRoot());
AionAddress contract = TxUtil.calculateContractAddress(receipt.getTransaction());
// add a block with transactions to both
List<AionTransaction> txs = generateTransactions(20, accounts, sourceChain.getRepository());
block = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), txs, true, time / 10_000L).block;
result = sourceChain.tryToConnect(block);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
result = testChain.tryToConnect(block);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(testChain.getRepository().getRoot()).isEqualTo(sourceChain.getRepository().getRoot());
// create a slow / fast block distinction
AionTransaction callTx = callSetValue2(sender, contract, 5, 6, BigInteger.ONE);
MiningBlock fastBlock = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(callTx), true, time / 10_000L).block;
callTx = callSetValue2(sender, contract, 1, 9, BigInteger.ONE);
MiningBlock slowBlock = new MiningBlock(sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(callTx), true, time / 10_000L).block);
MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(slowBlock.getHeader()).withTimestamp(time / 10_000L + 100).build();
slowBlock.updateHeader(newBlockHeader);
time += 100;
// sourceChain imports only fast block
assertThat(sourceChain.tryToConnect(fastBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
// testChain imports both blocks
assertThat(testChain.tryToConnect(fastBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(testChain.tryToConnect(slowBlock)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
// build two blocks with different contract storage calls
// the second block gets a higher total difficulty
callTx = callSetValue(sender, contract, 5, BigInteger.TWO);
MiningBlock lowBlock = testChain.createNewMiningBlockInternal(slowBlock, Arrays.asList(callTx), true, time / 10_000L + 101).block;
callTx = callSetValue(sender, contract, 9, BigInteger.TWO);
MiningBlock highBlock = sourceChain.createNewMiningBlockInternal(fastBlock, Arrays.asList(callTx), true, time / 10_000L).block;
// System.out.println("***highBlock TD: " + highBlock.getDifficultyBI());
// System.out.println("***lowBlock TD: " + lowBlock.getDifficultyBI());
assertThat(highBlock.getDifficultyBI()).isGreaterThan(lowBlock.getDifficultyBI());
// build first chain with highBlock applied directly
connectResult = sourceChain.tryToConnectAndFetchSummary(highBlock);
receipt = connectResult.getRight().getReceipts().get(0);
assertThat(receipt.isSuccessful()).isTrue();
result = connectResult.getLeft();
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
// collect the consensus information from the block & receipt
AionBlockSummary blockSummary = connectResult.getRight();
byte[] stateRoot = blockSummary.getBlock().getStateRoot();
byte[] blockReceiptsRoot = blockSummary.getBlock().getReceiptsRoot();
byte[] receiptTrieEncoded = receipt.getReceiptTrieEncoded();
// ****** test fork behavior ******
// first import lowBlock
assertThat(testChain.tryToConnect(lowBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
// next import highBlock causing the fork
connectResult = testChain.tryToConnectAndFetchSummary(highBlock);
receipt = connectResult.getRight().getReceipts().get(0);
assertThat(receipt.isSuccessful()).isTrue();
System.out.println(receipt);
result = connectResult.getLeft();
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
// collect the consensus information from the block & receipt
blockSummary = connectResult.getRight();
assertThat(testChain.getBestBlock()).isEqualTo(sourceChain.getBestBlock());
assertThat(blockSummary.getBlock().getStateRoot()).isEqualTo(stateRoot);
assertThat(blockSummary.getBlock().getReceiptsRoot()).isEqualTo(blockReceiptsRoot);
assertThat(receipt.getReceiptTrieEncoded()).isEqualTo(receiptTrieEncoded);
}
Aggregations