use of org.aion.types.AionAddress 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.types.AionAddress in project aion by aionnetwork.
the class AionBlockchainImpl method balanceRollback.
/**
* SQ4-142
* Rollback the balance for the mistake transactions
*/
private void balanceRollback() {
List<byte[]> rollbackTxHash = CfgAion.inst().getFork().getRollbackTx();
if (rollbackTxHash == null) {
LOG.debug("no rollback transaction");
return;
}
int accountDeleted = 0;
for (byte[] hash : rollbackTxHash) {
AionTxInfo info = getTransactionInfo(hash);
if (info == null) {
throw new IllegalStateException("the database missing the rollback transaction:" + ByteUtil.toHexString(hash) + "\n" + "Please re-sync your database.");
}
AionAddress sender = info.getReceipt().getTransaction().getSenderAddress();
AionAddress receiver = info.getReceipt().getTransaction().getDestinationAddress();
BigInteger balance = info.getReceipt().getTransaction().getValueBI();
LOG.debug("sender {}, receiver {}, balance {}", sender, receiver, balance);
AccountState stateReceiver = track.getAccountState(receiver);
if (stateReceiver == null) {
throw new IllegalStateException("missing receiver's state of the rollback transaction: " + receiver);
}
if (stateReceiver.isDeleted()) {
throw new IllegalStateException("the receiver's state has been deleted: " + receiver);
}
if (stateReceiver.getBalance().compareTo(balance) >= 0) {
track.addBalance(sender, balance);
track.addBalance(receiver, balance.negate());
} else {
throw new IllegalStateException("the receiver state of the balance cannot be negative: " + receiver);
}
if (stateReceiver.getBalance().equals(ZERO)) {
track.deleteAccount(receiver);
accountDeleted++;
LOG.debug("deletedAccount: {}", receiver);
}
}
LOG.debug("rollback transactions: {}, account deleted: {}", rollbackTxHash.size(), accountDeleted);
}
use of org.aion.types.AionAddress in project aion by aionnetwork.
the class AionBlockchainImpl method applyBlock.
private AionBlockSummary applyBlock(Block block) {
long saveTime = System.nanoTime();
List<AionTxReceipt> receipts = new ArrayList<>();
List<AionTxExecSummary> summaries = new ArrayList<>();
if (!block.getTransactionsList().isEmpty()) {
// might apply the block before the 040 fork point.
boolean fork040Enable = forkUtility.is040ForkActive(block.getNumber());
if (fork040Enable) {
TransactionTypeRule.allowAVMContractTransaction();
}
if (forkUtility.isSignatureSwapForkActive(block.getNumber())) {
HashUtil.setAfterSignatureSwap();
} else {
HashUtil.setBeforeSignatureSwap();
}
try {
// Booleans moved out here so their meaning is explicit.
boolean isLocalCall = false;
boolean incrementSenderNonce = true;
boolean checkBlockEnergyLimit = false;
List<AionTxExecSummary> executionSummaries = BulkExecutor.executeAllTransactionsInBlock(block.getDifficulty(), block.getNumber(), block.getTimestamp(), block.getNrgLimit(), block.getCoinbase(), block.getTransactionsList(), track, isLocalCall, incrementSenderNonce, fork040Enable, checkBlockEnergyLimit, LOGGER_VM, getPostExecutionWorkForApplyBlock(repository), executionTypeForAVM, cachedBlockNumberForAVM, forkUtility.isUnityForkActive(block.getNumber()), forkUtility.isSignatureSwapForkActive(block.getNumber()));
// Check for rejected transaction already included in the chain.
if (isException(block.getNumber())) {
for (AionTxExecSummary summary : executionSummaries) {
if (summary.isRejected()) {
AionTxReceipt receipt = summary.getReceipt();
receipt.setNrgUsed(receipt.getTransaction().getEnergyLimit());
}
}
}
for (AionTxExecSummary summary : executionSummaries) {
receipts.add(summary.getReceipt());
summaries.add(summary);
}
} catch (VmFatalException e) {
LOG.error("Shutdown due to a VM fatal error.", e);
System.exit(SystemExitCodes.FATAL_VM_ERROR);
}
}
Map<AionAddress, BigInteger> rewards = addReward(block);
return new AionBlockSummary(block, rewards, receipts, summaries);
}
use of org.aion.types.AionAddress in project aion by aionnetwork.
the class AionBlockchainImpl method generatePreBlock.
/**
* For generating the necessary transactions for a block
*
* @param block
* @return
*/
private RetValidPreBlock generatePreBlock(Block block) {
long saveTime = System.nanoTime();
List<AionTxReceipt> receipts = new ArrayList<>();
List<AionTxExecSummary> summaries = new ArrayList<>();
List<AionTransaction> transactions = new ArrayList<>();
if (!block.getTransactionsList().isEmpty()) {
boolean fork040Enable = forkUtility.is040ForkActive(block.getNumber());
if (fork040Enable) {
TransactionTypeRule.allowAVMContractTransaction();
}
try {
// Booleans moved out here so their meaning is explicit.
boolean isLocalCall = false;
boolean incrementSenderNonce = true;
boolean checkBlockEnergyLimit = true;
List<AionTxExecSummary> executionSummaries = BulkExecutor.executeAllTransactionsInBlock(block.getDifficulty(), block.getNumber(), block.getTimestamp(), block.getNrgLimit(), block.getCoinbase(), block.getTransactionsList(), track, isLocalCall, incrementSenderNonce, fork040Enable, checkBlockEnergyLimit, LOGGER_VM, getPostExecutionWorkForGeneratePreBlock(repository), BlockCachingContext.PENDING, bestBlock.getNumber(), forkUtility.isUnityForkActive(block.getNumber()), forkUtility.isSignatureSwapForkActive(block.getNumber()));
for (AionTxExecSummary summary : executionSummaries) {
if (!summary.isRejected()) {
transactions.add(summary.getTransaction());
receipts.add(summary.getReceipt());
summaries.add(summary);
}
}
} catch (VmFatalException e) {
LOG.error("Shutdown due to a VM fatal error.", e);
System.exit(SystemExitCodes.FATAL_VM_ERROR);
}
}
Map<AionAddress, BigInteger> rewards = addReward(block);
return new RetValidPreBlock(transactions, rewards, receipts, summaries);
}
use of org.aion.types.AionAddress in project aion by aionnetwork.
the class TokenBridgeContractTest method testTransferInsufficientValidatorSignatures.
@Test
public void testTransferInsufficientValidatorSignatures() {
// override defaults
PrecompiledTransactionContext initializationContext = context(OWNER_ADDR, CONTRACT_ADDR);
this.contract = new TokenBridgeContract(initializationContext, ExternalStateForTests.usingRepository(this.repository), OWNER_ADDR, CONTRACT_ADDR);
this.connector = this.contract.getConnector();
ListFVM encodingList = new ListFVM();
for (ECKey k : members) {
encodingList.add(new AddressFVM(k.getAddress()));
}
byte[] payload = new AbiEncoder(BridgeFuncSig.SIG_RING_INITIALIZE.getSignature(), encodingList).encodeBytes();
PrecompiledTransactionResult result = this.contract.execute(payload, DEFAULT_NRG);
assertTrue(result.getStatus().isSuccess());
// set relayer
byte[] callPayload = new AbiEncoder(BridgeFuncSig.SIG_SET_RELAYER.getSignature(), new AddressFVM(members[0].getAddress())).encodeBytes();
PrecompiledTransactionResult transferResult = this.contract.execute(callPayload, DEFAULT_NRG);
assertTrue(transferResult.getStatus().isSuccess());
// override defaults
this.repository.addBalance(CONTRACT_ADDR, BigInteger.TEN);
// we create a new token bridge contract here because we
// need to change the execution context
PrecompiledTransactionContext submitBundleContext = context(new AionAddress(members[0].getAddress()), CONTRACT_ADDR);
this.contract = new TokenBridgeContract(submitBundleContext, ExternalStateForTests.usingRepository(this.repository), OWNER_ADDR, CONTRACT_ADDR);
this.connector = this.contract.getConnector();
// assemble the payload
byte[] blockHash = HashUtil.h256("blockHash".getBytes());
BridgeTransfer[] transfers = new BridgeTransfer[5];
for (int i = 0; i < 5; i++) {
// generate a unique sourceTransactionHash for each transfer
byte[] sourceTransactionHash = HashUtil.h256(Integer.toString(i).getBytes());
transfers[i] = BridgeTransfer.getInstance(BigInteger.ONE, AddressSpecs.computeA0Address(HashUtil.h256(Integer.toHexString(i).getBytes())), sourceTransactionHash);
}
byte[] payloadHash = BridgeUtilities.computeBundleHash(blockHash, transfers);
// ATB-4, do one assert here to check that transactionHash is not set
assertThat(this.contract.execute(ByteUtil.merge(BridgeFuncSig.PURE_ACTION_MAP.getBytes(), payloadHash), 21000L).getReturnData()).isEqualTo(ByteUtil.EMPTY_WORD);
// only give 3/5 signatures
byte[][] signatures = new byte[3][];
signatures[0] = members[0].sign(payloadHash).toBytes();
signatures[1] = members[1].sign(payloadHash).toBytes();
signatures[2] = members[1].sign(payloadHash).toBytes();
ListFVM sourceTransactionList = new ListFVM();
ListFVM addressList = new ListFVM();
ListFVM uintList = new ListFVM();
for (BridgeTransfer b : transfers) {
sourceTransactionList.add(new AddressFVM(b.getSourceTransactionHash()));
addressList.add(new AddressFVM(b.getRecipient()));
uintList.add(new Uint128FVM(PrecompiledUtilities.pad(b.getTransferValue().toByteArray(), 16)));
}
ListFVM sigChunk1 = new ListFVM();
ListFVM sigChunk2 = new ListFVM();
ListFVM sigChunk3 = new ListFVM();
for (byte[] sig : signatures) {
// add incorrect signatures, copies [0:32] for all chunks
sigChunk1.add(new AddressFVM(Arrays.copyOfRange(sig, 0, 32)));
sigChunk2.add(new AddressFVM(Arrays.copyOfRange(sig, 0, 32)));
sigChunk3.add(new AddressFVM(Arrays.copyOfRange(sig, 0, 32)));
}
callPayload = new AbiEncoder(BridgeFuncSig.SIG_SUBMIT_BUNDLE.getSignature(), new AddressFVM(blockHash), sourceTransactionList, addressList, uintList, sigChunk1, sigChunk2, sigChunk3).encodeBytes();
// input will include 5 transfers and 3 validators with incorrect signatures
transferResult = this.contract.execute(callPayload, DEFAULT_NRG);
// / VERIFICATION
assertThat(this.contract.execute(ByteUtil.merge(BridgeFuncSig.PURE_ACTION_MAP.getBytes(), payloadHash), 21000L).getReturnData()).isEqualTo(new byte[32]);
assertEquals("FAILURE", transferResult.getStatus().causeOfError);
// check that nothing has been changed from the failed transfer
for (BridgeTransfer b : transfers) {
assertThat(this.repository.getBalance(new AionAddress(b.getRecipient()))).isEqualTo(BigInteger.ZERO);
}
assertThat(this.repository.getBalance(CONTRACT_ADDR)).isEqualTo(BigInteger.valueOf(10));
assertThat(submitBundleContext.getInternalTransactions()).isEmpty();
assertThat(submitBundleContext.getLogs()).isEmpty();
}
Aggregations