Skip to content

Commit

Permalink
Move precompiled call into IExternalStateForFvm interface
Browse files Browse the repository at this point in the history
- The fvm now calls precompiled contracts via IExternalStateForFvm
  rather than directly, so the kernel must provide this ability.
  • Loading branch information
aionick committed Jul 26, 2019
1 parent 4a83be0 commit 01c0b32
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,42 @@

public final class ContractExecutor {

/**
* Returns the result of executing the internal transaction whose context is the specified
* context.
*
* This method only executes the input and does nothing else. This should only ever be called
* by internal transactions!
*
* @param worldState The current state of the world.
* @param context The transaction context.
* @param input The call input.
* @param energyRemaining The current energy remaining.
* @return the execution result.
*/
public static PrecompiledTransactionResult executeInternalCall(IExternalStateForPrecompiled worldState, PrecompiledTransactionContext context, byte[] input, long energyRemaining) {
ContractFactory factory = new ContractFactory();
PrecompiledContract precompiledContract = factory.getPrecompiledContract(context, worldState);

if (precompiledContract == null) {
return new PrecompiledTransactionResult(PrecompiledResultCode.SUCCESS, energyRemaining);
} else {
return precompiledContract.execute(input, energyRemaining);
}
}

/**
* Returns the result of executing the specified transaction, which is a transaction that calls
* into a precompiled contract.
*
* This method performs verifications, balance transfers, etc. and runs as an external
* transaction!
*
* @param externalState The current state of the world.
* @param transaction The transaction.
* @return the execution result.
*/
public static PrecompiledTransactionResult execute(
public static PrecompiledTransactionResult executeExternalCall(
IExternalStateForPrecompiled externalState, AionTransaction transaction) {
if (externalState == null) {
throw new NullPointerException("Cannot run using a null externalState!");
Expand Down
78 changes: 78 additions & 0 deletions modVM/src/org/aion/vm/ExternalStateForFvm.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.aion.vm;

import java.math.BigInteger;
import org.aion.fastvm.ExecutionContext;
import org.aion.fastvm.FastVmResultCode;
import org.aion.fastvm.FastVmTransactionResult;
import org.aion.fastvm.IExternalStateForFvm;
import org.aion.mcf.core.AccountState;
import org.aion.mcf.db.IBlockStoreBase;
Expand All @@ -10,6 +13,12 @@
import org.aion.mcf.vm.DataWord;
import org.aion.mcf.vm.types.DataWordImpl;
import org.aion.mcf.vm.types.DoubleDataWord;
import org.aion.precompiled.ContractInfo;
import org.aion.precompiled.PrecompiledResultCode;
import org.aion.precompiled.PrecompiledTransactionResult;
import org.aion.precompiled.type.ContractExecutor;
import org.aion.precompiled.type.IExternalStateForPrecompiled;
import org.aion.precompiled.type.PrecompiledTransactionContext;
import org.aion.types.AionAddress;
import org.aion.util.types.ByteArrayWrapper;

Expand Down Expand Up @@ -81,6 +90,35 @@ public IExternalStateForFvm newChildExternalState() {
return new ExternalStateForFvm(this.repository.startTracking(), this.miner, this.blockDifficulty, this.isLocalCall, this.allowNonceIncrement, this.isFork040enabled, this.blockNumber, this.blockTimestamp, this.blockEnergyLimit);
}

/**
* Returns {@code true} only if the specified address is the address of a precompiled contract.
*
* @param address The address to check.
* @return whether the address is a precompiled contract.
*/
@Override
public boolean isPrecompiledContract(AionAddress address) {
return ContractInfo.isPrecompiledContract(address);
}

/**
* Executes an internal precompiled contract call and returns the result.
*
* @param context The context of the internal transaction.
* @return the execution result.
*/
@Override
public FastVmTransactionResult runInternalPrecompiledContractCall(ExecutionContext context) {

PrecompiledTransactionContext precompiledContext = toPrecompiledTransactionContext(context);

IExternalStateForPrecompiled precompiledWorldState = new ExternalStateForPrecompiled(this.repository, this.blockNumber, this.isLocalCall, this.allowNonceIncrement);

PrecompiledTransactionResult result = ContractExecutor.executeInternalCall(precompiledWorldState, precompiledContext, context.getTransactionData(), context.getTransactionEnergy());

return precompiledToFvmResult(result);
}

/**
* Adds the provided key-value pairing to the world state, associating it only with the given
* address.
Expand Down Expand Up @@ -500,4 +538,44 @@ private InternalVmType getVmType(AionAddress destination) {
}
return vm;
}

private static FastVmTransactionResult precompiledToFvmResult(PrecompiledTransactionResult precompiledResult) {
FastVmTransactionResult fvmResult = new FastVmTransactionResult();

fvmResult.addLogs(precompiledResult.getLogs());
fvmResult.addInternalTransactions(precompiledResult.getInternalTransactions());
fvmResult.addDeletedAddresses(precompiledResult.getDeletedAddresses());

fvmResult.setEnergyRemaining(precompiledResult.getEnergyRemaining());
fvmResult.setResultCode(precompiledToFvmResultCode(precompiledResult.getResultCode()));
fvmResult.setReturnData(precompiledResult.getReturnData());

return fvmResult;
}

private static FastVmResultCode precompiledToFvmResultCode(PrecompiledResultCode precompiledResultCode) {
switch (precompiledResultCode) {
case BAD_JUMP_DESTINATION: return FastVmResultCode.BAD_JUMP_DESTINATION;
case VM_INTERNAL_ERROR: return FastVmResultCode.VM_INTERNAL_ERROR;
case STATIC_MODE_ERROR: return FastVmResultCode.STATIC_MODE_ERROR;
case INVALID_NRG_LIMIT: return FastVmResultCode.INVALID_NRG_LIMIT;
case STACK_UNDERFLOW: return FastVmResultCode.STACK_UNDERFLOW;
case BAD_INSTRUCTION: return FastVmResultCode.BAD_INSTRUCTION;
case STACK_OVERFLOW: return FastVmResultCode.STACK_OVERFLOW;
case INVALID_NONCE: return FastVmResultCode.INVALID_NONCE;
case VM_REJECTED: return FastVmResultCode.VM_REJECTED;
case OUT_OF_NRG: return FastVmResultCode.OUT_OF_NRG;
case SUCCESS: return FastVmResultCode.SUCCESS;
case FAILURE: return FastVmResultCode.FAILURE;
case REVERT: return FastVmResultCode.REVERT;
case ABORT: return FastVmResultCode.ABORT;
case INSUFFICIENT_BALANCE: return FastVmResultCode.INSUFFICIENT_BALANCE;
case INCOMPATIBLE_CONTRACT_CALL: return FastVmResultCode.INCOMPATIBLE_CONTRACT_CALL;
default: throw new IllegalStateException("Unknown code: " + precompiledResultCode);
}
}

private static PrecompiledTransactionContext toPrecompiledTransactionContext(ExecutionContext context) {
return new PrecompiledTransactionContext(context.getDestinationAddress(), context.getOriginAddress(), context.getSenderAddress(), context.getSideEffects().getExecutionLogs(), context.getSideEffects().getInternalTransactions(), context.getSideEffects().getAddressesToBeDeleted(), context.getHashOfOriginTransaction(), context.getTransactionHash(), context.getBlockNumber(), context.getTransactionEnergy(), context.getTransactionStackDepth());
}
}
2 changes: 1 addition & 1 deletion modVM/src/org/aion/vm/PrecompiledTransactionExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static List<AionTxExecSummary> executeTransactions(
for (AionTransaction transaction : transactions) {

// Execute the contract.
PrecompiledTransactionResult result = ContractExecutor.execute(externalState, transaction);
PrecompiledTransactionResult result = ContractExecutor.executeExternalCall(externalState, transaction);

// Check the block energy limit & reject if necessary.
long energyUsed = computeEnergyUsed(transaction.getEnergyLimit(), result);
Expand Down

0 comments on commit 01c0b32

Please sign in to comment.