use of org.aion.zero.impl.types.StakingBlock 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.StakingBlock in project aion by aionnetwork.
the class AionImpl method getStakingBlockTemplate.
// Returns null if we're waiting on a Mining block, or if creating a new block template failed for some reason
@Override
public StakingBlock getStakingBlockTemplate(byte[] newSeed, byte[] signingPublicKey, byte[] coinbase) {
lock.lock();
try {
Block best = getBlockchain().getBestBlock();
LOG_GEN.debug("getStakingBlockTemplate best:{}", best);
if (best.getHeader().getSealType() == Seal.PROOF_OF_STAKE) {
return null;
} else {
return getBlockchain().createStakingBlockTemplate(best, getAionHub().getPendingState().getPendingTransactions(), signingPublicKey, newSeed, coinbase);
}
} finally {
lock.unlock();
}
}
use of org.aion.zero.impl.types.StakingBlock in project aion by aionnetwork.
the class BlockchainTestUtils method addStakingBlock.
public static Pair<Block, ImportResult> addStakingBlock(StandaloneBlockchain chain, Block parent, List<AionTransaction> txs, ECKey key) {
byte[] parentSeed = chain.forkUtility.isUnityForkBlock(parent.getNumber()) ? StakingBlockHeader.GENESIS_SEED : ((StakingBlock) chain.getBlockByHash(parent.getParentHash())).getSeed();
byte[] newSeed = key.sign(parentSeed).getSignature();
StakingBlock block = chain.createStakingBlockTemplate(parent, txs, key.getPubKey(), newSeed, new AionAddress(key.getAddress()).toByteArray());
if (block == null) {
return null;
}
byte[] mineHashSig = key.sign(block.getHeader().getMineHash()).getSignature();
block.seal(mineHashSig, key.getPubKey());
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.StakingBlock in project aion by aionnetwork.
the class BlockchainTestUtils method generateNextStakingBlock.
/**
* Generates a single staking block (containing the given transactions) on top of the given chain.
* Does not import the block.
*
* @param chain blockchain implementation to be extended with the new block
* @param parent the parent for the block to be generated
* @param transactions list of transactions to be included in the block
* @param producer the staker key that will create and sign the block
* @return the generated block
*/
public static Block generateNextStakingBlock(StandaloneBlockchain chain, Block parent, List<AionTransaction> transactions, ECKey producer) {
// get the parent seed
byte[] parentSeed = chain.forkUtility.isUnityForkBlock(parent.getNumber()) ? StakingBlockHeader.GENESIS_SEED : ((StakingBlock) chain.getBlockByHash(parent.getParentHash())).getSeed();
// SignatureSchemeSwap check
byte[] newSeedOrProof;
if (chain.forkUtility.isSignatureSwapForkBlock(parent.getNumber() - 1)) {
newSeedOrProof = VRF_Ed25519.generateProof(parentSeed, producer.getPrivKeyBytes());
} else if (chain.forkUtility.isSignatureSwapForkActive(parent.getNumber() + 1)) {
byte[] hash = VRF_Ed25519.generateProofHash(parentSeed);
newSeedOrProof = VRF_Ed25519.generateProof(hash, producer.getPrivKeyBytes());
} else {
newSeedOrProof = producer.sign(parentSeed).getSignature();
}
// create staking block
StakingBlock block = chain.createStakingBlockTemplate(parent, transactions, producer.getPubKey(), newSeedOrProof, new AionAddress(producer.getAddress()).toByteArray());
if (block == null) {
return null;
}
// seal staking block
byte[] mineHashSig = producer.sign(block.getHeader().getMineHash()).getSignature();
block.seal(mineHashSig, producer.getPubKey());
return block;
}
use of org.aion.zero.impl.types.StakingBlock 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