use of org.aion.zero.impl.types.BlockHeader in project aion by aionnetwork.
the class SyncHeaderRequestManagerTest method test_missingHeadersTrieRoot.
@Test
public void test_missingHeadersTrieRoot() {
List<BlockHeader> list = mock(List.class);
when(list.size()).thenReturn(10);
BlockHeader header = mock(BlockHeader.class);
when(header.getTxTrieRootWrapper()).thenReturn(EMPTY_TRIE_HASH);
when(list.get(0)).thenReturn(header);
srm.storeHeaders(1, list);
assertThat(srm.matchAndDropHeaders(1, 10, ByteArrayWrapper.wrap(new byte[32]))).isNull();
}
use of org.aion.zero.impl.types.BlockHeader in project aion by aionnetwork.
the class AionBlockchainImpl method createNewStakingBlock.
private StakingBlock createNewStakingBlock(Block parent, List<AionTransaction> txs, byte[] newSeed, byte[] signingPublicKey, byte[] coinbase) {
BlockHeader parentHdr = parent.getHeader();
byte[] sealedSeed = newSeed;
if (!forkUtility.isUnityForkActive(parentHdr.getNumber() + 1)) {
LOG.debug("Unity fork has not been enabled! Can't create the staking blocks");
return null;
}
byte[] parentSeed;
BigInteger newDiff;
if (parentHdr.getSealType() == Seal.PROOF_OF_STAKE) {
LOG.warn("Tried to create 2 PoS blocks in a row");
return null;
} else if (parentHdr.getSealType() == Seal.PROOF_OF_WORK) {
if (forkUtility.isUnityForkBlock(parentHdr.getNumber())) {
// this is the first PoS block, use all zeroes as seed, and totalStake / 10 as difficulty
parentSeed = GENESIS_SEED;
newDiff = calculateFirstPoSDifficultyAtBlock(parent);
} else if (forkUtility.isNonceForkBlock(parentHdr.getNumber())) {
BlockHeader parentStakingBlock = getParent(parentHdr).getHeader();
parentSeed = ((StakingBlockHeader) parentStakingBlock).getSeedOrProof();
newDiff = calculateFirstPoSDifficultyAtBlock(parent);
forkUtility.setNonceForkResetDiff(newDiff);
} else {
Block[] blockFamily = repository.getBlockStore().getTwoGenerationBlocksByHashWithInfo(parentHdr.getParentHash());
Objects.requireNonNull(blockFamily[0]);
BlockHeader parentStakingBlock = blockFamily[0].getHeader();
BlockHeader parentStakingBlocksParent = blockFamily[1].getHeader();
parentSeed = ((StakingBlockHeader) parentStakingBlock).getSeedOrProof();
newDiff = chainConfiguration.getUnityDifficultyCalculator().calculateDifficulty(parentStakingBlock, parentStakingBlocksParent);
}
} else {
throw new IllegalStateException("Invalid block type");
}
long newTimestamp;
AionAddress coinbaseAddress = new AionAddress(coinbase);
if (signingPublicKey != null) {
// Create block template for the external stakers.
byte[] proofHash = null;
if (forkUtility.isSignatureSwapForkBlock(parent.getNumber() - 1)) {
if (!VRF_Ed25519.verify(parentSeed, newSeed, signingPublicKey)) {
LOG.debug("Seed verification failed! previousProof:{} newProof:{} pKey:{}", ByteUtil.toHexString(parentSeed), ByteUtil.toHexString(newSeed), ByteUtil.toHexString(signingPublicKey));
return null;
}
proofHash = VRF_Ed25519.generateProofHash(newSeed);
} else if (forkUtility.isSignatureSwapForkActive(parent.getNumber() + 1)) {
byte[] parentSeedHash = VRF_Ed25519.generateProofHash(parentSeed);
if (!VRF_Ed25519.verify(parentSeedHash, newSeed, signingPublicKey)) {
LOG.debug("Seed verification failed! previousProof:{} newProof:{} pKey:{}", ByteUtil.toHexString(parentSeed), ByteUtil.toHexString(newSeed), ByteUtil.toHexString(signingPublicKey));
return null;
}
proofHash = VRF_Ed25519.generateProofHash(newSeed);
} else {
if (!ECKeyEd25519.verify(parentSeed, newSeed, signingPublicKey)) {
LOG.debug("Seed verification failed! previousSeed:{} newSeed:{} pKey:{}", ByteUtil.toHexString(parentSeed), ByteUtil.toHexString(newSeed), ByteUtil.toHexString(signingPublicKey));
return null;
}
if (forkUtility.isNonceForkActive(parentHdr.getNumber() + 1)) {
// new seed generation
BlockHeader parentStakingBlock = getParent(parentHdr).getHeader();
// retrieve components
parentSeed = ((StakingBlockHeader) parentStakingBlock).getSeedOrProof();
byte[] signerAddress = new AionAddress(AddressSpecs.computeA0Address(signingPublicKey)).toByteArray();
;
byte[] powMineHash = ((MiningBlock) parent).getHeader().getMineHash();
byte[] powNonce = ((MiningBlock) parent).getNonce();
int lastIndex = parentSeed.length + signerAddress.length + powMineHash.length + powNonce.length;
byte[] concatenated = new byte[lastIndex + 1];
System.arraycopy(parentSeed, 0, concatenated, 0, parentSeed.length);
System.arraycopy(signerAddress, 0, concatenated, parentSeed.length, signerAddress.length);
System.arraycopy(powMineHash, 0, concatenated, parentSeed.length + signerAddress.length, powMineHash.length);
System.arraycopy(powNonce, 0, concatenated, parentSeed.length + signerAddress.length + powMineHash.length, powNonce.length);
concatenated[lastIndex] = 0;
byte[] hash1 = h256(concatenated);
concatenated[lastIndex] = 1;
byte[] hash2 = h256(concatenated);
sealedSeed = new byte[hash1.length + hash2.length];
System.arraycopy(hash1, 0, sealedSeed, 0, hash1.length);
System.arraycopy(hash2, 0, sealedSeed, hash1.length, hash2.length);
}
}
AionAddress signingAddress = new AionAddress(AddressSpecs.computeA0Address(signingPublicKey));
BigInteger stakes = null;
try {
stakes = getStakingContractHelper().getEffectiveStake(signingAddress, coinbaseAddress, parent);
} catch (Exception e) {
LOG.error("Shutdown due to a fatal error encountered while getting the effective stake.", e);
System.exit(SystemExitCodes.FATAL_VM_ERROR);
}
if (stakes.signum() < 1) {
LOG.debug("The caller {} with coinbase {} has no stake ", signingAddress.toString(), coinbase.toString());
return null;
}
long newDelta = StakingDeltaCalculator.calculateDelta(proofHash == null ? sealedSeed : proofHash, newDiff, stakes);
newTimestamp = Long.max(parent.getHeader().getTimestamp() + newDelta, parent.getHeader().getTimestamp() + 1);
} else {
newTimestamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
if (parentHdr.getTimestamp() >= newTimestamp) {
newTimestamp = parentHdr.getTimestamp() + 1;
}
}
StakingBlock block;
try {
StakingBlockHeader.Builder headerBuilder = StakingBlockHeader.Builder.newInstance().withParentHash(parent.getHash()).withCoinbase(coinbaseAddress).withNumber(parentHdr.getNumber() + 1).withTimestamp(newTimestamp).withExtraData(minerExtraData).withTxTrieRoot(calcTxTrieRoot(txs)).withEnergyLimit(energyLimitStrategy.getEnergyLimit(parentHdr)).withDifficulty(ByteUtil.bigIntegerToBytes(newDiff, DIFFICULTY_BYTES)).withDefaultStateRoot().withDefaultReceiptTrieRoot().withDefaultLogsBloom().withDefaultSignature().withDefaultSigningPublicKey();
if (signingPublicKey != null) {
headerBuilder.withSigningPublicKey(signingPublicKey);
}
if (forkUtility.isSignatureSwapForkActive(parentHdr.getNumber() + 1)) {
headerBuilder.withProof(sealedSeed);
} else {
headerBuilder.withSeed(sealedSeed);
}
block = new StakingBlock(headerBuilder.build(), txs);
} catch (Exception e) {
throw new RuntimeException(e);
}
BigInteger transactionFee = blockPreSeal(parentHdr, block);
if (transactionFee == null) {
return null;
}
if (signingPublicKey != null) {
stakingBlockTemplate.putIfAbsent(ByteArrayWrapper.wrap(block.getHeader().getMineHash()), block);
}
LOG.debug("GetBlockTemp: {}", block.toString());
return block;
}
use of org.aion.zero.impl.types.BlockHeader 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.BlockHeader in project aion by aionnetwork.
the class SyncMgrTest method testRequestBodies_withFilteringOnBlockHash.
@Test
public void testRequestBodies_withFilteringOnBlockHash() {
BlockHeader header = mock(BlockHeader.class);
when(header.getNumber()).thenReturn(100L);
byte[] hash = Hex.decode("6fd8dae3304a9864f460ec7aec21bc94e14e34876e5dddd0a74d9c68ac7bc9ed");
when(header.getHash()).thenReturn(hash);
when(header.getTxTrieRootWrapper()).thenReturn(EMPTY_TRIE_HASH);
List<BlockHeader> list = new ArrayList<>();
list.add(header);
syncMgr.syncHeaderRequestManager.storeHeaders(1, list);
syncMgr.importedBlockHashes.put(ByteArrayWrapper.wrap(hash), true);
syncMgr.requestBodies(1, "peer1");
// ensure that 1 request was sent
verify(p2pMgr, never()).send(anyInt(), anyString(), any(ReqBlocksBodies.class));
assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(1, 1, EMPTY_TRIE_HASH)).isNull();
}
use of org.aion.zero.impl.types.BlockHeader in project aion by aionnetwork.
the class SyncMgrTest method testValidateAndAddHeaders_withImportedBlocks.
@Test
public void testValidateAndAddHeaders_withImportedBlocks() {
int nodeId = 1;
String displayId = "peer1";
List<BlockHeader> importedBlocks = new ArrayList<>();
importedBlocks.add(consecutiveHeaders.get(0));
importedBlocks.add(consecutiveHeaders.get(1));
syncMgr.importedBlockHashes.put(importedBlocks.get(0).getHashWrapper(), true);
syncMgr.importedBlockHashes.put(importedBlocks.get(1).getHashWrapper(), true);
List<BlockHeader> newHeaders = new ArrayList<>();
newHeaders.add(consecutiveHeaders.get(2));
newHeaders.add(consecutiveHeaders.get(3));
newHeaders.add(consecutiveHeaders.get(4));
List<BlockHeader> headers = new ArrayList<>();
headers.addAll(importedBlocks);
headers.addAll(newHeaders);
syncMgr.validateAndAddHeaders(nodeId, displayId, headers);
verify(p2pMgr, never()).errCheck(nodeId, displayId);
// Check that the sequential subset of headers was stored.
assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(nodeId, importedBlocks.size(), importedBlocks.get(0).getTxTrieRootWrapper())).isNull();
assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(nodeId, headers.size(), headers.get(0).getTxTrieRootWrapper())).isNull();
List<BlockHeader> stored = syncMgr.syncHeaderRequestManager.matchAndDropHeaders(nodeId, newHeaders.size(), newHeaders.get(0).getTxTrieRootWrapper());
assertThat(stored.size()).isEqualTo(newHeaders.size());
assertThat(stored).containsAllIn(newHeaders);
}
Aggregations