Files
serai/processor/ethereum/deployer/src/tests.rs
Luke Parker 184c02714a 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.
2025-04-12 08:09:09 -04:00

108 lines
3.9 KiB
Rust

use std::sync::Arc;
use alloy_rpc_types_eth::{TransactionInput, TransactionRequest};
use alloy_simple_request_transport::SimpleRequest;
use alloy_rpc_client::ClientBuilder;
use alloy_provider::{Provider, RootProvider};
use alloy_node_bindings::Anvil;
use crate::{
abi::Deployer::{PriorDeployed, DeploymentFailed, DeployerErrors},
Deployer,
};
#[tokio::test]
async fn test_deployer() {
const CANCUN: &str = "cancun";
const LATEST: &str = "latest";
for network in [CANCUN, LATEST] {
let anvil = Anvil::new().arg("--hardfork").arg(network).spawn();
let provider = Arc::new(RootProvider::new(
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()), true),
));
// Deploy the Deployer
{
let deployment_tx = Deployer::deployment_tx();
let gas_programmed = deployment_tx.tx().gas_limit;
let receipt = ethereum_test_primitives::publish_tx(&provider, deployment_tx).await;
assert!(receipt.status());
assert_eq!(receipt.contract_address.unwrap(), Deployer::address());
if network == CANCUN {
// Check the gas programmed was twice the gas used
// We only check this for cancun as the constant was programmed per cancun's gas pricing
assert_eq!(2 * receipt.gas_used, gas_programmed);
}
}
// Deploy the deployer with the deployer
let mut deploy_tx = Deployer::deploy_tx(crate::INITCODE.to_vec());
deploy_tx.gas_price = 100_000_000_000u128;
deploy_tx.gas_limit = 1_000_000;
{
let deploy_tx = ethereum_primitives::deterministically_sign(deploy_tx.clone());
let receipt = ethereum_test_primitives::publish_tx(&provider, deploy_tx).await;
assert!(receipt.status());
}
// Verify we can now find the deployer
{
let deployer = Deployer::new(provider.clone()).await.unwrap().unwrap();
let deployed_deployer = deployer
.find_deployment(ethereum_primitives::keccak256(crate::INITCODE))
.await
.unwrap()
.unwrap();
assert_eq!(
provider.get_code_at(deployed_deployer).await.unwrap(),
provider.get_code_at(Deployer::address()).await.unwrap(),
);
assert!(deployed_deployer != Deployer::address());
}
// Verify deploying the same init code multiple times fails
{
let mut deploy_tx = deploy_tx;
// Change the gas price to cause a distinct message, and with it, a distinct signer
deploy_tx.gas_price += 1;
let deploy_tx = ethereum_primitives::deterministically_sign(deploy_tx);
let receipt = ethereum_test_primitives::publish_tx(&provider, deploy_tx.clone()).await;
assert!(!receipt.status());
let call = TransactionRequest::default()
.to(Deployer::address())
.input(TransactionInput::new(deploy_tx.tx().input.clone()));
let call_err = provider.call(call).await.unwrap_err();
assert!(matches!(
call_err.as_error_resp().unwrap().as_decoded_interface_error::<DeployerErrors>().unwrap(),
DeployerErrors::PriorDeployed(PriorDeployed {}),
));
}
// Verify deployment failures yield errors properly
{
// 0xfe is an invalid opcode which is guaranteed to remain invalid
let mut deploy_tx = Deployer::deploy_tx(vec![0xfe]);
deploy_tx.gas_price = 100_000_000_000u128;
deploy_tx.gas_limit = 1_000_000;
let deploy_tx = ethereum_primitives::deterministically_sign(deploy_tx);
let receipt = ethereum_test_primitives::publish_tx(&provider, deploy_tx.clone()).await;
assert!(!receipt.status());
let call = TransactionRequest::default()
.to(Deployer::address())
.input(TransactionInput::new(deploy_tx.tx().input.clone()));
let call_err = provider.call(call).await.unwrap_err();
assert!(matches!(
call_err.as_error_resp().unwrap().as_decoded_interface_error::<DeployerErrors>().unwrap(),
DeployerErrors::DeploymentFailed(DeploymentFailed {}),
));
}
}
}