Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add batch run to EVM FLIP #257

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions protocol/20231116-evm-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@ fun main(bytes: [UInt8; 20]) {
}
```

`run` is the next crucial function in this contract which runs RLP-encoded EVM transactions. If the interaction with “Flow EVM” is successful and it changes the state, a new Flow-EVM block is formed and its data is emitted as a Cadence event. Using `run` limits EVM block to a single EVM transaction, a future `batchRun` provides option for batching EVM transaction execution.
`run` is the next crucial function in this contract which runs RLP-encoded EVM transactions. If the interaction with “Flow EVM” is successful and it changes the state, a new Flow-EVM block is formed and its data is emitted as a Cadence event. Using `run` limits EVM block to a single EVM transaction, a `batchRun` provides option for batching EVM transaction execution in a single block. Using batch run you can provide an array of RLP-encoded EVM transactions as input and they will be all executed in a new block, the function will return an array of results `[EVM.Result]` which will be the same length as the array of input transactions and will match the order.

```cadence
// Example of tx wrapping
import EVM from <ServiceAddress>

transaction(rlpEncodedTransaction: [UInt8], coinbaseBytes: [UInt8; 20]) {

prepare(signer: AuthAccount) {
execute {
let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
let result = EVM.run(tx: rlpEncodedTransaction, coinbase: coinbase)
assert(
Expand All @@ -89,6 +87,24 @@ transaction(rlpEncodedTransaction: [UInt8], coinbaseBytes: [UInt8; 20]) {
}
```

Example of batch run:
```
import EVM from <ServiceAddress>

transaction(rlpEncodedTransactions: [[UInt8]], coinbaseBytes: [UInt8; 20]) {
execute {
let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
let results = EVM.batchRun(txs: txs, coinbase: coinbase)

assert(results.length == txs.length, message: "invalid result length")
for res in results {
assert(res.status == EVM.Status.successful, message: "unexpected status")
}
}
}

```

Note that calling EVM.run doesn't revert the outter flow transaction and it requires the developer to take proper action based on the result.Status. Execution of a rlp encoded transaction result in one of these cases:
- `Status.invalid`: The execution of an evm transaction/call has failed at the validation step (e.g. nonce mismatch). An invalid transaction/call is rejected to be executed or be included in a block (no state change).
- `Status.failed`: The execution of an evm transaction/call has been successful but the vm has reported an error as the outcome of execution (e.g. running out of gas). A failed tx/call is included in a block.
Expand Down Expand Up @@ -541,6 +557,17 @@ contract EVM {
return runResult
}

/// Runs a batch of RLP-encoded EVM transactions, deducts the gas fees,
/// and deposits the gas fees into the provided coinbase address.
/// An invalid transaction is not executed and not included in the block.
access(all)
fun batchRun(txs: [[UInt8]], coinbase: EVMAddress): [Result] {
return InternalEVM.batchRun(
txs: txs,
coinbase: coinbase.bytes,
) as! [Result]
}

access(all)
fun encodeABI(_ values: [AnyStruct]): [UInt8] {
return InternalEVM.encodeABI(values)
Expand Down
Loading