Skip to content

Commit 29f5a83

Browse files
Implement the calls from the EVM to {EVM,Wasm}. (#3717)
## Motivation We have the EVM application, but not the function calls from the EVM to EVM/Wasm. ## Proposal We have two cases to cover and the implementation is distinct for both cases. Call to EVM: * The EVM itself has cross-application calls and it has a well established system for doing application calls. * We want to reproduce that system and the canonical technique in REVM is to use a Call interceptor that implements the inspector trait. We need a Contract version and a Service version. * That call is thus bypassed and send to a `try_call_application/try_query_application`. * However, for the inspector trait, we need more than just the output, we need the full `InterpreterResult`. This forces adding a specific selector named `INTERPRETER_RESULT_SELECTOR`. This hack has the same cryptographic assumption as the use of selectors by the EVM. * Depending on the case, we return differently. * The EVM addresses are converted to ApplicationId by adding 12 values 0. Call to Wasm: * Calling the Wasm is done by using the precompile. This address returns the `bytes` output, which is then processed. * Of course we need precompile for contract and for service. They call `try_call_application/try_query_application`. * The calls are done directly with the serialization/deserialization being done in the solidity code. * The address is composed as a `bytes32`. Next steps: * Implement the fuel consumption. * Implement the transfer. * Implement further LINERA APIs in the EVM. Implement the code by using solidity code. Coauthored by Andreas Fackler ## Test Plan The testing framework is done in parallel to the test in `test_wasm_call_evm_end_to_end_counter` with the same values and the same APIs. For the `test_evm_call_evm_end_to_end_counter` this is rather straightforward in term of contract code and it would be the same if one write something in ethereum. For the `test_evm_call_wasm_end_to_end_counter` this is far more problematic: * The serialization for `execute_operation` is done with BCS. We wrote the code as generated by `serde-reflection`. * The serialization for `query_operation` is done with `serde_json`. So far, there is no code for generating this code in `serde-reflection`. In the EVM, we have a `eth_sendRawTransaction/eth_getTransactionReceipt` and the `eth_call`. If an EVM smart contract in linera is calling Wasm application, then we cannot have the same behavior. ## Release Plan This should be significant for next TestNet. ## Links None.
1 parent 410e2c7 commit 29f5a83

File tree

21 files changed

+1535
-702
lines changed

21 files changed

+1535
-702
lines changed

Cargo.lock

Lines changed: 60 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ rcgen = "0.12.1"
142142
reqwest = { version = "0.11.24", default-features = false, features = [
143143
"rustls-tls",
144144
] }
145-
revm = "19.4.0"
146-
revm-interpreter = { version = "15.1.0", features = ["serde"] }
147-
revm-precompile = "16.0.0"
148-
revm-primitives = "15.1.0"
145+
revm = "19.7.0"
146+
revm-interpreter = { version = "15.2.0", features = ["serde"] }
147+
revm-precompile = "16.2.0"
148+
revm-primitives = "15.2.0"
149149
rocksdb = "0.21.0"
150150
ruzstd = "0.7.1"
151151
scylla = "0.15.1"

linera-base/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ version.workspace = true
1414
[features]
1515
metrics = ["prometheus"]
1616
reqwest = ["dep:reqwest"]
17+
revm = []
1718
test = ["test-strategy", "proptest"]
1819
web = [
1920
"getrandom/js",

linera-base/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ fn main() {
88
with_metrics: { all(not(target_arch = "wasm32"), feature = "metrics") },
99
with_reqwest: { feature = "reqwest" },
1010
with_testing: { any(test, feature = "test") },
11+
with_revm: { any(test, feature = "revm") },
1112

1213
// the old version of `getrandom` we pin here is available on all targets, but
1314
// using it will panic if no suitable source of entropy is found

linera-base/src/identifiers.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use std::{
1010
str::FromStr,
1111
};
1212

13+
#[cfg(with_revm)]
14+
use alloy_primitives::{Address, B256};
1315
use anyhow::{anyhow, Context};
1416
use async_graphql::SimpleObject;
1517
use custom_debug_derive::Debug;
@@ -952,6 +954,21 @@ impl<A> ApplicationId<A> {
952954
}
953955
}
954956

957+
#[cfg(with_revm)]
958+
impl<A> ApplicationId<A> {
959+
/// Converts the `ApplicationId` into an Ethereum Address.
960+
pub fn evm_address(&self) -> Address {
961+
let bytes = self.application_description_hash.as_bytes();
962+
let bytes = bytes.0.as_ref();
963+
Address::from_slice(&bytes[0..20])
964+
}
965+
966+
/// Converts the `ApplicationId` into an Ethereum-compatible 32-byte array.
967+
pub fn bytes32(&self) -> B256 {
968+
*self.application_description_hash.as_bytes()
969+
}
970+
}
971+
955972
#[derive(Serialize, Deserialize)]
956973
#[serde(rename = "AccountOwner")]
957974
enum SerializableAccountOwner {

linera-execution/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ test = ["tokio/macros", "linera-base/test", "linera-views/test", "proptest"]
1616
revm = [
1717
"dep:revm",
1818
"dep:revm-primitives",
19+
"dep:revm-precompile",
20+
"dep:revm-interpreter",
1921
"dep:alloy",
2022
"dep:alloy-sol-types",
2123
"dep:hex",
@@ -55,6 +57,8 @@ prometheus = { workspace = true, optional = true }
5557
proptest = { workspace = true, optional = true }
5658
reqwest = { workspace = true, features = ["blocking", "json", "stream"] }
5759
revm = { workspace = true, optional = true, features = ["serde"] }
60+
revm-interpreter = { workspace = true, optional = true, features = ["serde"] }
61+
revm-precompile = { workspace = true, optional = true }
5862
revm-primitives = { workspace = true, optional = true }
5963
serde.workspace = true
6064
serde_bytes.workspace = true

0 commit comments

Comments
 (0)