Skip to main content

signet_test_utils/specs/
ru_spec.rs

1use super::{sign_tx_with_key_pair, simple_send};
2#[cfg(doc)]
3use crate::specs::HostBlockSpec;
4use alloy::{
5    consensus::{BlobTransactionSidecar, SidecarBuilder, SimpleCoder, TxEnvelope},
6    eips::eip2718::Encodable2718,
7    primitives::{keccak256, Address, Bytes, B256, U256},
8    rlp::Encodable,
9    signers::local::PrivateKeySigner,
10};
11use signet_constants::test_utils::*;
12use signet_extract::{Extractable, Extracts};
13use signet_types::constants::{KnownChains, ParseChainError, SignetSystemConstants};
14use signet_zenith::Zenith::{self};
15use std::str::FromStr;
16
17/// A block spec for the Ru chain.
18///
19/// Typically this should be used as follows:
20/// 1. Instantiate with a [`SignetSystemConstants`] object via [`Self::new`].
21/// 2. Add transactions to the block with [`Self::add_tx`].
22/// 3. Optionally set the gas limit with [`Self::with_gas_limit`].
23/// 4. Optionally set the reward address with [`Self::with_reward_address`].
24/// 5. Add to a [`HostBlockSpec`] via `HostBlockSpec::add_ru_block`.
25#[derive(Debug, Clone)]
26pub struct RuBlockSpec {
27    /// The system constants for the block.
28    pub constants: SignetSystemConstants,
29    /// The transactions in the block.
30    pub tx: Vec<Vec<u8>>,
31    /// The gas limit for the block.
32    pub gas_limit: Option<u64>,
33    /// The reward address for the block.
34    pub reward_address: Option<Address>,
35}
36
37impl RuBlockSpec {
38    /// Create a new empty RU block spec.
39    pub const fn new(constants: SignetSystemConstants) -> Self {
40        Self { constants, tx: vec![], gas_limit: None, reward_address: None }
41    }
42
43    /// Create a new empty RU block spec with the Mainnet constants.
44    pub const fn mainnet() -> Self {
45        Self::new(SignetSystemConstants::mainnet())
46    }
47
48    /// Create a new empty RU block spec with the Parmigiana constants.
49    pub const fn parmigiana() -> Self {
50        Self::new(SignetSystemConstants::parmigiana())
51    }
52
53    /// Create a new empty RU block spec with the Gouda constants.
54    pub const fn gouda() -> Self {
55        Self::new(SignetSystemConstants::gouda())
56    }
57
58    /// Create a new empty RU block spec with the Pecorino constants.
59    #[deprecated(note = "Pecorino is being deprecated in favor of Parmigiana")]
60    #[allow(deprecated)]
61    pub const fn pecorino() -> Self {
62        Self::new(SignetSystemConstants::pecorino())
63    }
64
65    /// Create a new empty RU block spec with the test constants.
66    pub const fn test() -> Self {
67        Self::new(SignetSystemConstants::test())
68    }
69
70    /// Builder method to set the gas limit.
71    pub const fn with_gas_limit(mut self, gas_limit: u64) -> Self {
72        self.gas_limit = Some(gas_limit);
73        self
74    }
75
76    /// Builder method to set the reward address.
77    pub const fn with_reward_address(mut self, reward_address: Address) -> Self {
78        self.reward_address = Some(reward_address);
79        self
80    }
81
82    /// Add a transaction to the block.
83    pub fn add_tx(&mut self, tx: &TxEnvelope) {
84        self.tx.push(tx.encoded_2718());
85    }
86
87    /// Add an alloy transaction to the block
88    pub fn add_alloy_tx(&mut self, tx: &TxEnvelope) {
89        self.tx.push(tx.encoded_2718());
90    }
91
92    /// Add an invalid transaction to the block.
93    pub fn add_invalid_tx(&mut self, tx: impl Into<Bytes>) {
94        self.tx.push(tx.into().into());
95    }
96
97    /// Add a transaction to the block, returning self.
98    pub fn tx(mut self, tx: &TxEnvelope) -> Self {
99        self.add_tx(tx);
100        self
101    }
102
103    /// Add an alloy transaction to the block, returning self.
104    pub fn alloy_tx(mut self, tx: &TxEnvelope) -> Self {
105        self.add_alloy_tx(tx);
106        self
107    }
108
109    /// Add a simple send to the block, returns the send added.
110    pub fn add_simple_send(
111        &mut self,
112        wallet: &PrivateKeySigner,
113        to: Address,
114        amount: U256,
115        nonce: u64,
116    ) -> TxEnvelope {
117        let tx = sign_tx_with_key_pair(
118            wallet,
119            simple_send(to, amount, nonce, self.constants.ru_chain_id()),
120        );
121        self.add_tx(&tx);
122        tx
123    }
124
125    /// Convert to a host sidecar.
126    pub fn to_sidecar(&self) -> (B256, BlobTransactionSidecar) {
127        let mut buf = vec![];
128        Vec::<Vec<u8>>::encode(&self.tx, &mut buf);
129
130        let sidecar = SidecarBuilder::<SimpleCoder>::from_slice(&buf).build().unwrap();
131        (keccak256(&buf), sidecar)
132    }
133
134    /// Convert to a block submitted, along with the sidecar.
135    pub fn to_block_submitted(&self) -> (Zenith::BlockSubmitted, BlobTransactionSidecar) {
136        let (bdh, sidecar) = self.to_sidecar();
137
138        let block_submitted = Zenith::BlockSubmitted {
139            sequencer: Address::repeat_byte(3),
140            rollupChainId: U256::from(self.constants.ru_chain_id()),
141            gasLimit: U256::from(self.gas_limit.unwrap_or(100_000_000)),
142            rewardAddress: self.reward_address.unwrap_or(DEFAULT_REWARD_ADDRESS),
143            blockDataHash: bdh,
144        };
145
146        (block_submitted, sidecar)
147    }
148
149    /// Assert that extracted data conforms to the block spec.
150    pub fn assert_conforms<C: Extractable>(&self, extracts: &Extracts<'_, C>) {
151        let submitted = extracts.submitted.as_ref().unwrap();
152
153        if let Some(gas_limit) = self.gas_limit {
154            assert_eq!(submitted.gas_limit(), gas_limit)
155        }
156
157        if let Some(reward_address) = self.reward_address {
158            assert_eq!(submitted.reward_address(), reward_address)
159        }
160    }
161}
162
163impl TryFrom<KnownChains> for RuBlockSpec {
164    type Error = ParseChainError;
165
166    fn try_from(chain: KnownChains) -> Result<Self, Self::Error> {
167        match chain {
168            KnownChains::Mainnet => Ok(Self::mainnet()),
169            KnownChains::Parmigiana => Ok(Self::parmigiana()),
170            KnownChains::Gouda => Ok(Self::gouda()),
171            #[allow(deprecated)]
172            KnownChains::Pecorino => Ok(Self::pecorino()),
173            KnownChains::Test => Ok(Self::test()),
174        }
175    }
176}
177
178impl FromStr for RuBlockSpec {
179    type Err = ParseChainError;
180
181    fn from_str(s: &str) -> Result<Self, Self::Err> {
182        s.parse::<KnownChains>()?.try_into()
183    }
184}