alloy-core 1.0, alloy 0.14, revm 0.22 (001)

This moves to Rust 1.86 as were prior on Rust 1.81, and the new alloy
dependencies require 1.82.

The revm API changes were notable for us. Instead of relying on a modified call
instruction (with deep introspection into the EVM design), we now use the more
recent and now more prominent Inspector API. This:

1) Lets us perform far less introspection
2) Forces us to rewrite the gas estimation code we just had audited

Thankfully, it itself should be much easier to read/review, and our existing
test suite has extensively validated it.

This resolves 001 which was a concern for if/when this upgrade occurs. By doing
it now, with a dedicated test case ensuring the issue we would have had with
alloy-core 0.8 and `validate=false` isn't actively an issue, we resolve it.
This commit is contained in:
Luke Parker
2025-04-12 08:09:09 -04:00
parent 5a7b815e2e
commit 184c02714a
25 changed files with 1483 additions and 625 deletions

View File

@@ -17,15 +17,14 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true
[dependencies]
alloy-core = { version = "0.8", default-features = false }
alloy-core = { version = "1", default-features = false }
alloy-sol-types = { version = "0.8", default-features = false }
alloy-sol-macro = { version = "0.8", default-features = false }
alloy-sol-types = { version = "1", default-features = false }
alloy-sol-macro = { version = "1", default-features = false }
alloy-rpc-types-eth = { version = "0.9", default-features = false }
alloy-transport = { version = "0.9", default-features = false }
alloy-simple-request-transport = { path = "../../../networks/ethereum/alloy-simple-request-transport", default-features = false }
alloy-provider = { version = "0.9", default-features = false }
alloy-rpc-types-eth = { version = "0.14", default-features = false }
alloy-transport = { version = "0.14", default-features = false }
alloy-provider = { version = "0.14", default-features = false }
ethereum-primitives = { package = "serai-processor-ethereum-primitives", path = "../primitives", default-features = false }

View File

@@ -11,7 +11,6 @@ use alloy_sol_types::{SolInterface, SolEvent};
use alloy_rpc_types_eth::{Log, Filter, TransactionTrait};
use alloy_transport::{TransportErrorKind, RpcError};
use alloy_simple_request_transport::SimpleRequest;
use alloy_provider::{Provider, RootProvider};
use ethereum_primitives::LogIndex;
@@ -94,7 +93,7 @@ impl Erc20 {
// Yielding THE top-level transfer would require tracing the transaction execution and isn't
// worth the effort.
async fn top_level_transfer(
provider: &RootProvider<SimpleRequest>,
provider: &RootProvider,
erc20: Address,
transaction_hash: [u8; 32],
transfer_logs: &[Log],
@@ -112,15 +111,13 @@ impl Erc20 {
return Ok(None);
}
// Don't validate the encoding as this can't be re-encoded to an identical bytestring due
// to the additional data appended after the call itself
let Ok(call) = IERC20Calls::abi_decode(transaction.inner.input(), false) else {
let Ok(call) = IERC20Calls::abi_decode(transaction.inner.input()) else {
return Ok(None);
};
// Extract the top-level call's from/to/value
let (from, to, value) = match call {
IERC20Calls::transfer(transferCall { to, value }) => (transaction.from, to, value),
IERC20Calls::transfer(transferCall { to, value }) => (transaction.inner.signer(), to, value),
IERC20Calls::transferFrom(transferFromCall { from, to, value }) => (from, to, value),
// Treat any other function selectors as unrecognized
_ => return Ok(None),
@@ -149,7 +146,7 @@ impl Erc20 {
}
// Read the data appended after
let data = if let Ok(call) = SeraiIERC20Calls::abi_decode(transaction.inner.input(), true) {
let data = if let Ok(call) = SeraiIERC20Calls::abi_decode(transaction.inner.input()) {
match call {
SeraiIERC20Calls::transferWithInInstruction01BB244A8A(
transferWithInInstructionCall { inInstruction, .. },
@@ -180,7 +177,7 @@ impl Erc20 {
///
/// The `transfers` in the result are unordered. The `logs` are sorted by index.
pub async fn top_level_transfers_unordered(
provider: &RootProvider<SimpleRequest>,
provider: &RootProvider,
blocks: RangeInclusive<u64>,
erc20: Address,
to: Address,

View File

@@ -12,4 +12,30 @@ fn selector_collisions() {
);
}
#[test]
fn abi_decode_panic() {
use alloy_sol_types::SolInterface;
/*
The following code panics with alloy-core 0.8, when the validate flag (commented out) is set to
`false`. This flag was removed with alloy-core 1.0, leaving the default behavior of
`abi_decode` to be `validate = false`. This test was added to ensure when we removed our
practice of `validate = true`, we didn't open ourselves up this as a DoS risk.
*/
assert!(crate::SeraiIERC20Calls::abi_decode(
&alloy_core::primitives::hex::decode(concat!(
"a9059cbb",
"0000000000000000000000000000000000000000000000000000000000000000",
"0000000000000000000000000000000000000000000000000000000000000000",
"000000000000000000000000000000000000000000000000000000000000006f",
"ffffffffff000000000000000000000000000000000000000000000000000023",
"000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ffffff0000000000000000000000000000000000000000000000000000000000",
))
.unwrap(),
// false
)
.is_err());
}
// This is primarily tested via serai-processor-ethereum-router