Provide a common node implementation for substrate chains

This commit is contained in:
Omar Abdulla
2025-09-17 20:23:31 +03:00
parent ac0f4e0cf2
commit f0f59ad024
4 changed files with 107 additions and 126 deletions
+2 -2
View File
@@ -20,7 +20,7 @@ use revive_dt_format::traits::ResolverApi;
use revive_dt_node::{ use revive_dt_node::{
Node, Node,
geth::{self, GethNode}, geth::{self, GethNode},
kitchensink::KitchensinkNode, substrate::SubstrateNode,
}; };
use revive_dt_node_interaction::EthereumNode; use revive_dt_node_interaction::EthereumNode;
use tracing::info; use tracing::info;
@@ -54,7 +54,7 @@ impl Platform for Geth {
pub struct Kitchensink; pub struct Kitchensink;
impl Platform for Kitchensink { impl Platform for Kitchensink {
type Blockchain = KitchensinkNode; type Blockchain = SubstrateNode;
type Compiler = revive_resolc::Resolc; type Compiler = revive_resolc::Resolc;
fn config_id() -> &'static TestingPlatform { fn config_id() -> &'static TestingPlatform {
+1 -2
View File
@@ -2,14 +2,13 @@
use alloy::genesis::Genesis; use alloy::genesis::Genesis;
use revive_common::EVMVersion; use revive_common::EVMVersion;
use revive_dt_config::*;
use revive_dt_node_interaction::EthereumNode; use revive_dt_node_interaction::EthereumNode;
pub mod common; pub mod common;
pub mod constants; pub mod constants;
pub mod geth; pub mod geth;
pub mod kitchensink;
pub mod pool; pub mod pool;
pub mod substrate;
/// An abstract interface for testing nodes. /// An abstract interface for testing nodes.
pub trait Node: EthereumNode { pub trait Node: EthereumNode {
+2 -3
View File
@@ -12,7 +12,6 @@ use revive_dt_config::{
KitchensinkConfiguration, ReviveDevNodeConfiguration, WalletConfiguration, KitchensinkConfiguration, ReviveDevNodeConfiguration, WalletConfiguration,
WorkingDirectoryConfiguration, WorkingDirectoryConfiguration,
}; };
use tracing::info;
use crate::Node; use crate::Node;
@@ -81,7 +80,7 @@ where
} }
fn spawn_node<T: Node + Send>( fn spawn_node<T: Node + Send>(
context: impl AsRef<WorkingDirectoryConfiguration> _: impl AsRef<WorkingDirectoryConfiguration>
+ AsRef<ConcurrencyConfiguration> + AsRef<ConcurrencyConfiguration>
+ AsRef<GenesisConfiguration> + AsRef<GenesisConfiguration>
+ AsRef<WalletConfiguration> + AsRef<WalletConfiguration>
@@ -91,7 +90,7 @@ fn spawn_node<T: Node + Send>(
+ AsRef<EthRpcConfiguration> + AsRef<EthRpcConfiguration>
+ Clone + Clone
+ 'static, + 'static,
genesis: Genesis, _: Genesis,
) -> anyhow::Result<T> { ) -> anyhow::Result<T> {
todo!("Remove"); todo!("Remove");
} }
@@ -51,12 +51,15 @@ use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE};
static NODE_COUNT: AtomicU32 = AtomicU32::new(0); static NODE_COUNT: AtomicU32 = AtomicU32::new(0);
/// A node implementation for Substrate based chains. Currently, this supports either kitchensink
/// or the revive-dev-node which is done by changing the path and some of the other arguments passed
/// to the command.
#[derive(Debug)] #[derive(Debug)]
pub struct KitchensinkNode { pub struct SubstrateNode {
id: u32, id: u32,
substrate_binary: PathBuf, node_binary: PathBuf,
dev_node_binary: PathBuf,
eth_proxy_binary: PathBuf, eth_proxy_binary: PathBuf,
export_chainspec_command: String,
rpc_url: String, rpc_url: String,
base_directory: PathBuf, base_directory: PathBuf,
logs_directory: PathBuf, logs_directory: PathBuf,
@@ -65,16 +68,11 @@ pub struct KitchensinkNode {
wallet: Arc<EthereumWallet>, wallet: Arc<EthereumWallet>,
nonce_manager: CachedNonceManager, nonce_manager: CachedNonceManager,
chain_id_filler: ChainIdFiller, chain_id_filler: ChainIdFiller,
use_kitchensink_not_dev_node: bool,
/// This vector stores [`File`] objects that we use for logging which we want to flush when the
/// node object is dropped. We do not store them in a structured fashion at the moment (in
/// separate fields) as the logic that we need to apply to them is all the same regardless of
/// what it belongs to, we just want to flush them on [`Drop`] of the node.
logs_file_to_flush: Vec<File>, logs_file_to_flush: Vec<File>,
} }
impl KitchensinkNode { impl SubstrateNode {
const BASE_DIRECTORY: &str = "kitchensink"; const BASE_DIRECTORY: &str = "Substrate";
const LOGS_DIRECTORY: &str = "logs"; const LOGS_DIRECTORY: &str = "logs";
const DATA_DIRECTORY: &str = "chains"; const DATA_DIRECTORY: &str = "chains";
@@ -87,44 +85,39 @@ impl KitchensinkNode {
const SUBSTRATE_LOG_ENV: &str = "error,evm=debug,sc_rpc_server=info,runtime::revive=debug"; const SUBSTRATE_LOG_ENV: &str = "error,evm=debug,sc_rpc_server=info,runtime::revive=debug";
const PROXY_LOG_ENV: &str = "info,eth-rpc=debug"; const PROXY_LOG_ENV: &str = "info,eth-rpc=debug";
const KITCHENSINK_STDOUT_LOG_FILE_NAME: &str = "node_stdout.log"; const SUBSTRATE_STDOUT_LOG_FILE_NAME: &str = "node_stdout.log";
const KITCHENSINK_STDERR_LOG_FILE_NAME: &str = "node_stderr.log"; const SUBSTRATE_STDERR_LOG_FILE_NAME: &str = "node_stderr.log";
const PROXY_STDOUT_LOG_FILE_NAME: &str = "proxy_stdout.log"; const PROXY_STDOUT_LOG_FILE_NAME: &str = "proxy_stdout.log";
const PROXY_STDERR_LOG_FILE_NAME: &str = "proxy_stderr.log"; const PROXY_STDERR_LOG_FILE_NAME: &str = "proxy_stderr.log";
pub const KITCHENSINK_EXPORT_CHAINSPEC_COMMAND: &str = "export-chain-spec";
pub const REVIVE_DEV_NODE_EXPORT_CHAINSPEC_COMMAND: &str = "build-spec";
pub fn new( pub fn new(
node_path: PathBuf,
export_chainspec_command: &str,
context: impl AsRef<WorkingDirectoryConfiguration> context: impl AsRef<WorkingDirectoryConfiguration>
+ AsRef<ConcurrencyConfiguration>
+ AsRef<GenesisConfiguration>
+ AsRef<WalletConfiguration>
+ AsRef<GethConfiguration>
+ AsRef<KitchensinkConfiguration>
+ AsRef<ReviveDevNodeConfiguration>
+ AsRef<EthRpcConfiguration> + AsRef<EthRpcConfiguration>
+ Clone, + AsRef<WalletConfiguration>,
) -> Self { ) -> Self {
let kitchensink_configuration = AsRef::<KitchensinkConfiguration>::as_ref(&context); let working_directory_path =
let dev_node_configuration = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context); AsRef::<WorkingDirectoryConfiguration>::as_ref(&context).as_path();
let eth_rpc_configuration = AsRef::<EthRpcConfiguration>::as_ref(&context); let eth_rpc_path = AsRef::<EthRpcConfiguration>::as_ref(&context)
let working_directory_configuration = .path
AsRef::<WorkingDirectoryConfiguration>::as_ref(&context); .as_path();
let wallet_configuration = AsRef::<WalletConfiguration>::as_ref(&context); let wallet = AsRef::<WalletConfiguration>::as_ref(&context).wallet();
let kitchensink_directory = working_directory_configuration let substrate_directory = working_directory_path.join(Self::BASE_DIRECTORY);
.as_path()
.join(Self::BASE_DIRECTORY);
let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst);
let base_directory = kitchensink_directory.join(id.to_string()); let base_directory = substrate_directory.join(id.to_string());
let logs_directory = base_directory.join(Self::LOGS_DIRECTORY); let logs_directory = base_directory.join(Self::LOGS_DIRECTORY);
let wallet = wallet_configuration.wallet();
Self { Self {
id, id,
substrate_binary: kitchensink_configuration.path.clone(), node_binary: node_path,
dev_node_binary: dev_node_configuration.path.clone(), eth_proxy_binary: eth_rpc_path.to_path_buf(),
eth_proxy_binary: eth_rpc_configuration.path.clone(), export_chainspec_command: export_chainspec_command.to_string(),
rpc_url: String::new(), rpc_url: String::new(),
base_directory, base_directory,
logs_directory, logs_directory,
@@ -133,9 +126,6 @@ impl KitchensinkNode {
wallet: wallet.clone(), wallet: wallet.clone(),
chain_id_filler: Default::default(), chain_id_filler: Default::default(),
nonce_manager: Default::default(), nonce_manager: Default::default(),
use_kitchensink_not_dev_node: kitchensink_configuration.use_kitchensink,
// We know that we only need to be storing 4 files so we can specify that when creating
// the vector. It's the stdout and stderr of the substrate-node and the eth-rpc.
logs_file_to_flush: Vec::with_capacity(4), logs_file_to_flush: Vec::with_capacity(4),
} }
} }
@@ -153,33 +143,24 @@ impl KitchensinkNode {
// Note: we do not pipe the logs of this process to a separate file since this is just a // Note: we do not pipe the logs of this process to a separate file since this is just a
// once-off export of the default chain spec and not part of the long-running node process. // once-off export of the default chain spec and not part of the long-running node process.
let output = if self.use_kitchensink_not_dev_node { let output = Command::new(&self.node_binary)
Command::new(&self.substrate_binary) .arg(self.export_chainspec_command.as_str())
.arg("export-chain-spec") .arg("--chain")
.arg("--chain") .arg("dev")
.arg("dev") .output()
.output() .context("Failed to export the chain-spec")?;
.context("Failed to export the chain-spec")?
} else {
Command::new(&self.dev_node_binary)
.arg("build-spec")
.arg("--chain")
.arg("dev")
.output()
.context("Failed to export the chain-spec")?
};
if !output.status.success() { if !output.status.success() {
anyhow::bail!( anyhow::bail!(
"substrate-node export-chain-spec failed: {}", "Substrate-node export-chain-spec failed: {}",
String::from_utf8_lossy(&output.stderr) String::from_utf8_lossy(&output.stderr)
); );
} }
let content = String::from_utf8(output.stdout) let content = String::from_utf8(output.stdout)
.context("Failed to decode substrate export-chain-spec output as UTF-8")?; .context("Failed to decode Substrate export-chain-spec output as UTF-8")?;
let mut chainspec_json: JsonValue = let mut chainspec_json: JsonValue =
serde_json::from_str(&content).context("Failed to parse substrate chain spec JSON")?; serde_json::from_str(&content).context("Failed to parse Substrate chain spec JSON")?;
let existing_chainspec_balances = let existing_chainspec_balances =
chainspec_json["genesis"]["runtimeGenesis"]["patch"]["balances"]["balances"] chainspec_json["genesis"]["runtimeGenesis"]["patch"]["balances"]["balances"]
@@ -250,17 +231,13 @@ impl KitchensinkNode {
// Start Substrate node // Start Substrate node
let kitchensink_stdout_logs_file = open_options let kitchensink_stdout_logs_file = open_options
.clone() .clone()
.open(self.kitchensink_stdout_log_file_path()) .open(self.substrate_stdout_log_file_path())
.context("Failed to open kitchensink stdout logs file")?; .context("Failed to open kitchensink stdout logs file")?;
let kitchensink_stderr_logs_file = open_options let kitchensink_stderr_logs_file = open_options
.clone() .clone()
.open(self.kitchensink_stderr_log_file_path()) .open(self.substrate_stderr_log_file_path())
.context("Failed to open kitchensink stderr logs file")?; .context("Failed to open kitchensink stderr logs file")?;
let node_binary_path = if self.use_kitchensink_not_dev_node { let node_binary_path = self.node_binary.as_path();
self.substrate_binary.as_path()
} else {
self.dev_node_binary.as_path()
};
self.process_substrate = Command::new(node_binary_path) self.process_substrate = Command::new(node_binary_path)
.arg("--dev") .arg("--dev")
.arg("--chain") .arg("--chain")
@@ -290,17 +267,17 @@ impl KitchensinkNode {
.context("Failed to clone kitchensink stderr log file handle")?, .context("Failed to clone kitchensink stderr log file handle")?,
) )
.spawn() .spawn()
.context("Failed to spawn substrate node process")? .context("Failed to spawn Substrate node process")?
.into(); .into();
// Give the node a moment to boot // Give the node a moment to boot
if let Err(error) = Self::wait_ready( if let Err(error) = Self::wait_ready(
self.kitchensink_stderr_log_file_path().as_path(), self.substrate_stderr_log_file_path().as_path(),
Self::SUBSTRATE_READY_MARKER, Self::SUBSTRATE_READY_MARKER,
Duration::from_secs(60), Duration::from_secs(60),
) { ) {
self.shutdown() self.shutdown()
.context("Failed to gracefully shutdown after substrate start error")?; .context("Failed to gracefully shutdown after Substrate start error")?;
return Err(error); return Err(error);
}; };
@@ -414,14 +391,14 @@ impl KitchensinkNode {
Ok(String::from_utf8_lossy(&output).trim().to_string()) Ok(String::from_utf8_lossy(&output).trim().to_string())
} }
fn kitchensink_stdout_log_file_path(&self) -> PathBuf { fn substrate_stdout_log_file_path(&self) -> PathBuf {
self.logs_directory self.logs_directory
.join(Self::KITCHENSINK_STDOUT_LOG_FILE_NAME) .join(Self::SUBSTRATE_STDOUT_LOG_FILE_NAME)
} }
fn kitchensink_stderr_log_file_path(&self) -> PathBuf { fn substrate_stderr_log_file_path(&self) -> PathBuf {
self.logs_directory self.logs_directory
.join(Self::KITCHENSINK_STDERR_LOG_FILE_NAME) .join(Self::SUBSTRATE_STDERR_LOG_FILE_NAME)
} }
fn proxy_stdout_log_file_path(&self) -> PathBuf { fn proxy_stdout_log_file_path(&self) -> PathBuf {
@@ -435,15 +412,11 @@ impl KitchensinkNode {
async fn provider( async fn provider(
&self, &self,
) -> anyhow::Result< ) -> anyhow::Result<
FillProvider< FillProvider<impl TxFiller<ReviveNetwork>, impl Provider<ReviveNetwork>, ReviveNetwork>,
impl TxFiller<KitchensinkNetwork>,
impl Provider<KitchensinkNetwork>,
KitchensinkNetwork,
>,
> { > {
ProviderBuilder::new() ProviderBuilder::new()
.disable_recommended_fillers() .disable_recommended_fillers()
.network::<KitchensinkNetwork>() .network::<ReviveNetwork>()
.filler(FallbackGasFiller::new( .filler(FallbackGasFiller::new(
25_000_000, 25_000_000,
1_000_000_000, 1_000_000_000,
@@ -458,7 +431,7 @@ impl KitchensinkNode {
} }
} }
impl EthereumNode for KitchensinkNode { impl EthereumNode for SubstrateNode {
fn execute_transaction( fn execute_transaction(
&self, &self,
transaction: alloy::rpc::types::TransactionRequest, transaction: alloy::rpc::types::TransactionRequest,
@@ -551,19 +524,18 @@ impl EthereumNode for KitchensinkNode {
Box::pin(async move { Box::pin(async move {
let id = self.id; let id = self.id;
let provider = self.provider().await?; let provider = self.provider().await?;
Ok(Box::new(KitchensinkNodeResolver { id, provider }) as Box<dyn ResolverApi>) Ok(Box::new(SubstrateNodeResolver { id, provider }) as Box<dyn ResolverApi>)
}) })
} }
} }
pub struct KitchensinkNodeResolver<F: TxFiller<KitchensinkNetwork>, P: Provider<KitchensinkNetwork>> pub struct SubstrateNodeResolver<F: TxFiller<ReviveNetwork>, P: Provider<ReviveNetwork>> {
{
id: u32, id: u32,
provider: FillProvider<F, P, KitchensinkNetwork>, provider: FillProvider<F, P, ReviveNetwork>,
} }
impl<F: TxFiller<KitchensinkNetwork>, P: Provider<KitchensinkNetwork>> ResolverApi impl<F: TxFiller<ReviveNetwork>, P: Provider<ReviveNetwork>> ResolverApi
for KitchensinkNodeResolver<F, P> for SubstrateNodeResolver<F, P>
{ {
#[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))]
fn chain_id( fn chain_id(
@@ -688,7 +660,7 @@ impl<F: TxFiller<KitchensinkNetwork>, P: Provider<KitchensinkNetwork>> ResolverA
} }
// TODO: Remove // TODO: Remove
impl ResolverApi for KitchensinkNode { impl ResolverApi for SubstrateNode {
fn chain_id( fn chain_id(
&self, &self,
) -> Pin<Box<dyn Future<Output = anyhow::Result<alloy::primitives::ChainId>> + '_>> { ) -> Pin<Box<dyn Future<Output = anyhow::Result<alloy::primitives::ChainId>> + '_>> {
@@ -830,7 +802,7 @@ impl ResolverApi for KitchensinkNode {
} }
} }
impl Node for KitchensinkNode { impl Node for SubstrateNode {
fn id(&self) -> usize { fn id(&self) -> usize {
self.id as _ self.id as _
} }
@@ -848,7 +820,7 @@ impl Node for KitchensinkNode {
} }
if let Some(mut child) = self.process_substrate.take() { if let Some(mut child) = self.process_substrate.take() {
child.kill().map_err(|error| { child.kill().map_err(|error| {
anyhow::anyhow!("Failed to kill the substrate process: {error:?}") anyhow::anyhow!("Failed to kill the Substrate process: {error:?}")
})?; })?;
} }
@@ -870,7 +842,7 @@ impl Node for KitchensinkNode {
} }
fn version(&self) -> anyhow::Result<String> { fn version(&self) -> anyhow::Result<String> {
let output = Command::new(&self.substrate_binary) let output = Command::new(&self.node_binary)
.arg("--version") .arg("--version")
.stdin(Stdio::null()) .stdin(Stdio::null())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
@@ -895,16 +867,16 @@ impl Node for KitchensinkNode {
} }
} }
impl Drop for KitchensinkNode { impl Drop for SubstrateNode {
fn drop(&mut self) { fn drop(&mut self) {
self.shutdown().expect("Failed to shutdown") self.shutdown().expect("Failed to shutdown")
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KitchensinkNetwork; pub struct ReviveNetwork;
impl Network for KitchensinkNetwork { impl Network for ReviveNetwork {
type TxType = <Ethereum as Network>::TxType; type TxType = <Ethereum as Network>::TxType;
type TxEnvelope = <Ethereum as Network>::TxEnvelope; type TxEnvelope = <Ethereum as Network>::TxEnvelope;
@@ -913,7 +885,7 @@ impl Network for KitchensinkNetwork {
type ReceiptEnvelope = <Ethereum as Network>::ReceiptEnvelope; type ReceiptEnvelope = <Ethereum as Network>::ReceiptEnvelope;
type Header = KitchensinkHeader; type Header = ReviveHeader;
type TransactionRequest = <Ethereum as Network>::TransactionRequest; type TransactionRequest = <Ethereum as Network>::TransactionRequest;
@@ -921,12 +893,12 @@ impl Network for KitchensinkNetwork {
type ReceiptResponse = <Ethereum as Network>::ReceiptResponse; type ReceiptResponse = <Ethereum as Network>::ReceiptResponse;
type HeaderResponse = Header<KitchensinkHeader>; type HeaderResponse = Header<ReviveHeader>;
type BlockResponse = Block<Transaction<TxEnvelope>, Header<KitchensinkHeader>>; type BlockResponse = Block<Transaction<TxEnvelope>, Header<ReviveHeader>>;
} }
impl TransactionBuilder<KitchensinkNetwork> for <Ethereum as Network>::TransactionRequest { impl TransactionBuilder<ReviveNetwork> for <Ethereum as Network>::TransactionRequest {
fn chain_id(&self) -> Option<alloy::primitives::ChainId> { fn chain_id(&self) -> Option<alloy::primitives::ChainId> {
<<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::chain_id(self) <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::chain_id(self)
} }
@@ -1058,7 +1030,7 @@ impl TransactionBuilder<KitchensinkNetwork> for <Ethereum as Network>::Transacti
fn complete_type( fn complete_type(
&self, &self,
ty: <KitchensinkNetwork as Network>::TxType, ty: <ReviveNetwork as Network>::TxType,
) -> Result<(), Vec<&'static str>> { ) -> Result<(), Vec<&'static str>> {
<<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::complete_type( <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::complete_type(
self, ty, self, ty,
@@ -1075,13 +1047,13 @@ impl TransactionBuilder<KitchensinkNetwork> for <Ethereum as Network>::Transacti
<<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::can_build(self) <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::can_build(self)
} }
fn output_tx_type(&self) -> <KitchensinkNetwork as Network>::TxType { fn output_tx_type(&self) -> <ReviveNetwork as Network>::TxType {
<<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::output_tx_type( <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::output_tx_type(
self, self,
) )
} }
fn output_tx_type_checked(&self) -> Option<<KitchensinkNetwork as Network>::TxType> { fn output_tx_type_checked(&self) -> Option<<ReviveNetwork as Network>::TxType> {
<<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::output_tx_type_checked( <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::output_tx_type_checked(
self, self,
) )
@@ -1095,15 +1067,14 @@ impl TransactionBuilder<KitchensinkNetwork> for <Ethereum as Network>::Transacti
fn build_unsigned( fn build_unsigned(
self, self,
) -> alloy::network::BuildResult<<KitchensinkNetwork as Network>::UnsignedTx, KitchensinkNetwork> ) -> alloy::network::BuildResult<<ReviveNetwork as Network>::UnsignedTx, ReviveNetwork> {
{
let result = <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::build_unsigned( let result = <<Ethereum as Network>::TransactionRequest as TransactionBuilder<Ethereum>>::build_unsigned(
self, self,
); );
match result { match result {
Ok(unsigned_tx) => Ok(unsigned_tx), Ok(unsigned_tx) => Ok(unsigned_tx),
Err(UnbuiltTransactionError { request, error }) => { Err(UnbuiltTransactionError { request, error }) => {
Err(UnbuiltTransactionError::<KitchensinkNetwork> { Err(UnbuiltTransactionError::<ReviveNetwork> {
request, request,
error: match error { error: match error {
TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => { TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => {
@@ -1124,20 +1095,18 @@ impl TransactionBuilder<KitchensinkNetwork> for <Ethereum as Network>::Transacti
} }
} }
async fn build<W: alloy::network::NetworkWallet<KitchensinkNetwork>>( async fn build<W: alloy::network::NetworkWallet<ReviveNetwork>>(
self, self,
wallet: &W, wallet: &W,
) -> Result< ) -> Result<<ReviveNetwork as Network>::TxEnvelope, TransactionBuilderError<ReviveNetwork>>
<KitchensinkNetwork as Network>::TxEnvelope, {
TransactionBuilderError<KitchensinkNetwork>,
> {
Ok(wallet.sign_request(self).await?) Ok(wallet.sign_request(self).await?)
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct KitchensinkHeader { pub struct ReviveHeader {
/// The Keccak 256-bit hash of the parent /// The Keccak 256-bit hash of the parent
/// blocks header, in its entirety; formally Hp. /// blocks header, in its entirety; formally Hp.
pub parent_hash: B256, pub parent_hash: B256,
@@ -1240,7 +1209,7 @@ pub struct KitchensinkHeader {
pub requests_hash: Option<B256>, pub requests_hash: Option<B256>,
} }
impl BlockHeader for KitchensinkHeader { impl BlockHeader for ReviveHeader {
fn parent_hash(&self) -> B256 { fn parent_hash(&self) -> B256 {
self.parent_hash self.parent_hash
} }
@@ -1344,7 +1313,7 @@ mod tests {
context context
} }
fn new_node() -> (ExecutionContext, KitchensinkNode) { fn new_node() -> (ExecutionContext, SubstrateNode) {
// Note: When we run the tests in the CI we found that if they're all // Note: When we run the tests in the CI we found that if they're all
// run in parallel then the CI is unable to start all of the nodes in // run in parallel then the CI is unable to start all of the nodes in
// time and their start up times-out. Therefore, we want all of the // time and their start up times-out. Therefore, we want all of the
@@ -1364,7 +1333,11 @@ mod tests {
let _guard = NODE_START_MUTEX.lock().unwrap(); let _guard = NODE_START_MUTEX.lock().unwrap();
let context = test_config(); let context = test_config();
let mut node = KitchensinkNode::new(&context); let mut node = SubstrateNode::new(
context.kitchensink_configuration.path.clone(),
SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND,
&context,
);
node.init(context.genesis_configuration.genesis().unwrap().clone()) node.init(context.genesis_configuration.genesis().unwrap().clone())
.expect("Failed to initialize the node") .expect("Failed to initialize the node")
.spawn_process() .spawn_process()
@@ -1373,8 +1346,8 @@ mod tests {
} }
/// A shared node that multiple tests can use. It starts up once. /// A shared node that multiple tests can use. It starts up once.
fn shared_node() -> &'static KitchensinkNode { fn shared_node() -> &'static SubstrateNode {
static NODE: LazyLock<(ExecutionContext, KitchensinkNode)> = LazyLock::new(|| { static NODE: LazyLock<(ExecutionContext, SubstrateNode)> = LazyLock::new(|| {
let (context, node) = new_node(); let (context, node) = new_node();
(context, node) (context, node)
}); });
@@ -1423,7 +1396,12 @@ mod tests {
} }
"#; "#;
let mut dummy_node = KitchensinkNode::new(&test_config()); let context = test_config();
let mut dummy_node = SubstrateNode::new(
context.kitchensink_configuration.path.clone(),
SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND,
&context,
);
// Call `init()` // Call `init()`
dummy_node dummy_node
@@ -1433,16 +1411,16 @@ mod tests {
// Check that the patched chainspec file was generated // Check that the patched chainspec file was generated
let final_chainspec_path = dummy_node let final_chainspec_path = dummy_node
.base_directory .base_directory
.join(KitchensinkNode::CHAIN_SPEC_JSON_FILE); .join(SubstrateNode::CHAIN_SPEC_JSON_FILE);
assert!(final_chainspec_path.exists(), "Chainspec file should exist"); assert!(final_chainspec_path.exists(), "Chainspec file should exist");
let contents = fs::read_to_string(&final_chainspec_path).expect("Failed to read chainspec"); let contents = fs::read_to_string(&final_chainspec_path).expect("Failed to read chainspec");
// Validate that the Substrate addresses derived from the Ethereum addresses are in the file // Validate that the Substrate addresses derived from the Ethereum addresses are in the file
let first_eth_addr = KitchensinkNode::eth_to_substrate_address( let first_eth_addr = SubstrateNode::eth_to_substrate_address(
&"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap(), &"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap(),
); );
let second_eth_addr = KitchensinkNode::eth_to_substrate_address( let second_eth_addr = SubstrateNode::eth_to_substrate_address(
&"Ab8483F64d9C6d1EcF9b849Ae677dD3315835cb2".parse().unwrap(), &"Ab8483F64d9C6d1EcF9b849Ae677dD3315835cb2".parse().unwrap(),
); );
@@ -1469,7 +1447,12 @@ mod tests {
} }
"#; "#;
let node = KitchensinkNode::new(&test_config()); let context = test_config();
let node = SubstrateNode::new(
context.kitchensink_configuration.path.clone(),
SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND,
&context,
);
let result = node let result = node
.extract_balance_from_genesis_file(&serde_json::from_str(genesis_json).unwrap()) .extract_balance_from_genesis_file(&serde_json::from_str(genesis_json).unwrap())
@@ -1502,7 +1485,7 @@ mod tests {
]; ];
for eth_addr in eth_addresses { for eth_addr in eth_addresses {
let ss58 = KitchensinkNode::eth_to_substrate_address(&eth_addr.parse().unwrap()); let ss58 = SubstrateNode::eth_to_substrate_address(&eth_addr.parse().unwrap());
println!("Ethereum: {eth_addr} -> Substrate SS58: {ss58}"); println!("Ethereum: {eth_addr} -> Substrate SS58: {ss58}");
} }
@@ -1530,7 +1513,7 @@ mod tests {
]; ];
for (eth_addr, expected_ss58) in cases { for (eth_addr, expected_ss58) in cases {
let result = KitchensinkNode::eth_to_substrate_address(&eth_addr.parse().unwrap()); let result = SubstrateNode::eth_to_substrate_address(&eth_addr.parse().unwrap());
assert_eq!( assert_eq!(
result, expected_ss58, result, expected_ss58,
"Mismatch for Ethereum address {eth_addr}" "Mismatch for Ethereum address {eth_addr}"
@@ -1545,8 +1528,8 @@ mod tests {
let version = node.version().unwrap(); let version = node.version().unwrap();
assert!( assert!(
version.starts_with("substrate-node"), version.starts_with("Substrate-node"),
"Expected substrate-node version string, got: {version}" "Expected Substrate-node version string, got: {version}"
); );
} }