use of org.aion.avm.stub.IAvmResourceFactory in project aion by aionnetwork.
the class BlockchainForkingTest method testVmTypeRetrieval_ForkWithConflictingContractVM.
/**
* Ensures that if a side-chain block is imported after a main-chain block creating the same
* contract address X but using different VMs, then each chain will operate on the correct VM.
*/
@Test
public void testVmTypeRetrieval_ForkWithConflictingContractVM() throws Exception {
TestResourceProvider resourceProvider = TestResourceProvider.initializeAndCreateNewProvider(AvmPathManager.getPathOfProjectRootDirectory());
IAvmResourceFactory resourceFactory = resourceProvider.factoryForVersion1;
// blocks to be built
MiningBlock block, fastBlock, slowBlock, lowBlock, highBlock;
// transactions used in blocks
AionTransaction deployOnAVM, deployOnFVM, callTxOnFVM;
// for processing block results
Pair<ImportResult, AionBlockSummary> connectResult;
ImportResult result;
AionTxReceipt receipt;
// build a blockchain
TransactionTypeRule.allowAVMContractTransaction();
List<ECKey> accounts = generateAccounts(10);
StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
StandaloneBlockchain sourceChain = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build().bc;
StandaloneBlockchain testChain = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build().bc;
ECKey sender = accounts.remove(0);
assertThat(testChain).isNotEqualTo(sourceChain);
assertThat(testChain.genesis).isEqualTo(sourceChain.genesis);
long time = System.currentTimeMillis();
// add a block to both chains
block = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Collections.emptyList(), true, time / 10_000L).block;
assertThat(sourceChain.tryToConnect(block)).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(testChain.tryToConnect(block)).isEqualTo(ImportResult.IMPORTED_BEST);
// ****** setup side chain ******
// deploy contracts on different VMs for the two chains
deployOnAVM = deployStatefulnessAVMContract(resourceFactory, sender);
fastBlock = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(deployOnAVM), true, time / 10_000L).block;
deployOnFVM = deployContract(sender);
slowBlock = new MiningBlock(sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(deployOnFVM), true, time / 10_000L).block);
MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(slowBlock.getHeader()).withTimestamp(time / 10_000L + 100).build();
slowBlock.updateHeader(newBlockHeader);
time += 100;
// sourceChain imports only fast block
connectResult = sourceChain.tryToConnectAndFetchSummary(fastBlock);
result = connectResult.getLeft();
receipt = connectResult.getRight().getReceipts().get(0);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(receipt.isSuccessful()).isTrue();
AionAddress contract = TxUtil.calculateContractAddress(receipt.getTransaction());
// testChain imports both blocks
connectResult = testChain.tryToConnectAndFetchSummary(fastBlock);
result = connectResult.getLeft();
receipt = connectResult.getRight().getReceipts().get(0);
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(receipt.isSuccessful()).isTrue();
assertThat(TxUtil.calculateContractAddress(receipt.getTransaction())).isEqualTo(contract);
connectResult = testChain.tryToConnectAndFetchSummary(slowBlock);
result = connectResult.getLeft();
receipt = connectResult.getRight().getReceipts().get(0);
assertThat(result).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
assertThat(receipt.isSuccessful()).isTrue();
assertThat(TxUtil.calculateContractAddress(receipt.getTransaction())).isEqualTo(contract);
// ****** check that the correct contract details are kept ******
// check that both chains have the correct vm type for the AVM contract
byte[] codeHashAVM = sourceChain.getRepository().getAccountState(contract).getCodeHash();
assertThat(testChain.getRepository().getVMUsed(contract, codeHashAVM)).isEqualTo(sourceChain.getRepository().getVMUsed(contract, codeHashAVM));
// check that only the second chain has the vm type for the FVM contract
byte[] codeHashFVM = ((AionRepositoryImpl) testChain.getRepository().getSnapshotTo(slowBlock.getStateRoot())).getAccountState(contract).getCodeHash();
assertThat(sourceChain.getRepository().getVMUsed(contract, codeHashFVM)).isEqualTo(InternalVmType.UNKNOWN);
assertThat(testChain.getRepository().getVMUsed(contract, codeHashFVM)).isEqualTo(InternalVmType.FVM);
// check the stored information details
ContractInformation infoSingleImport = sourceChain.getRepository().getIndexedContractInformation(contract);
System.out.println("without side chain:" + infoSingleImport);
assertThat(infoSingleImport.getVmUsed(codeHashAVM)).isEqualTo(InternalVmType.AVM);
assertThat(infoSingleImport.getInceptionBlocks(codeHashAVM)).isEqualTo(Set.of(fastBlock.getHashWrapper()));
assertThat(infoSingleImport.getVmUsed(codeHashFVM)).isEqualTo(InternalVmType.UNKNOWN);
assertThat(infoSingleImport.getInceptionBlocks(codeHashFVM)).isEmpty();
ContractInformation infoMultiImport = testChain.getRepository().getIndexedContractInformation(contract);
System.out.println("with side chain:" + infoMultiImport);
assertThat(infoMultiImport.getVmUsed(codeHashAVM)).isEqualTo(InternalVmType.AVM);
assertThat(infoMultiImport.getInceptionBlocks(codeHashAVM)).isEqualTo(Set.of(fastBlock.getHashWrapper()));
assertThat(infoMultiImport.getVmUsed(codeHashFVM)).isEqualTo(InternalVmType.FVM);
assertThat(infoMultiImport.getInceptionBlocks(codeHashFVM)).isEqualTo(Set.of(slowBlock.getHashWrapper()));
// build two blocks where the second block has a higher total difficulty
callTxOnFVM = callSetValue(sender, contract, 9, BigInteger.ONE);
lowBlock = testChain.createNewMiningBlockInternal(slowBlock, Arrays.asList(callTxOnFVM), true, time / 10_000L + 101).block;
int expectedCount = 3;
List<AionTransaction> callTxOnAVM = callStatefulnessAVM(resourceFactory, sender, expectedCount, BigInteger.ONE, contract);
highBlock = sourceChain.createNewMiningBlockInternal(fastBlock, callTxOnAVM, true, time / 10_000L).block;
assertThat(highBlock.getDifficultyBI()).isGreaterThan(lowBlock.getDifficultyBI());
// build first chain with highBlock applied directly
connectResult = sourceChain.tryToConnectAndFetchSummary(highBlock);
// get last tx
receipt = connectResult.getRight().getReceipts().get(expectedCount);
assertThat(receipt.isSuccessful()).isTrue();
result = connectResult.getLeft();
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
// collect the consensus information from the block & receipt
AionBlockSummary blockSummary = connectResult.getRight();
byte[] stateRoot = blockSummary.getBlock().getStateRoot();
byte[] blockReceiptsRoot = blockSummary.getBlock().getReceiptsRoot();
byte[] receiptTrieEncoded = receipt.getReceiptTrieEncoded();
int returnedCount = resourceFactory.newDecoder(blockSummary.getReceipts().get(expectedCount).getTransactionOutput()).decodeOneInteger();
assertThat(returnedCount).isEqualTo(expectedCount);
// ****** test fork behavior ******
// first import lowBlock
assertThat(testChain.tryToConnect(lowBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
// next import highBlock causing the fork
connectResult = testChain.tryToConnectAndFetchSummary(highBlock);
receipt = connectResult.getRight().getReceipts().get(expectedCount);
assertThat(receipt.isSuccessful()).isTrue();
System.out.println(receipt);
result = connectResult.getLeft();
assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
// collect the consensus information from the block & receipt
blockSummary = connectResult.getRight();
assertThat(testChain.getBestBlock()).isEqualTo(sourceChain.getBestBlock());
assertThat(blockSummary.getBlock().getStateRoot()).isEqualTo(stateRoot);
assertThat(blockSummary.getBlock().getReceiptsRoot()).isEqualTo(blockReceiptsRoot);
assertThat(receipt.getReceiptTrieEncoded()).isEqualTo(receiptTrieEncoded);
returnedCount = resourceFactory.newDecoder(blockSummary.getReceipts().get(expectedCount).getTransactionOutput()).decodeOneInteger();
assertThat(returnedCount).isEqualTo(expectedCount);
}
use of org.aion.avm.stub.IAvmResourceFactory in project aion by aionnetwork.
the class StakingContractHelper method getEffectiveStake.
/**
* this method called by the kernel for querying the correct stakes in the staking contract by giving desired coinbase address and the block signing address.
* @param signingAddress the block signing address
* @param coinbase the staker's coinbase for receiving the block rewards
* @return the stake amount of the staker
*/
public BigInteger getEffectiveStake(AionAddress signingAddress, AionAddress coinbase, Block block) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
if (signingAddress == null || coinbase == null) {
throw new NullPointerException();
}
if (!AvmProvider.tryAcquireLock(10, TimeUnit.MINUTES)) {
throw new IllegalStateException("Failed to acquire the avm lock!");
}
if (!AvmProvider.isVersionEnabled(LATEST_AVM_VERSION)) {
AvmProvider.enableAvmVersion(LATEST_AVM_VERSION, AvmConfigurations.getProjectRootDirectory());
}
IAvmResourceFactory resourceFactory = AvmProvider.getResourceFactory(LATEST_AVM_VERSION);
if (this.effectiveStake == null) {
this.effectiveStake = resourceFactory.newStreamingEncoder().encodeOneString("getEffectiveStake").getEncoding();
}
byte[] abi = ByteUtil.merge(this.effectiveStake, resourceFactory.newStreamingEncoder().encodeOneAddress(signingAddress).getEncoding(), resourceFactory.newStreamingEncoder().encodeOneAddress(coinbase).getEncoding());
AvmProvider.releaseLock();
AionTransaction callTx = AionTransaction.create(keyForCallandEstimate, BigInteger.ZERO.toByteArray(), stakingContractAddr, BigInteger.ZERO.toByteArray(), abi, 2_000_000L, 10_000_000_000L, TransactionTypes.DEFAULT, null);
AionTxReceipt receipt = null;
try {
receipt = callConstant(callTx, block);
} catch (VmFatalException e) {
LOG_VM.error("VM fatal exception! Shutting down the kernel!", e);
System.exit(SystemExitCodes.FATAL_VM_ERROR);
}
if (receipt == null || Arrays.equals(receipt.getTransactionOutput(), new byte[0])) {
LOG_CONS.debug("getEffectiveStake failed due to the " + (receipt == null ? "null receipt" : "empty transactionOutput"));
return BigInteger.ZERO;
}
if (!AvmProvider.tryAcquireLock(10, TimeUnit.MINUTES)) {
throw new IllegalStateException("Failed to acquire the avm lock!");
}
BigInteger output = resourceFactory.newDecoder(receipt.getTransactionOutput()).decodeOneBigInteger();
AvmProvider.releaseLock();
return output;
}
use of org.aion.avm.stub.IAvmResourceFactory in project aion by aionnetwork.
the class PendingStateTest method testAddPendingTransaction_AVMContractDeploy_Success.
@Test
public void testAddPendingTransaction_AVMContractDeploy_Success() throws Exception {
TestResourceProvider resourceProvider = TestResourceProvider.initializeAndCreateNewProvider(AvmPathManager.getPathOfProjectRootDirectory());
IAvmResourceFactory resourceFactory = resourceProvider.factoryForVersion1;
// Successful transaction
byte[] jar = resourceFactory.newContractFactory().getDeploymentBytes(AvmContract.HELLO_WORLD);
AionTransaction transaction = AionTransaction.create(deployerKey, BigInteger.ZERO.toByteArray(), null, BigInteger.ZERO.toByteArray(), jar, 5_000_000, energyPrice, TransactionTypes.AVM_CREATE_CODE, null);
assertEquals(pendingState.addTransactionFromApiServer(transaction), TxResponse.SUCCESS);
}
use of org.aion.avm.stub.IAvmResourceFactory in project aion by aionnetwork.
the class InvalidBlockTest method makeTransactions.
private List<AionTransaction> makeTransactions(AvmVersion version, int num, BigInteger initialNonce) {
List<AionTransaction> transactions = new ArrayList<>();
IAvmResourceFactory factory = (version == AvmVersion.VERSION_1) ? resourceProvider.factoryForVersion1 : resourceProvider.factoryForVersion2;
byte[] jar = factory.newContractFactory().getDeploymentBytes(AvmContract.GENERIC_CONTRACT);
BigInteger nonce = initialNonce;
for (int i = 0; i < num; i++) {
AionTransaction transaction = AionTransaction.create(deployerKey, nonce.toByteArray(), null, BigInteger.ZERO.toByteArray(), jar, 5_000_000L, 10_000_000_000L, TransactionTypes.AVM_CREATE_CODE, null);
transactions.add(transaction);
nonce = nonce.add(BigInteger.ONE);
}
return transactions;
}
use of org.aion.avm.stub.IAvmResourceFactory in project aion by aionnetwork.
the class MultiVersionAvmTest method makeHelloWorldCallTransaction.
private AionTransaction makeHelloWorldCallTransaction(AvmVersion version, BigInteger nonce, AionAddress contract) {
IAvmResourceFactory factory = (version == AvmVersion.VERSION_1) ? resourceProvider.factoryForVersion1 : resourceProvider.factoryForVersion2;
byte[] callData = factory.newStreamingEncoder().encodeOneString("sayHello").getEncoding();
return AionTransaction.create(this.deployerKey, nonce.toByteArray(), contract, BigInteger.ZERO.toByteArray(), callData, 2_000_000, energyPrice, TransactionTypes.DEFAULT, null);
}
Aggregations