use of org.aion.base.AionTxExecSummary in project aion by aionnetwork.
the class ContractIntegTest method testFvmConstructorIsCalledOnCodeDeployment.
@Test
public void testFvmConstructorIsCalledOnCodeDeployment() throws Exception {
String contractName = "MultiFeatureContract";
byte[] deployCode = ContractUtils.getContractDeployer("MultiFeatureContract.sol", "MultiFeatureContract");
long nrg = 1_000_000;
long nrgPrice = energyPrice;
BigInteger value = BigInteger.ONE;
BigInteger nonce = BigInteger.ZERO;
AionTransaction tx = AionTransaction.create(deployerKey, nonce.toByteArray(), null, value.toByteArray(), deployCode, nrg, nrgPrice, txType, null);
RepositoryCache repo = blockchain.getRepository().startTracking();
nonce = nonce.add(BigInteger.ONE);
AionAddress contract = deployContract(repo, tx, contractName, null, value, nrg, nrgPrice, nonce);
if (txType == TransactionTypes.DEFAULT) {
// Now call the contract and check that the constructor message was set.
String getMsgFunctionHash = "ce6d41de";
tx = AionTransaction.create(deployerKey, nonce.toByteArray(), contract, BigInteger.ZERO.toByteArray(), Hex.decode(getMsgFunctionHash), nrg, nrgPrice, txType, null);
assertFalse(tx.isContractCreationTransaction());
MiningBlock block = makeBlock(tx);
AionTxExecSummary summary = executeTransaction(tx, block, repo);
assertEquals("", summary.getReceipt().getError());
assertNotEquals(nrg, summary.getNrgUsed().longValue());
String expectedMsg = "Im alive!";
assertEquals(expectedMsg, new String(extractOutput(summary.getResult())));
} else if (txType == TransactionTypes.AVM_CREATE_CODE) {
assertNull(contract);
}
}
use of org.aion.base.AionTxExecSummary in project aion by aionnetwork.
the class ContractIntegTest method tellFvmContractCallAvmContract.
@Test
public void tellFvmContractCallAvmContract() throws Exception {
if (txType == TransactionTypes.AVM_CREATE_CODE) {
return;
}
String contractName = "InternalCallContract";
byte[] deployCode = getDeployCode(contractName);
long nrg = Constants.NRG_TRANSACTION_MAX;
long nrgPrice = energyPrice;
BigInteger value = BigInteger.ZERO;
BigInteger nonce = BigInteger.ZERO;
AionTransaction tx = AionTransaction.create(deployerKey, nonce.toByteArray(), null, value.toByteArray(), deployCode, nrg, nrgPrice, txType, null);
RepositoryCache repo = blockchain.getRepository().startTracking();
nonce = nonce.add(BigInteger.ONE);
AionAddress contract = deployContract(repo, tx, contractName, null, value, nrg, nrgPrice, nonce, true);
assertNotNull(contract);
repo = blockchain.getRepository().startTracking();
AionAddress avmAddress = deployAvmContract(AvmVersion.VERSION_1, nonce);
assertNotNull(avmAddress);
nonce = nonce.add(BigInteger.ONE);
byte[] input = Arrays.copyOfRange(HashUtil.keccak256("callAVM(address)".getBytes()), 0, 4);
input = ByteUtil.merge(input, avmAddress.toByteArray());
tx = AionTransaction.create(deployerKey, nonce.toByteArray(), contract, BigInteger.ZERO.toByteArray(), input, nrg, nrgPrice, txType, null);
assertFalse(tx.isContractCreationTransaction());
MiningBlock block = makeBlock(tx);
AionTxExecSummary summary = executeTransaction(tx, block, repo);
// The evmjit only return the the transaction success or failed when performing the function
// call.
assertEquals("reverted", summary.getReceipt().getError());
assertNotEquals(nrg, summary.getNrgUsed().longValue());
Pair<ImportResult, AionBlockSummary> result = blockchain.tryToConnectAndFetchSummary(block);
assertTrue(result.getLeft().isSuccessful());
assertTrue(result.getRight().getSummaries().get(0).isFailed());
}
use of org.aion.base.AionTxExecSummary in project aion by aionnetwork.
the class ContractIntegTest method testDeployWithOutCode.
@Test
public void testDeployWithOutCode() throws Exception {
long nrg = 1_000_000;
long nrgPrice = energyPrice;
// attempt to transfer value to new contract.
BigInteger value = BigInteger.ZERO;
BigInteger nonce = BigInteger.ZERO;
// to == null signals that this is contract creation.
AionTransaction tx = AionTransaction.create(deployerKey, nonce.toByteArray(), null, value.toByteArray(), new byte[0], nrg, nrgPrice, txType, null);
assertTrue(tx.isContractCreationTransaction());
assertEquals(Builder.DEFAULT_BALANCE, blockchain.getRepository().getBalance(deployer));
assertEquals(BigInteger.ZERO, blockchain.getRepository().getNonce(deployer));
if (txType == TransactionTypes.DEFAULT) {
MiningBlock block = makeBlock(tx);
RepositoryCache repo = blockchain.getRepository().startTracking();
AionTxExecSummary summary = executeTransaction(tx, block, repo);
assertEquals("", summary.getReceipt().getError());
// all energy is not used up.
assertNotEquals(nrg, summary.getNrgUsed().longValue());
AionAddress contract = TxUtil.calculateContractAddress(tx);
checkStateOfDeployer(repo, summary, nrgPrice, BigInteger.ZERO, nonce.add(BigInteger.ONE));
byte[] code = repo.getCode(contract);
assertNotNull(code);
} else {
blockchain.forkUtility.enable040Fork(0);
MiningBlock block = makeBlock(tx);
RepositoryCache repo = blockchain.getRepository().startTracking();
AionTxExecSummary summary = executeTransaction(tx, block, repo);
assertEquals("Failed: invalid data", summary.getReceipt().getError());
}
}
use of org.aion.base.AionTxExecSummary in project aion by aionnetwork.
the class ContractIntegTest method testRecursiveStackoverflow.
@Test
public void testRecursiveStackoverflow() throws Exception {
String contractName = "Recursive";
byte[] deployCode = getDeployCode(contractName);
long nrg = Constants.NRG_TRANSACTION_MAX;
long nrgPrice = energyPrice;
BigInteger value = BigInteger.ZERO;
BigInteger nonce = BigInteger.ZERO;
AionTransaction tx = AionTransaction.create(deployerKey, nonce.toByteArray(), null, value.toByteArray(), deployCode, nrg, nrgPrice, txType, null);
RepositoryCache repo = blockchain.getRepository().startTracking();
nonce = nonce.add(BigInteger.ONE);
AionAddress contract = deployContract(repo, tx, contractName, null, value, nrg, nrgPrice, nonce);
if (txType == TransactionTypes.AVM_CREATE_CODE) {
assertNull(contract);
return;
}
deployerBalance = repo.getBalance(deployer);
deployerNonce = repo.getNonce(deployer);
// First recurse 1 time less than the max and verify this is ok.
// Note that 128 == FvmConstants.MAX_CALL_DEPTH
int numRecurses = 127;
byte[] input = ByteUtil.merge(Hex.decode("2d7df21a"), contract.toByteArray());
input = ByteUtil.merge(input, new DataWord(numRecurses + 1).getData());
tx = AionTransaction.create(deployerKey, nonce.toByteArray(), contract, BigInteger.ZERO.toByteArray(), input, nrg, nrgPrice, txType, null);
assertFalse(tx.isContractCreationTransaction());
MiningBlock block = makeBlock(tx);
AionTxExecSummary summary = executeTransaction(tx, block, repo);
assertEquals("", summary.getReceipt().getError());
assertNotEquals(nrg, summary.getNrgUsed().longValue());
BigInteger txCost = BigInteger.valueOf(summary.getNrgUsed().longValue()).multiply(BigInteger.valueOf(nrgPrice));
assertEquals(deployerBalance.subtract(txCost), repo.getBalance(deployer));
deployerBalance = repo.getBalance(deployer);
deployerNonce = repo.getNonce(deployer);
repo.flushTo(blockchain.getRepository(), true);
repo = blockchain.getRepository().startTracking();
// Now recurse the max amount of times and ensure we fail.
// Note that 128 == FvmConstants.MAX_CALL_DEPTH
numRecurses = 128;
input = ByteUtil.merge(Hex.decode("2d7df21a"), contract.toByteArray());
input = ByteUtil.merge(input, new DataWord(numRecurses + 1).getData());
nonce = nonce.add(BigInteger.ONE);
tx = AionTransaction.create(deployerKey, nonce.toByteArray(), contract, BigInteger.ZERO.toByteArray(), input, nrg, nrgPrice, txType, null);
assertFalse(tx.isContractCreationTransaction());
block = makeBlock(tx);
summary = executeTransaction(tx, block, repo);
assertEquals("reverted", summary.getReceipt().getError());
assertNotEquals(nrg, summary.getNrgUsed().longValue());
txCost = BigInteger.valueOf(summary.getNrgUsed().longValue()).multiply(BigInteger.valueOf(nrgPrice));
assertEquals(deployerBalance.subtract(txCost), repo.getBalance(deployer));
}
use of org.aion.base.AionTxExecSummary in project aion by aionnetwork.
the class AvmTransactionExecutor method executeTransactions.
/**
* Executes the specified transactions using the avm, and returns the execution summaries of
* each of the transactions.
*
* This method does not perform any checks on its inputs! It operates under the assumption that
* the caller has ensured the input parameters are correct!
*
* In particular, every object supplied must be non-null with the exception of
* {@code postExecutionWork}, which may be null. Also, we must have
* {@code initialBlockEnergyLimit <= blockEnergyLimit}.
*
* @param repository The current state of the world.
* @param blockDifficulty The block difficulty.
* @param blockNumber The current block number.
* @param blockTimestamp The block timestamp.
* @param blockEnergyLimit The energy limit of the block.
* @param miner The miner address.
* @param transactions The transactions to execute.
* @param postExecutionWork The post-execution work to be applied after executing the transactions.
* @param decrementBlockEnergyLimit Whether or not to check the block energy limit.
* @param allowNonceIncrement Whether to increment the sender's nonce or not.
* @param isLocalCall Whether this is a local call (ie. is to cause no state changes).
* @param remainingBlockEnergy The amount of energy remaining in the block.
* @param executionType The avm execution type.
* @param cachedBlockNumber The cached block number.
* @param unityForkEnabled the flag shows the unityfork feature enabled/disabled
* @param signatureSchemeSwapEnabled the flag shows the signatureSchemeSwap feature enabled/disabled
* @return the execution summaries of the transactions.
* @throws VmFatalException If a fatal error occurred and the kernel must be shut down.
*/
public static List<AionTxExecSummary> executeTransactions(RepositoryCache repository, BigInteger blockDifficulty, long blockNumber, long blockTimestamp, long blockEnergyLimit, AionAddress miner, AionTransaction[] transactions, PostExecutionWork postExecutionWork, boolean decrementBlockEnergyLimit, boolean allowNonceIncrement, boolean isLocalCall, long remainingBlockEnergy, AvmExecutionType executionType, long cachedBlockNumber, boolean unityForkEnabled, boolean signatureSchemeSwapEnabled) throws VmFatalException {
List<AionTxExecSummary> transactionSummaries = new ArrayList<>();
long blockEnergy = remainingBlockEnergy;
try {
// We need to acquire the provider's lock before we can do anything meaningful.
if (!AvmProvider.tryAcquireLock(10, TimeUnit.MINUTES)) {
throw new TimeoutException("Timed out waiting to acquire the avm provider lock!");
}
// Ensure that the vm is in the correct state and grab the version of the avm we need to use for this block.
AvmVersion versionToUse = updateAvmsAndGetVersionToUse(AvmConfigurations.getProjectRootDirectory(), blockNumber, signatureSchemeSwapEnabled);
IAvmFutureResult[] futures = invokeAvm(versionToUse, repository, blockDifficulty, blockNumber, blockTimestamp, blockEnergyLimit, miner, transactions, allowNonceIncrement, isLocalCall, executionType, cachedBlockNumber, unityForkEnabled);
// Process the transaction results.
int index = 0;
for (IAvmFutureResult future : futures) {
TransactionResult result = future.getResult();
if (result.transactionStatus.isFatal()) {
throw new VmFatalException(result.transactionStatus.causeOfError);
}
// Check the block energy limit and reject if necessary.
AionTransaction transaction = transactions[index];
if (result.energyUsed > blockEnergy) {
result = markAsBlockEnergyLimitExceeded(result, transaction.getEnergyLimit());
}
AionTxExecSummary summary = buildSummaryAndUpdateState(future, transaction, result, versionToUse, repository, blockDifficulty, blockNumber, blockTimestamp, blockEnergyLimit, miner, allowNonceIncrement, isLocalCall);
// Do any post execution work if any is specified.
if (postExecutionWork != null) {
postExecutionWork.doWork(repository, summary, transaction);
}
// Update the remaining block energy.
if (!result.transactionStatus.isRejected() && decrementBlockEnergyLimit) {
blockEnergy -= summary.getReceipt().getEnergyUsed();
}
transactionSummaries.add(summary);
index++;
}
} catch (Throwable e) {
// If we get here then something unexpected went wrong, we treat this as a fatal situation since shutting down is our only recovery.
System.err.println("Encountered an unexpected error while processing the transactions in the avm: " + e.toString());
throw new VmFatalException(e);
} finally {
AvmProvider.releaseLock();
}
return transactionSummaries;
}
Aggregations