PostContractCall
Introduction
The PostContractCall join point occurs during the DeliverTx
phase of
the Transaction lifecycle.
This join point will be triggered after the cross-contract call is executed. Below is evm call
graph:
ApplyTransaction
- ⮕
ApplyMessageWithConfig
- ⮕
evm.Call
- ⮕
loop opCodes
- | ⚙ PreContractCall join point
- |
evm.Interpreter.Run 0
- | ⚙ PostContractCall join point
- | ⚙ PreContractCall join point
- |
evm.Interpreter.Run 1
- | ⚙ PostContractCall join point
- ....
- ⮕
- ⮕
- ⮕
RefundGas
- ⮕
At this stage, the join point has the capability to examine the post-call state of the contract, enabling it to make informed decisions for subsequent execution.
Interface
interface IPostContractCallJP extends IAspectBase {
postContractCall(input: PostContractCallInput): void;
}
- Parameter
- input: PostContractCallInput; The base layer will deliver the PostContractCallInput object to Aspect in this join
point.
input.block.number
: current block number.input.call.from
: caller of the contract call.input.call.to
: to address of the contract call.input.call.data
: input bytes of the contract call.input.call.gas
: gas limit of the contract call.input.call.index
: index of the contract call.input.call.value
: transfer value of the contract call.input.call.ret
: return value of the contract call.input.call.error
: error message of the contract call.
- input: PostContractCallInput; The base layer will deliver the PostContractCallInput object to Aspect in this join
point.
- Returns
- void; If Aspect returns normally, the transaction will continue to execute. If Aspect calls
sys.revert
to revert the transaction, the base layer will revert the transaction.
- void; If Aspect returns normally, the transaction will continue to execute. If Aspect calls
Example
/**
* postContractCall is a join-point that gets invoked after the execution of a contract call.
*
* @param input Input of the given join-point
* @return void
*/
postContractCall(input: postContractCallInput): void {
let ethMessage = new StaticCallRequest();
// get static call params from the aspect property
const from = sys.hostApi.aspectProperty.get("from");
const to = sys.hostApi.aspectProperty.get("to");
const data = sys.hostApi.aspectProperty.get("data");
// build the message
ethMessage.from = from
ethMessage.to = to
ethMessage.gas = 400000;
ethMessage.data = data;
// send static call
let staticCallresult = sys.hostApi.evmCall.staticCall(ethMessage);
if (staticCallresult.vmError != "") {
sys.revert("static call failed");
}
}
Programming Guide
There are two programming modes that can be used in this method:
By utilizing the 'input' input argument, it provides essential insights into transactions and block processing. see how to use input.
Using the 'sys' namespace, it provides both hight level API and low-level API access to system data and contextual information generated during blockchain runtime, including details about the environment, blocks, transactions, and utility classes such as crypto and ABI encoding/decoding. see more details.
Important point: Since the join point is in the EVM execution process, using sys.revert(), sys.require() in this join point will actually revert the transaction.
Host APIs
For a comprehensive overview of all APIs and their usage see API References.
Each join-point has access to different host APIs, and the host APIs available within the current breakpoint can be found at the following table.
System APIs | Availability | Description |
---|---|---|
sys.revert | ✅ | Forces the current transaction to fail. |
sys.require | ✅ | Checks if certain conditions are met; if not, forces the entire transaction to fail. |
sys.log | ✅ | A wrapper for sys.hostApi.util.log , prints log messages to Artela output for debugging on the localnet. |
sys.aspect.id | ✅ | Retrieves the ID of the aspect. |
sys.aspect.version | ✅ | Retrieves the version of the aspect. |
sys.aspect.mutableState | ✅ | A wrapper for sys.hostApi.aspectState that facilitates easier reading or writing of values of a specified type to aspect state. |
sys.aspect.property | ✅ | A wrapper for sys.hostApi.aspectProperty that facilitates easier reading of values of a specified type from aspect property. |
sys.aspect.readonlyState | ✅ | A wrapper for sys.hostApi.aspectState that facilitates easier reading of values of a specified type from aspect state. |
sys.aspect.transientStorage | ✅ | A wrapper for sys.hostApi.aspectTransientStorage that facilitates easier reading or writing of values of a specified type to aspect transient storage. |
sys.hostApi.aspectProperty | ✅ | Retrieves the property of the aspect as written in aspect deployment. |
sys.hostApi.aspectState | ✅ | Retrieves or writes the state of the aspect. |
sys.hostApi.aspectTransientStorage | ✅ | Retrieves or writes to the transient storage of the aspect. This storage is only valid within the current transaction lifecycle. |
sys.hostApi.crypto.ecRecover | ✅ | Calls crypto methods ecRecover . |
sys.hostApi.crypto.keccak | ✅ | Calls crypto methods keccak . |
sys.hostApi.crypto.ripemd160 | ✅ | Calls crypto methods ripemd160 . |
sys.hostApi.crypto.sha256 | ✅ | Calls crypto methods sha256 . |
sys.hostApi.runtimeContext | ✅ | Retrieves runtime context by the key. Refer to the runtime context to see which keys can be accessed by the current join point. |
sys.hostApi.stateDb.balance | ✅ | Gets the balance of the specified address from the EVM state database. |
sys.hostApi.stateDb.codeHash | ✅ | Gets the hash of the code from the EVM state database. |
sys.hostApi.stateDb.codeSize | ✅ | Gets the size of the code from the EVM state database. |
sys.hostApi.stateDb.hasSuicided | ✅ | Gets the codehash from the EVM state database. |
sys.hostApi.stateDb.nonce | ✅ | Checks if the contract at the specified address is suicided in the current transactions. |
sys.hostApi.stateDb.stateAt | ✅ | Gets the state at a specific point. |
sys.hostApi.evmCall.jitCall | ✅ | Creates a contract call and executes it immediately. |
sys.hostApi.evmCall.staticCall | ✅ | Creates a static call and executes it immediately. |
sys.hostApi.trace.queryCallTree | ✅ | Returns the call tree of EVM execution. |
sys.hostApi.trace.queryStateChange | ✅ | Returns the state change in EVM execution for the specified key. |
Runtime context
The Aspect Runtime Context encapsulates data generated through the consensus process. With the acquired Runtime Context object, retrieve specific data by specifying the relevant Context Key. Each Context Key is associated with a particular type of data or information.
Usage
const enableCreate = sys.hostApi.runtimeContext.get('env.enableCreate');
//decode BoolData
const enableCreateData = Protobuf.decode<BoolData>(enableCreate, BoolData.decode);
sys.log('env.enableCreate' + ' ' + enableCreateData.data.toString());
const msgErr = sys.hostApi.runtimeContext.get("msg.result.error");
if (msgErr.length>0){
///decode StringData
const msgErrData = Protobuf.decode <StringData> (msgErr, StringData.decode);
sys.log("msg.result.error" + " " + msgErrData.data)
}
Key table
Context key | Value type | Description |
---|---|---|
isCall | BoolData | Get the current transaction is Call or Send. If it is Call, return true. |
tx.type | UintData | Returns the transaction type id. LegacyTxType=0x00 AccessListTxType=0x01 DynamicFeeTxType=0x02 BlobTxType=0x03 |
tx.chainId | BytesData | Returns the EIP155 chain ID of the transaction. The return value will always be non-nil. For legacy transactions which are not replay-protected, the return value is zero. |
tx.accessList | EthAccessList | AccessListTx is the data of EIP-2930 access list transactions. |
tx.nonce | UintData | Returns the sender account nonce of the transaction. |
tx.gasPrice | BytesData | Returns the gas price of the transaction. |
tx.gas | UintData | Returns the gas limit of the transaction. |
tx.gasTipCap | BytesData | Returns the gasTipCap per gas of the transaction. |
tx.gasFeeCap | BytesData | Returns the fee cap per gas of the transaction. |
tx.to | BytesData | Returns the recipient address of the transaction. For contract-creation transactions, To returns nil. |
tx.value | BytesData | Returns the ether amount of the transaction. |
tx.data | BytesData | Returns the input data of the transaction. |
tx.bytes | BytesData | Returns the transaction marshal binary. |
tx.hash | BytesData | Returns the transaction hash. |
tx.unsigned.bytes | BytesData | Returns the unsigned transaction marshal binary. |
tx.unsigned.hash | BytesData | Returns the unsigned transaction hash. |
tx.sig.v | BytesData | Returns the V signature values of the transaction. |
tx.sig.r | BytesData | Returns the R signature values of the transaction. |
tx.sig.s | BytesData | Returns the S signature values of the transaction. |
tx.from | BytesData | Returns the from address of the transaction. |
tx.index | UintData | Returns the transaction index of current block. |
aspect.id | BytesData | Returns current aspect id. |
aspect.version | UintData | Returns current aspect version. |
msg.from | BytesData | Returns the sender address of the EVM call message. |
msg.to | BytesData | Returns the recipient address of the EVM call message. |
msg.value | BytesData | Returns the ether amount of the EVM call message. |
msg.gas | UintData | Returns the gas limit of the EVM call message. |
msg.input | BytesData | Returns the input data of the EVM call message. |
msg.index | UintData | Returns the index of the EVM call message. |
msg.result.ret | BytesData | Returns the result of the EVM call. |
msg.result.gasUsed | UintData | Returns the gas used of the EVM call. |
msg.result.error | StringData | Returns the result error message of the EVM call. |
block.header.parentHash | BytesData | Get the current block header parent hash. |
block.header.miner | BytesData | Get the current block header miner. |
block.header.transactionsRoot | BytesData | Get the current block TransactionsRoot hash. |
block.header.number | UintData | Get the current block number. |
block.header.timestamp | UintData | Get the current block header timestamp. |
env.extraEIPs | IntArrayData | Retrieve the EVM module parameters for the 'extra_eips': defines the additional EIPs for the vm.Config. |
env.enableCreate | BoolData | Retrieve the EVM module parameters for the 'enable_create': toggles states transitions that use the vm.Create function. |
env.enableCall | BoolData | Retrieve the EVM module parameters for the 'enable_call': toggles states transitions that use the vm.Call function. |
env.allowUnprotectedTxs | BoolData | Retrieve the EVM module parameters for the 'allow_unprotected_txs': defines if replay-protected (i.e non EIP155 // signed) transactions can be executed on the states machine. |
env.chain.chainId | UintData | Retrieve the Ethereum chain config id. |
env.chain.homesteadBlock | UintData | Retrieve the Ethereum chain configuration for the 'homestead_block': switch (nil no fork, 0 = already homestead) |
env.chain.daoForkBlock | UintData | Retrieve the Ethereum chain configuration for the 'dao_fork_block': corresponds to TheDAO hard-fork switch block (nil no fork) |
env.chain.daoForkSupport | BoolData | Retrieve the Ethereum chain configuration for the 'dao_fork_support': defines whether the nodes supports or opposes the DAO hard-fork |
env.chain.eip150Block | UintData | Retrieve the Ethereum chain configuration for the 'eip150_block': EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) EIP150 HF block (nil no fork) |
env.chain.eip155Block | UintData | Retrieve the Ethereum chain configuration for the 'eip155_block'. |
env.chain.eip158Block | UintData | Retrieve the Ethereum chain configuration for the 'eip158_block'. |
env.chain.byzantiumBlock | UintData | Retrieve the Ethereum chain configuration for the 'byzantium_block': Byzantium switch block (nil no fork, 0 =already on byzantium) |
env.chain.constantinopleBlock | UintData | Retrieve the Ethereum chain configuration for the 'constantinople_block': Constantinople switch block (nil no fork, 0 = already activated) |
env.chain.petersburgBlock | UintData | Retrieve the Ethereum chain configuration for the 'petersburg_block': Petersburg switch block (nil no fork, 0 = already activated) |
env.chain.istanbulBlock | UintData | Retrieve the Ethereum chain configuration for the 'istanbul_block': Istanbul switch block (nil no fork, 0 = already on istanbul) |
env.chain.muirGlacierBlock | UintData | Retrieve the Ethereum chain configuration for the 'muir_glacier_block': Eip-2384 (bomb delay) switch block ( nil no fork, 0 = already activated). |
env.chain.berlinBlock | UintData | Retrieve the Ethereum chain configuration for the 'berlin_block': Berlin switch block (nil = no fork, 0 = already on berlin) |
env.chain.londonBlock | UintData | Retrieve the Ethereum chain configuration for the 'london_block': London switch block (nil = no fork, 0 = already on london) |
env.chain.arrowGlacierBlock | UintData | Retrieve the Ethereum chain configuration for the 'arrow_glacier_block': Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) |
env.chain.grayGlacierBlock | UintData | Retrieve the Ethereum chain configuration for the 'gray_glacier_block': EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) |
env.chain.mergeNetSplitBlock | UintData | Retrieve the Ethereum chain configuration for the 'merge_netsplit_block': Virtual fork after The Merge to use as a network splitter. |
env.chain.shanghaiTime | UintData | Retrieve the Ethereum chain configuration for the 'shanghaiTime': Shanghai switch time (nil = no fork, 0 = already on shanghai). |
env.chain.cancunTime | UintData | Retrieve the Ethereum chain configuration for the 'CancunTime': Cancun switch time (nil = no fork, 0 = already on cancun). |
env.chain.pragueTime | UintData | Retrieve the Ethereum chain configuration for the 'PragueTime': Prague switch time (nil = no fork, 0 = already on prague). |
env.consensusParams.block.maxGas | IntData | Retrieve the max gas per block. |
env.consensusParams.block.maxBytes | IntData | Retrieve the max block size, in bytes. |
env.consensusParams.evidence.maxAgeDuration | IntData | Retrieve the max age duration.It should correspond with an app's "unbonding period" or other similar mechanism for handling. |
env.consensusParams.evidence.maxAgeNumBlocks | IntData | The basic formula for calculating this is: MaxAgeDuration / {average block time}. |
env.consensusParams.evidence.maxBytes | IntData | Retrieve the maximum size of total evidence in bytes that can be committed in a single block. |
env.consensusParams.validator.pubKeyTypes | StringArrayData | Restrict the public key types validators can use. |
env.consensusParams.appVersion | UintData | Get the ABCI application version. |