use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class ApiWeb3Aion method stratum_getHeaderByBlockNumber.
public RpcMsg stratum_getHeaderByBlockNumber(Object _params) {
Object _blockNum;
if (_params instanceof JSONArray) {
_blockNum = ((JSONArray) _params).opt(0);
} else {
return new RpcMsg(null, RpcError.INVALID_PARAMS, "Invalid parameters");
}
JSONObject obj = new JSONObject();
if (!JSONObject.NULL.equals(_blockNum)) {
String bnStr = _blockNum + "";
try {
int bnInt = Integer.decode(bnStr);
Block block = getBlockRaw(bnInt);
if (block != null && isPowBlock(block)) {
MiningBlockHeader header = (MiningBlockHeader) block.getHeader();
// 0 = success
obj.put("code", 0);
obj.put("nonce", toHexString(header.getNonce()));
obj.put("solution", toHexString(header.getSolution()));
obj.put("headerHash", toHexString(header.getMineHash()));
obj.putOpt("blockHeader", header.toJSON());
} else {
obj.put("message", "Fail - Unable to find block" + bnStr);
obj.put("code", -2);
}
} catch (Exception e) {
obj.put("message", bnStr + " must be an integer value");
obj.put("code", -3);
}
} else {
obj.put("message", "Missing block number");
obj.put("code", -1);
}
return new RpcMsg(obj);
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class BlockchainTestUtils method generateNewBlock.
/**
* @param chain blockchain implementation to be populated
* @param parent the parent block for the newly generated block
* @param accounts existing accounts
* @param txCount maximum number of transactions per block
* @implNote returns {@code null} if the parent block is not part of the chain
*/
public static Block generateNewBlock(StandaloneBlockchain chain, Block parent, List<ECKey> accounts, int txCount) {
if (!chain.isBlockStored(parent.getHash(), parent.getNumber()))
return null;
Block block;
AionRepositoryImpl repo = chain.getRepository();
List<AionTransaction> txs;
// generate transactions for correct root
byte[] originalRoot = repo.getRoot();
repo.syncToRoot(parent.getStateRoot());
txs = generateTransactions(txCount, accounts, repo);
repo.syncToRoot(originalRoot);
long time = System.currentTimeMillis();
block = chain.createNewMiningBlockInternal(parent, txs, true, time / TEN_THOUSAND_MS).block;
MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader((MiningBlockHeader) block.getHeader()).withExtraData(String.valueOf(time).getBytes()).build();
block.updateHeader(newBlockHeader);
return block;
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class BlockchainIndexIntegrityTest method testIndexIntegrityWithRecovery.
/**
* Test the index integrity check and recovery when the index database is incorrect.
*/
@Test
public void testIndexIntegrityWithRecovery() {
final int NUMBER_OF_BLOCKS = 5;
// build a blockchain with a few blocks
StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").build();
StandaloneBlockchain chain = bundle.bc;
Block bestBlock;
ImportResult result;
for (int i = 0; i < NUMBER_OF_BLOCKS; i++) {
bestBlock = chain.getBestBlock();
MiningBlock next = chain.createNewMiningBlock(bestBlock, Collections.emptyList(), true);
result = chain.tryToConnect(next);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
// adding side chain
next = chain.createNewMiningBlock(bestBlock, Collections.emptyList(), true);
MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(next.getHeader()).withExtraData("other".getBytes()).build();
next.updateHeader(newBlockHeader);
result = chain.tryToConnect(next);
assertThat(result).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
}
bestBlock = chain.getBestBlock();
assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
chain.getRepository().flush();
AionRepositoryImpl repo = chain.getRepository();
ByteArrayKeyValueDatabase indexDatabase = repo.getIndexDatabase();
// corrupting the index at level 2
ArrayStore<List<BlockInfo>> index = Stores.newArrayStore(indexDatabase, BLOCK_INFO_SERIALIZER);
List<BlockInfo> infos = index.get(2);
assertThat(infos.size()).isEqualTo(2);
for (BlockInfo bi : infos) {
bi.setTotalDifficulty(bi.getTotalDifficulty().add(BigInteger.TEN));
}
index.set(2, infos);
AionBlockStore blockStore = repo.getBlockStore();
// check that the index recovery succeeded
assertThat(blockStore.indexIntegrityCheck()).isEqualTo(AionBlockStore.IntegrityCheckResult.FIXED);
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class BlockchainTestUtils method addMiningBlock.
private static Pair<Block, ImportResult> addMiningBlock(StandaloneBlockchain chain, Block parent, List<AionTransaction> txs, long time, byte[] extraData) {
MiningBlock block = chain.createNewMiningBlockInternal(parent, txs, true, time / TEN_THOUSAND_MS).block;
MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(block.getHeader()).withExtraData(extraData).build();
block.updateHeader(newBlockHeader);
ImportResult result = chain.tryToConnect(block);
System.out.format("Created block with hash: %s, number: %6d, extra data: %6s, txs: %3d, import status: %20s %n", block.getShortHash(), block.getNumber(), new String(block.getExtraData()), block.getTransactionsList().size(), result.toString());
return Pair.of(block, result);
}
use of org.aion.zero.impl.types.MiningBlockHeader in project aion by aionnetwork.
the class BlockchainDataRecoveryTest method testRecoverIndexWithPartialIndex_ShorterSideChain.
/**
* Test the recovery of the index with start from the index of an ancestor block.
*/
@Test
public void testRecoverIndexWithPartialIndex_ShorterSideChain() {
final int EVEN_NUMBER_OF_BLOCKS = NUMBER_OF_BLOCKS % 2 == 0 ? NUMBER_OF_BLOCKS : NUMBER_OF_BLOCKS + 1;
// build a blockchain with a few blocks
StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build();
StandaloneBlockchain chain = bundle.bc;
AionRepositoryImpl repo = chain.getRepository();
BlockContext context;
List<AionTransaction> txs;
// adding common blocks
long time = System.currentTimeMillis();
for (int i = 0; i < EVEN_NUMBER_OF_BLOCKS / 2 - 1; i++) {
txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
context = chain.createNewMiningBlockInternal(chain.getBestBlock(), txs, true, time / 10000L);
assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
}
// splitting chains
Block mainChainBlock, sideChainBlock;
mainChainBlock = chain.getBestBlock();
sideChainBlock = mainChainBlock;
txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
context = chain.createNewMiningBlockInternal(mainChainBlock, txs, true, time / 10000L);
assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
mainChainBlock = context.block;
// starting side chain
txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
context = chain.createNewMiningBlockInternal(sideChainBlock, txs, true, time / 10000L);
MiningBlockHeader newHeader = MiningBlockHeader.Builder.newInstance().withHeader(context.block.getHeader()).withExtraData("other".getBytes()).build();
context.block.updateHeader(newHeader);
assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
sideChainBlock = context.block;
// building chains; sidechain will have missing index
Map<Long, byte[]> blocksToDelete = new HashMap<>();
List<MiningBlock> blocksToImportMainChain = new ArrayList<>();
List<MiningBlock> blocksToImportSideChain = new ArrayList<>();
for (int i = 0; i < EVEN_NUMBER_OF_BLOCKS / 2 - 1; i++) {
txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
context = chain.createNewMiningBlockInternal(mainChainBlock, txs, true, time / 10000L);
assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
mainChainBlock = context.block;
blocksToImportMainChain.add(context.block);
// adding side chain
txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
context = chain.createNewMiningBlockInternal(sideChainBlock, txs, true, time / 10000L);
assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
sideChainBlock = context.block;
blocksToDelete.put(sideChainBlock.getNumber(), sideChainBlock.getHash());
blocksToImportSideChain.add(context.block);
}
// making the main chain longer
txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
context = chain.createNewMiningBlockInternal(mainChainBlock, txs, true, time / 10000L);
assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
mainChainBlock = context.block;
Block bestBlock = chain.getBestBlock();
assertThat(bestBlock.getNumber()).isEqualTo(EVEN_NUMBER_OF_BLOCKS);
assertThat(bestBlock.getHash()).isEqualTo(mainChainBlock.getHash());
// delete index entries from the database
MockDB indexDatabase = (MockDB) repo.getIndexDatabase();
// 1: direct recovery call
repo.flush();
Map<Long, byte[]> deletedInfo = new HashMap<>();
for (Map.Entry<Long, byte[]> entry : blocksToDelete.entrySet()) {
byte[] indexKey = ByteUtil.intToBytes(entry.getKey().intValue());
// saving the data for checking recovery
deletedInfo.put(entry.getKey(), indexDatabase.get(indexKey).get());
// deleting the block info
indexDatabase.deleteAndCommit(indexKey);
// ensure that the index was corrupted
assertThat(repo.isIndexed(entry.getValue(), entry.getKey())).isFalse();
}
// call the recovery functionality for the main chain subsection
boolean worked = chain.recoverIndexEntry(repo, chain.getBlockByHash(mainChainBlock.getParentHash()));
// ensure that the index was corrupted only for the side chain
assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isFalse();
assertThat(repo.isIndexed(mainChainBlock.getHash(), mainChainBlock.getNumber())).isTrue();
assertThat(worked).isTrue();
// call the recovery functionality
worked = chain.recoverIndexEntry(repo, sideChainBlock);
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// ensure that the index was recovered
assertThat(worked).isTrue();
assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isTrue();
// check that the index information is correct
for (Map.Entry<Long, byte[]> entry : blocksToDelete.entrySet()) {
long level = entry.getKey();
byte[] hash = entry.getValue();
// checking at block store level
assertThat(repo.isIndexed(hash, level)).isTrue();
// checking at database level
byte[] indexKey = ByteUtil.intToBytes(entry.getKey().intValue());
// NOTE: this checks the correction of both main chain and side chain recovery
assertThat(deletedInfo.get(level)).isEqualTo(indexDatabase.get(indexKey).get());
}
// 2: recovery at import
repo.flush();
for (Map.Entry<Long, byte[]> entry : blocksToDelete.entrySet()) {
byte[] indexKey = ByteUtil.intToBytes(entry.getKey().intValue());
// deleting the block info
indexDatabase.deleteAndCommit(indexKey);
// ensure that the index was corrupted
assertThat(repo.isIndexed(entry.getValue(), entry.getKey())).isFalse();
}
// call the recovery functionality indirectly for main chain
for (MiningBlock block : blocksToImportMainChain) {
// index missing before import
assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isFalse();
assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
// index present after import
assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
}
// ensure that the index was corrupted only for the side chain
assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isFalse();
assertThat(repo.isIndexed(mainChainBlock.getHash(), mainChainBlock.getNumber())).isTrue();
// call the recovery functionality indirectly for side chain
for (MiningBlock block : blocksToImportSideChain) {
// index missing before import
assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isFalse();
assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
// index present after import
assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
}
// ensure that the index was corrupted only for the side chain
assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isTrue();
assertThat(repo.isIndexed(mainChainBlock.getHash(), mainChainBlock.getNumber())).isTrue();
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// check that the index information is correct at database level
for (Long key : blocksToDelete.keySet()) {
// checking at database level
byte[] indexKey = ByteUtil.intToBytes(key.intValue());
// NOTE: this checks the correction of both main chain and side chain recovery
assertThat(deletedInfo.get(key)).isEqualTo(indexDatabase.get(indexKey).get());
}
}
Aggregations