Implement a solution for the pre-fund account limit

This commit is contained in:
Omar Abdulla
2025-09-28 16:52:43 +03:00
parent f9dc362c03
commit ec96410546
9 changed files with 228 additions and 32 deletions
Generated
+1
View File
@@ -4618,6 +4618,7 @@ version = "0.1.0"
dependencies = [
"alloy",
"anyhow",
"futures",
"revive-common",
"revive-dt-common",
"revive-dt-config",
+152 -1
View File
@@ -236,6 +236,78 @@ pub struct TestExecutionContext {
pub report_configuration: ReportConfiguration,
}
#[derive(Clone, Debug, Parser, Serialize)]
pub struct BenchmarkingContext {
/// The working directory that the program will use for all of the temporary artifacts needed at
/// runtime.
///
/// If not specified, then a temporary directory will be created and used by the program for all
/// temporary artifacts.
#[clap(
short,
long,
default_value = "",
value_hint = ValueHint::DirPath,
)]
pub working_directory: WorkingDirectoryConfiguration,
/// The set of platforms that the differential tests should run on.
#[arg(
short = 'p',
long = "platform",
default_values = ["geth-evm-solc", "revive-dev-node-polkavm-resolc"]
)]
pub platforms: Vec<PlatformIdentifier>,
/// A list of test corpus JSON files to be tested.
#[arg(long = "corpus", short)]
pub corpus: Vec<PathBuf>,
/// Configuration parameters for the solc compiler.
#[clap(flatten, next_help_heading = "Solc Configuration")]
pub solc_configuration: SolcConfiguration,
/// Configuration parameters for the resolc compiler.
#[clap(flatten, next_help_heading = "Resolc Configuration")]
pub resolc_configuration: ResolcConfiguration,
/// Configuration parameters for the geth node.
#[clap(flatten, next_help_heading = "Geth Configuration")]
pub geth_configuration: GethConfiguration,
/// Configuration parameters for the lighthouse node.
#[clap(flatten, next_help_heading = "Lighthouse Configuration")]
pub lighthouse_configuration: KurtosisConfiguration,
/// Configuration parameters for the Kitchensink.
#[clap(flatten, next_help_heading = "Kitchensink Configuration")]
pub kitchensink_configuration: KitchensinkConfiguration,
/// Configuration parameters for the Revive Dev Node.
#[clap(flatten, next_help_heading = "Revive Dev Node Configuration")]
pub revive_dev_node_configuration: ReviveDevNodeConfiguration,
/// Configuration parameters for the Eth Rpc.
#[clap(flatten, next_help_heading = "Eth RPC Configuration")]
pub eth_rpc_configuration: EthRpcConfiguration,
/// Configuration parameters for the wallet.
#[clap(flatten, next_help_heading = "Wallet Configuration")]
pub wallet_configuration: WalletConfiguration,
/// Configuration parameters for concurrency.
#[clap(flatten, next_help_heading = "Concurrency Configuration")]
pub concurrency_configuration: ConcurrencyConfiguration,
/// Configuration parameters for the compilers and compilation.
#[clap(flatten, next_help_heading = "Compilation Configuration")]
pub compilation_configuration: CompilationConfiguration,
/// Configuration parameters for the report.
#[clap(flatten, next_help_heading = "Report Configuration")]
pub report_configuration: ReportConfiguration,
}
impl Default for TestExecutionContext {
fn default() -> Self {
Self::parse_from(["execution-context"])
@@ -320,6 +392,84 @@ impl AsRef<ReportConfiguration> for TestExecutionContext {
}
}
impl Default for BenchmarkingContext {
fn default() -> Self {
Self::parse_from(["execution-context"])
}
}
impl AsRef<WorkingDirectoryConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &WorkingDirectoryConfiguration {
&self.working_directory
}
}
impl AsRef<SolcConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &SolcConfiguration {
&self.solc_configuration
}
}
impl AsRef<ResolcConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &ResolcConfiguration {
&self.resolc_configuration
}
}
impl AsRef<GethConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &GethConfiguration {
&self.geth_configuration
}
}
impl AsRef<KurtosisConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &KurtosisConfiguration {
&self.lighthouse_configuration
}
}
impl AsRef<KitchensinkConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &KitchensinkConfiguration {
&self.kitchensink_configuration
}
}
impl AsRef<ReviveDevNodeConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &ReviveDevNodeConfiguration {
&self.revive_dev_node_configuration
}
}
impl AsRef<EthRpcConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &EthRpcConfiguration {
&self.eth_rpc_configuration
}
}
impl AsRef<WalletConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &WalletConfiguration {
&self.wallet_configuration
}
}
impl AsRef<ConcurrencyConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &ConcurrencyConfiguration {
&self.concurrency_configuration
}
}
impl AsRef<CompilationConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &CompilationConfiguration {
&self.compilation_configuration
}
}
impl AsRef<ReportConfiguration> for BenchmarkingContext {
fn as_ref(&self) -> &ReportConfiguration {
&self.report_configuration
}
}
/// A set of configuration parameters for Solc.
#[derive(Clone, Debug, Parser, Serialize)]
pub struct SolcConfiguration {
@@ -499,7 +649,7 @@ pub struct WalletConfiguration {
/// This argument controls which private keys the nodes should have access to and be added to
/// its wallet signers. With a value of N, private keys (0, N] will be added to the signer set
/// of the node.
#[clap(long = "wallet.additional-keys", default_value_t = 200)]
#[clap(long = "wallet.additional-keys", default_value_t = 100_000)]
additional_keys: usize,
/// The wallet object that will be used.
@@ -629,6 +779,7 @@ impl AsRef<Path> for WorkingDirectoryConfiguration {
impl Default for WorkingDirectoryConfiguration {
fn default() -> Self {
TempDir::new()
.map(|tempdir| dbg!(tempdir.dont_delete_on_drop()))
.map(Arc::new)
.map(Self::TemporaryDirectory)
.expect("Failed to create the temporary directory")
+1
View File
@@ -147,6 +147,7 @@ async fn run_driver(
let mut nodes = Vec::<(&dyn Platform, NodePool)>::new();
for platform in platforms.into_iter() {
let pool = NodePool::new(Context::ExecuteTests(Box::new(context.clone())), platform)
.await
.inspect_err(|err| {
error!(
?err,
+9 -1
View File
@@ -16,7 +16,7 @@ pub struct NodePool {
impl NodePool {
/// Create a new Pool. This will start as many nodes as there are workers in `config`.
pub fn new(context: Context, platform: &dyn Platform) -> anyhow::Result<Self> {
pub async fn new(context: Context, platform: &dyn Platform) -> anyhow::Result<Self> {
let concurrency_configuration = AsRef::<ConcurrencyConfiguration>::as_ref(&context);
let nodes = concurrency_configuration.number_of_nodes;
@@ -38,6 +38,14 @@ impl NodePool {
);
}
let pre_transactions_tasks = nodes
.iter_mut()
.map(|node| node.pre_transactions())
.collect::<Vec<_>>();
futures::future::try_join_all(pre_transactions_tasks)
.await
.context("Failed to run the pre-transactions task")?;
Ok(Self {
nodes,
next: Default::default(),
+3
View File
@@ -14,6 +14,9 @@ use revive_dt_format::traits::ResolverApi;
/// An interface for all interactions with Ethereum compatible nodes.
#[allow(clippy::type_complexity)]
pub trait EthereumNode {
/// A function to run post spawning the nodes and before any transactions are run on the node.
fn pre_transactions(&mut self) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + '_>>;
fn id(&self) -> usize;
/// Returns the nodes connection string.
+1
View File
@@ -11,6 +11,7 @@ rust-version.workspace = true
[dependencies]
anyhow = { workspace = true }
alloy = { workspace = true }
futures = { workspace = true }
tracing = { workspace = true }
tokio = { workspace = true }
+4
View File
@@ -266,6 +266,10 @@ impl GethNode {
}
impl EthereumNode for GethNode {
fn pre_transactions(&mut self) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + '_>> {
Box::pin(async move { Ok(()) })
}
fn id(&self) -> usize {
self.id as _
}
+53 -30
View File
@@ -39,8 +39,10 @@ use alloy::{
EIP1186AccountProofResponse, TransactionRequest,
trace::geth::{DiffMode, GethDebugTracingOptions, PreStateConfig, PreStateFrame},
},
signers::local::PrivateKeySigner,
};
use anyhow::Context as _;
use futures::future;
use revive_common::EVMVersion;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::serde_as;
@@ -91,6 +93,9 @@ pub struct LighthouseGethNode {
/* Spawned Processes */
process: Option<Process>,
/* Prefunded Account Information */
prefunded_account_private_key: PrivateKeySigner,
/* Provider Related Fields */
wallet: Arc<EthereumWallet>,
nonce_manager: CachedNonceManager,
@@ -160,6 +165,9 @@ impl LighthouseGethNode {
/* Spawned Processes */
process: None,
/* Prefunded Account Information */
prefunded_account_private_key: PrivateKeySigner::random(),
/* Provider Related Fields */
wallet: wallet.clone(),
nonce_manager: Default::default(),
@@ -168,7 +176,7 @@ impl LighthouseGethNode {
}
/// Create the node directory and call `geth init` to configure the genesis.
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn init(&mut self, _: Genesis) -> anyhow::Result<&mut Self> {
self.init_directories()
.context("Failed to initialize the directories of the Lighthouse Geth node.")?;
@@ -228,14 +236,8 @@ impl LighthouseGethNode {
num_validator_keys_per_node: 64,
genesis_delay: 10,
prefunded_accounts: {
let map = NetworkWallet::<Ethereum>::signer_addresses(&self.wallet)
.map(|address| {
(
address,
GenesisAccount::default()
.with_balance(INITIAL_BALANCE.try_into().unwrap()),
)
})
let map = std::iter::once(self.prefunded_account_private_key.address())
.map(|address| (address, GenesisAccount::default().with_balance(U256::MAX)))
.collect::<BTreeMap<_, _>>();
serde_json::to_string(&map).unwrap()
},
@@ -261,7 +263,7 @@ impl LighthouseGethNode {
}
/// Spawn the go-ethereum node child process.
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn spawn_process(&mut self) -> anyhow::Result<&mut Self> {
let process = Process::new(
None,
@@ -346,9 +348,30 @@ impl LighthouseGethNode {
.await
.context("Failed to create the provider for Kurtosis")
}
/// Funds all of the accounts in the Ethereum wallet from the initially funded account.
async fn fund_all_accounts(&self) -> anyhow::Result<()> {
let tasks = NetworkWallet::<Ethereum>::signer_addresses(self.wallet.as_ref())
.enumerate()
.map(|(nonce, address)| async move {
let transaction = TransactionRequest::default()
.from(self.prefunded_account_private_key.address())
.to(address)
.nonce(nonce as _)
.value(INITIAL_BALANCE.try_into().unwrap());
self.execute_transaction(transaction).await
})
.collect::<Vec<_>>();
future::try_join_all(tasks).await?;
Ok(())
}
}
impl EthereumNode for LighthouseGethNode {
fn pre_transactions(&mut self) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + '_>> {
Box::pin(async move { self.fund_all_accounts().await })
}
fn id(&self) -> usize {
self.id as _
}
@@ -360,7 +383,7 @@ impl EthereumNode for LighthouseGethNode {
#[instrument(
level = "info",
skip_all,
fields(geth_node_id = self.id, connection_string = self.connection_string),
fields(lighthouse_node_id = self.id, connection_string = self.connection_string),
err,
)]
fn execute_transaction(
@@ -407,7 +430,7 @@ impl EthereumNode for LighthouseGethNode {
let provider = Arc::new(provider);
poll(
Self::RECEIPT_POLLING_DURATION,
PollingWaitBehavior::Constant(Duration::from_millis(200)),
PollingWaitBehavior::Constant(Duration::from_millis(500)),
move || {
let provider = provider.clone();
async move {
@@ -433,7 +456,7 @@ impl EthereumNode for LighthouseGethNode {
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn trace_transaction(
&self,
tx_hash: TxHash,
@@ -473,7 +496,7 @@ impl EthereumNode for LighthouseGethNode {
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn state_diff(
&self,
tx_hash: TxHash,
@@ -497,7 +520,7 @@ impl EthereumNode for LighthouseGethNode {
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn balance_of(
&self,
address: Address,
@@ -512,7 +535,7 @@ impl EthereumNode for LighthouseGethNode {
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn latest_state_proof(
&self,
address: Address,
@@ -529,7 +552,7 @@ impl EthereumNode for LighthouseGethNode {
})
}
// #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
// #[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn resolver(
&self,
) -> Pin<Box<dyn Future<Output = anyhow::Result<Arc<dyn ResolverApi + '_>>> + '_>> {
@@ -553,14 +576,14 @@ pub struct LighthouseGethNodeResolver<F: TxFiller<Ethereum>, P: Provider<Ethereu
impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
for LighthouseGethNodeResolver<F, P>
{
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn chain_id(
&self,
) -> Pin<Box<dyn Future<Output = anyhow::Result<alloy::primitives::ChainId>> + '_>> {
Box::pin(async move { self.provider.get_chain_id().await.map_err(Into::into) })
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn transaction_gas_price(
&self,
tx_hash: TxHash,
@@ -574,7 +597,7 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn block_gas_limit(
&self,
number: BlockNumberOrTag,
@@ -589,7 +612,7 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn block_coinbase(
&self,
number: BlockNumberOrTag,
@@ -604,7 +627,7 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn block_difficulty(
&self,
number: BlockNumberOrTag,
@@ -619,7 +642,7 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn block_base_fee(
&self,
number: BlockNumberOrTag,
@@ -639,7 +662,7 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn block_hash(
&self,
number: BlockNumberOrTag,
@@ -654,7 +677,7 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn block_timestamp(
&self,
number: BlockNumberOrTag,
@@ -669,14 +692,14 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
})
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn last_block_number(&self) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockNumber>> + '_>> {
Box::pin(async move { self.provider.get_block_number().await.map_err(Into::into) })
}
}
impl Node for LighthouseGethNode {
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn shutdown(&mut self) -> anyhow::Result<()> {
if !Command::new(self.kurtosis_binary_path.as_path())
.arg("enclave")
@@ -699,13 +722,13 @@ impl Node for LighthouseGethNode {
Ok(())
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn spawn(&mut self, genesis: Genesis) -> anyhow::Result<()> {
self.init(genesis)?.spawn_process()?;
Ok(())
}
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn version(&self) -> anyhow::Result<String> {
let output = Command::new(&self.kurtosis_binary_path)
.arg("version")
@@ -722,7 +745,7 @@ impl Node for LighthouseGethNode {
}
impl Drop for LighthouseGethNode {
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
#[instrument(level = "info", skip_all, fields(lighthouse_node_id = self.id))]
fn drop(&mut self) {
self.shutdown().expect("Failed to shutdown")
}
+4
View File
@@ -356,6 +356,10 @@ impl SubstrateNode {
}
impl EthereumNode for SubstrateNode {
fn pre_transactions(&mut self) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + '_>> {
Box::pin(async move { Ok(()) })
}
fn id(&self) -> usize {
self.id as _
}