use of org.aion.zero.impl.types.MiningBlock in project aion by aionnetwork.
the class BlockchainDataRecoveryTest method testRecoverWorldState_wDeletedBlock.
@Test
public void testRecoverWorldState_wDeletedBlock() {
// 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;
// all blocks will be incorrect
long time = System.currentTimeMillis();
List<byte[]> statesToDelete = new ArrayList<>();
List<MiningBlock> blocksToImport = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_BLOCKS; 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);
statesToDelete.add(context.block.getStateRoot());
// skipping middle block
if (context.block.getNumber() != NUMBER_OF_BLOCKS / 2) {
blocksToImport.add(context.block);
}
}
Block bestBlock = chain.getBestBlock();
assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
// delete middle block from db
Block middle = chain.getBlockByNumber(NUMBER_OF_BLOCKS / 2);
MockDB database = (MockDB) repo.getBlockDatabase();
database.deleteAndCommit(middle.getHash());
// delete some world state root entries from the database
TrieImpl trie = (TrieImpl) repo.getWorldState();
database = (MockDB) repo.getStateDatabase();
// 1: direct recovery call
repo.flush();
for (byte[] key : statesToDelete) {
database.deleteAndCommit(key);
assertThat(trie.isValidRoot(key)).isFalse();
}
// ensure that the world state was corrupted
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// call the recovery functionality
assertThat(chain.recoverWorldState(repo, bestBlock)).isFalse();
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// ensure that the world state could not be recovered
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// 2: recovery at import
repo.flush();
for (byte[] key : statesToDelete) {
database.deleteAndCommit(key);
assertThat(trie.isValidRoot(key)).isFalse();
}
// ensure that the world state was corrupted
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// call the recovery functionality indirectly
for (MiningBlock block : blocksToImport) {
// state missing before import
assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
if (block.getNumber() < middle.getNumber()) {
// state present after import
assertThat(trie.isValidRoot(block.getStateRoot())).isTrue();
} else {
// block after missing one cannot be recovered
assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
}
}
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// ensure that the world state is ok
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// importing middle block
assertThat(chain.tryToConnect(middle)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
// call the recovery functionality indirectly
for (MiningBlock block : blocksToImport) {
// checking only failed blocks from before
if (block.getNumber() > middle.getNumber()) {
// state missing before import
assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
// state present after import
assertThat(trie.isValidRoot(block.getStateRoot())).isTrue();
}
}
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// ensure that the world state is ok
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isTrue();
}
use of org.aion.zero.impl.types.MiningBlock in project aion by aionnetwork.
the class BlockchainDataRecoveryTest method testRecoverWorldStateWithoutGenesis.
/**
* Test the recovery of the world state when missing the genesis block state.
*
* <p>Under these circumstances the recovery will fail.
*/
@Test
public void testRecoverWorldStateWithoutGenesis() {
// 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;
// all blocks will be incorrect
long time = System.currentTimeMillis();
List<MiningBlock> blocksToImport = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_BLOCKS; 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);
blocksToImport.add(context.block);
}
Block bestBlock = chain.getBestBlock();
assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
// delete some world state root entries from the database
TrieImpl trie = (TrieImpl) repo.getWorldState();
MockDB database = (MockDB) repo.getStateDatabase();
// 1: direct recovery call
repo.flush();
List<byte[]> statesToDelete = new ArrayList<>();
Iterator<byte[]> iterator = database.keys();
while (iterator.hasNext()) {
statesToDelete.add(iterator.next());
}
for (byte[] key : statesToDelete) {
database.deleteAndCommit(key);
assertThat(trie.isValidRoot(key)).isFalse();
}
// ensure that the world state was corrupted
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// call the recovery functionality
boolean worked = chain.recoverWorldState(repo, bestBlock);
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// ensure that the world state was not recovered
assertThat(worked).isFalse();
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// 2: recovery at import
repo.flush();
for (byte[] key : statesToDelete) {
database.deleteAndCommit(key);
assertThat(trie.isValidRoot(key)).isFalse();
}
// ensure that the world state was corrupted
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
// call the recovery functionality indirectly
for (MiningBlock block : blocksToImport) {
// state missing before import
assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
// state missing after import (because there is not genesis to recover from)
assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
}
// ensure that the blockchain is ok
assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
// ensure that the world state is ok
assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
}
use of org.aion.zero.impl.types.MiningBlock in project aion by aionnetwork.
the class TxTest method testTxInfoToJsonDetails.
@Test
public void testTxInfoToJsonDetails() {
byte[] emptyByteArray = new byte[32];
Arrays.fill(emptyByteArray, (byte) 0);
AionAddress coinBase = new AionAddress(Arrays.copyOf(emptyByteArray, 32));
byte[] parentHash = HashUtil.h256("parent".getBytes());
byte[] bloom = BloomFilter.create().getBloomFilterBytes();
byte[] difficulty = BigInteger.TEN.toByteArray();
long blockNumber = 1;
long timestamp = System.currentTimeMillis();
byte[] extraData = new byte[0];
byte[] nonce = BigInteger.valueOf(100).toByteArray();
byte[] receiptsRoot = Arrays.copyOf(emptyByteArray, 32);
byte[] transactionsRoot = Arrays.copyOf(emptyByteArray, 32);
byte[] stateRoot = Arrays.copyOf(emptyByteArray, 32);
byte[] solution = new byte[256];
long nrgConsumed = 0L;
long nrgLimit = 0;
byte[] txNonce = ByteUtil.bigIntegerToBytes(BigInteger.ONE);
AionAddress to = new AionAddress(emptyByteArray);
AionAddress from = new AionAddress(emptyByteArray);
byte[] value = ByteUtil.bigIntegerToBytes(BigInteger.TEN);
byte[] data = Arrays.copyOf(emptyByteArray, 32);
long txNrgLimit = 10L;
long txNrgPrice = 10L;
byte type = 0b1;
long txNrgUsed = 5L;
AionTransaction transaction = AionTransaction.createWithoutKey(txNonce, from, to, value, data, txNrgLimit, txNrgPrice, type, null);
AionTxReceipt txReceipt = new AionTxReceipt();
txReceipt.setTransaction(transaction);
txReceipt.setNrgUsed(txNrgUsed);
MiningBlock block = new MiningBlock(parentHash, coinBase, bloom, difficulty, blockNumber, timestamp, extraData, nonce, receiptsRoot, transactionsRoot, stateRoot, List.of(transaction), solution, nrgConsumed, nrgLimit);
byte[] hash = block.getHash();
JSONObject object = Tx.aionTxInfoToDetailsJSON(AionTxInfo.newInstance(txReceipt, block.getHashWrapper(), 0), block);
assertNotNull(object);
assertEquals(ByteUtil.byteArrayToLong(txNonce), object.get("nonce"));
assertEquals(StringUtils.toJsonHex(data), object.get("input"));
assertEquals(StringUtils.toJsonHex(to.toByteArray()), object.get("to"));
assertEquals(StringUtils.toJsonHex(from.toByteArray()), object.get("from"));
assertEquals(txNrgLimit, object.get("nrg"));
assertEquals(StringUtils.toJsonHex(value), object.get("value"));
assertEquals(StringUtils.toJsonHex(txNrgPrice), object.get("nrgPrice"));
assertEquals(new NumericalValue(transaction.getTimestamp()).toHexString(), object.get("timestamp"));
assertEquals(StringUtils.toJsonHex(blockNumber), object.get("blockNumber"));
assertEquals(StringUtils.toJsonHex(hash), object.get("blockHash"));
assertEquals("", object.get("error"));
assertEquals(new NumericalValue(value).toHexString(), object.get("value"));
assertFalse(object.getBoolean("hasInternalTransactions"));
assertTrue(object.getJSONArray("logs").isEmpty());
assertEquals(new NumericalValue(txNrgUsed).toHexString(), object.get("nrgUsed"));
assertEquals(new NumericalValue(txNrgUsed).toHexString(), object.get("gasUsed"));
byte[] onesArray = new byte[32];
byte[] twosArray = new byte[32];
Arrays.fill(onesArray, (byte) 1);
Arrays.fill(twosArray, (byte) 2);
byte[] logData = new byte[32];
Arrays.fill(logData, (byte) 7);
List<byte[]> topics = List.of(onesArray, twosArray);
Log txLog = Log.topicsAndData(to.toByteArray(), topics, logData);
AionTransaction transactionWithLog = AionTransaction.createWithoutKey(txNonce, from, to, value, data, txNrgLimit, txNrgPrice, type, null);
AionTxReceipt txReceiptWithLog = new AionTxReceipt();
txReceiptWithLog.setLogs(List.of(txLog));
txReceiptWithLog.setTransaction(transactionWithLog);
txReceiptWithLog.setNrgUsed(txNrgUsed);
MiningBlock blockWithLog = new MiningBlock(parentHash, coinBase, bloom, difficulty, blockNumber, timestamp, extraData, nonce, receiptsRoot, transactionsRoot, stateRoot, List.of(transactionWithLog), solution, nrgConsumed, nrgLimit);
JSONObject jsonWithLogs = Tx.aionTxInfoToDetailsJSON(AionTxInfo.newInstance(txReceiptWithLog, blockWithLog.getHashWrapper(), 0), blockWithLog);
assertNotNull(jsonWithLogs);
List<Object> jsonArray = jsonWithLogs.getJSONArray("logs").toList();
for (Object log : jsonArray) {
assertEquals(StringUtils.toJsonHex(to.toByteArray()), ((Map) log).get("address"));
assertEquals(StringUtils.toJsonHex(logData), ((Map) log).get("data"));
ArrayList jsonTopics = (ArrayList) ((Map) log).get("topics");
for (int i = 0; i < topics.size(); i++) {
assertEquals(StringUtils.toJsonHex(topics.get(i)), jsonTopics.get(i));
}
}
}
use of org.aion.zero.impl.types.MiningBlock in project aion by aionnetwork.
the class BlkTest method aionBlockDetailsToJsonTest.
@Test
public void aionBlockDetailsToJsonTest() {
JSONObject nullObject = Blk.aionBlockDetailsToJson(null, Collections.emptyList(), null, null, null);
assertNull(nullObject);
byte[] emptyByteArray = new byte[32];
Arrays.fill(emptyByteArray, (byte) 0);
AionAddress coinBase = new AionAddress(Arrays.copyOf(emptyByteArray, 32));
byte[] parentHash = HashUtil.h256("parent".getBytes());
byte[] bloom = BloomFilter.create().getBloomFilterBytes();
byte[] difficulty = BigInteger.TEN.toByteArray();
long blockNumber = 1;
long timestamp = System.currentTimeMillis();
byte[] extraData = new byte[0];
byte[] nonce = BigInteger.valueOf(100).toByteArray();
byte[] receiptsRoot = Arrays.copyOf(emptyByteArray, 32);
byte[] transactionsRoot = Arrays.copyOf(emptyByteArray, 32);
byte[] stateRoot = Arrays.copyOf(emptyByteArray, 32);
byte[] solution = new byte[256];
long nrgConsumed = 0L;
long nrgLimit = 0;
BigInteger totalDifficulty = BigInteger.valueOf(20);
MiningBlock block = new MiningBlock(parentHash, coinBase, bloom, difficulty, blockNumber, timestamp, extraData, nonce, receiptsRoot, transactionsRoot, stateRoot, Collections.emptyList(), solution, nrgConsumed, nrgLimit);
byte[] hash = block.getHash();
JSONObject blkObject = Blk.aionBlockDetailsToJson(block, Collections.emptyList(), timestamp - 10, totalDifficulty, BigInteger.valueOf(1).pow(18));
assertEquals(blkObject.get("miner"), StringUtils.toJsonHex(coinBase.toString()));
assertEquals(blkObject.get("number"), blockNumber);
assertEquals(blkObject.get("logsBloom"), StringUtils.toJsonHex(block.getLogBloom()));
assertEquals(blkObject.get("stateRoot"), StringUtils.toJsonHex(stateRoot));
assertEquals(blkObject.get("blockTime"), 10L);
assertEquals(blkObject.get("timestamp"), StringUtils.toJsonHex(timestamp));
assertEquals(blkObject.get("hash"), StringUtils.toJsonHex(hash));
assertEquals(blkObject.get("parentHash"), StringUtils.toJsonHex(parentHash));
assertEquals(blkObject.get("receiptsRoot"), StringUtils.toJsonHex(receiptsRoot));
assertEquals(blkObject.get("difficulty"), StringUtils.toJsonHex(difficulty));
assertEquals(blkObject.get("totalDifficulty"), StringUtils.toJsonHex(totalDifficulty));
assertEquals(blkObject.get("nonce"), StringUtils.toJsonHex(nonce));
assertEquals(blkObject.get("solution"), StringUtils.toJsonHex(solution));
assertEquals(blkObject.get("gasUsed"), StringUtils.toJsonHex(block.getHeader().getEnergyConsumed()));
assertEquals(blkObject.get("gasLimit"), StringUtils.toJsonHex(block.getHeader().getEnergyLimit()));
assertEquals(blkObject.get("nrgUsed"), StringUtils.toJsonHex(block.getHeader().getEnergyConsumed()));
assertEquals(blkObject.get("nrgLimit"), StringUtils.toJsonHex(block.getHeader().getEnergyLimit()));
assertEquals(blkObject.get("extraData"), StringUtils.toJsonHex(block.getExtraData()));
assertEquals(blkObject.get("size"), block.size());
assertEquals(blkObject.get("numTransactions"), 0);
assertEquals(blkObject.get("txTrieRoot"), StringUtils.toJsonHex(block.getTxTrieRoot()));
assertEquals(blkObject.get("blockReward"), new NumericalValue(BigInteger.valueOf(1).pow(18)).toHexString());
JSONArray array = (JSONArray) blkObject.get("transactions");
assertTrue(array.isEmpty());
block = new MiningBlock(parentHash, coinBase, bloom, difficulty, 0, timestamp, extraData, nonce, receiptsRoot, transactionsRoot, stateRoot, Collections.emptyList(), solution, nrgConsumed, nrgLimit);
blkObject = Blk.aionBlockDetailsToJson(block, Collections.emptyList(), null, totalDifficulty, BigInteger.valueOf(1).pow(18));
assertEquals(blkObject.get("blockTime"), 0);
block = new MiningBlock(parentHash, coinBase, bloom, difficulty, 10, timestamp, extraData, nonce, receiptsRoot, transactionsRoot, stateRoot, Collections.emptyList(), solution, nrgConsumed, nrgLimit);
blkObject = Blk.aionBlockDetailsToJson(block, Collections.emptyList(), null, totalDifficulty, BigInteger.valueOf(1).pow(18));
assertEquals(blkObject.get("blockTime"), JSONObject.NULL);
}
use of org.aion.zero.impl.types.MiningBlock in project aion by aionnetwork.
the class ApiAion0 method getRsp_getBlockDetails.
private List<Message.t_BlockDetail> getRsp_getBlockDetails(List<Block> blks) {
return blks.parallelStream().filter(Objects::nonNull).map(blk -> {
Message.t_BlockDetail.Builder builder;
if (blk.getHeader().getSealType() == Seal.PROOF_OF_WORK) {
MiningBlock b = (MiningBlock) blk;
builder = Message.t_BlockDetail.newBuilder().setBlockNumber(b.getNumber()).setDifficulty(ByteString.copyFrom(b.getDifficulty())).setExtraData(ByteString.copyFrom(b.getExtraData())).setHash(ByteString.copyFrom(b.getHash())).setLogsBloom(ByteString.copyFrom(b.getLogBloom())).setMinerAddress(ByteString.copyFrom(b.getCoinbase().toByteArray())).setNonce(ByteString.copyFrom(b.getNonce())).setNrgConsumed(b.getNrgConsumed()).setNrgLimit(b.getNrgLimit()).setParentHash(ByteString.copyFrom(b.getParentHash())).setTimestamp(b.getTimestamp()).setTxTrieRoot(ByteString.copyFrom(b.getTxTrieRoot())).setReceiptTrieRoot(ByteString.copyFrom(b.getReceiptsRoot())).setStateRoot(ByteString.copyFrom(b.getStateRoot())).setSize(b.size()).setSolution(ByteString.copyFrom(b.getHeader().getSolution())).setTotalDifficulty(ByteString.copyFrom(blk.getTotalDifficulty().toByteArray()));
} else if (blk.getHeader().getSealType() == Seal.PROOF_OF_STAKE) {
StakingBlock b = (StakingBlock) blk;
builder = Message.t_BlockDetail.newBuilder().setBlockNumber(b.getNumber()).setDifficulty(ByteString.copyFrom(b.getDifficulty())).setExtraData(ByteString.copyFrom(b.getExtraData())).setHash(ByteString.copyFrom(b.getHash())).setLogsBloom(ByteString.copyFrom(b.getLogBloom())).setMinerAddress(ByteString.copyFrom(b.getCoinbase().toByteArray())).setNonce(ByteString.copyFrom(new byte[0])).setNrgConsumed(b.getNrgConsumed()).setNrgLimit(b.getNrgLimit()).setParentHash(ByteString.copyFrom(b.getParentHash())).setTimestamp(b.getTimestamp()).setTxTrieRoot(ByteString.copyFrom(b.getTxTrieRoot())).setReceiptTrieRoot(ByteString.copyFrom(b.getReceiptsRoot())).setStateRoot(ByteString.copyFrom(b.getStateRoot())).setSize(b.size()).setSolution(ByteString.copyFrom(new byte[0])).setTotalDifficulty(ByteString.copyFrom(blk.getTotalDifficulty().toByteArray()));
} else {
throw new IllegalStateException("Invalid block type!");
}
List<AionTransaction> txs = blk.getTransactionsList();
List<Message.t_TxDetail> tds = txs.parallelStream().filter(Objects::nonNull).map((AionTransaction tx) -> {
AionTxInfo ti = ((AionBlockchainImpl) this.ac.getAionHub().getBlockchain()).getTransactionInfoLite(tx.getTransactionHash(), blk.getHeader().getHash());
List<Message.t_LgEle> tles = ti.getReceipt().getLogInfoList().parallelStream().map(log -> {
List<String> topics = new ArrayList<>();
for (int i = 0; i < log.copyOfTopics().size(); i++) {
topics.add(StringUtils.toJsonHex(log.copyOfTopics().get(i)));
}
return Message.t_LgEle.newBuilder().setData(ByteString.copyFrom(log.copyOfData())).setAddress(ByteString.copyFrom(log.copyOfAddress())).addAllTopics(topics).build();
}).filter(Objects::nonNull).collect(Collectors.toList());
Message.t_TxDetail.Builder tdBuilder = Message.t_TxDetail.newBuilder().setData(ByteString.copyFrom(tx.getData())).setTo(ByteString.copyFrom(tx.getDestinationAddress() == null ? EMPTY_BYTE_ARRAY : tx.getDestinationAddress().toByteArray())).setFrom(ByteString.copyFrom(tx.getSenderAddress().toByteArray())).setNonce(ByteString.copyFrom(tx.getNonce())).setValue(ByteString.copyFrom(tx.getValue())).setNrgConsumed(ti.getReceipt().getEnergyUsed()).setNrgPrice(tx.getEnergyPrice()).setTxHash(ByteString.copyFrom(tx.getTransactionHash())).setTxIndex(ti.getIndex()).setType(ByteString.copyFrom(new byte[] { tx.getType() })).addAllLogs(tles);
return tdBuilder.build();
}).filter(Objects::nonNull).collect(Collectors.toList());
return builder.addAllTx(tds).build();
}).filter(Objects::nonNull).collect(Collectors.toList());
}
Aggregations