Bläddra i källkod

fix(fortuna): Eip1559 fixes (#1597)

* fix(fortuna): Change order of middlewares to avoid calling gas oracle if legacy tx

* Auto detect EIP 1559

* Fault tolerant start of api and keeper

* Bump
Amin Moghaddam 1 år sedan
förälder
incheckning
1e25f3fbff

+ 1 - 1
apps/fortuna/Cargo.lock

@@ -1488,7 +1488,7 @@ dependencies = [
 
 [[package]]
 name = "fortuna"
-version = "5.4.0"
+version = "5.4.1"
 dependencies = [
  "anyhow",
  "axum",

+ 1 - 1
apps/fortuna/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name    = "fortuna"
-version = "5.4.0"
+version = "5.4.1"
 edition = "2021"
 
 [dependencies]

+ 15 - 11
apps/fortuna/src/chain/ethereum.rs

@@ -67,12 +67,12 @@ abigen!(
 );
 
 pub type SignablePythContract = PythRandom<
-    GasOracleMiddleware<
-        TransformerMiddleware<
+    TransformerMiddleware<
+        GasOracleMiddleware<
             NonceManagerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>>,
-            LegacyTxTransformer,
+            EthProviderOracle<Provider<Http>>,
         >,
-        EthProviderOracle<Provider<Http>>,
+        LegacyTxTransformer,
     >,
 >;
 pub type PythContract = PythRandom<Provider<Http>>;
@@ -102,11 +102,15 @@ impl SignablePythContract {
     ) -> Result<SignablePythContract> {
         let provider = Provider::<Http>::try_from(&chain_config.geth_rpc_addr)?;
         let chain_id = provider.get_chainid().await?;
-
+        let eip1559_supported = provider
+            .get_block(ethers::prelude::BlockNumber::Latest)
+            .await?
+            .ok_or_else(|| anyhow!("Latest block not found"))?
+            .base_fee_per_gas
+            .is_some();
         let gas_oracle = EthProviderOracle::new(provider.clone());
-
         let transformer = LegacyTxTransformer {
-            use_legacy_tx: chain_config.legacy_tx,
+            use_legacy_tx: !eip1559_supported,
         };
 
         let wallet__ = private_key
@@ -117,12 +121,12 @@ impl SignablePythContract {
 
         Ok(PythRandom::new(
             chain_config.contract_addr,
-            Arc::new(GasOracleMiddleware::new(
-                TransformerMiddleware::new(
+            Arc::new(TransformerMiddleware::new(
+                GasOracleMiddleware::new(
                     NonceManagerMiddleware::new(SignerMiddleware::new(provider, wallet__), address),
-                    transformer,
+                    gas_oracle,
                 ),
-                gas_oracle,
+                transformer,
             )),
         ))
     }

+ 86 - 65
apps/fortuna/src/command/run.rs

@@ -10,6 +10,7 @@ use {
         config::{
             Commitment,
             Config,
+            EthereumConfig,
             ProviderConfig,
             RunOptions,
         },
@@ -149,77 +150,23 @@ pub async fn run_keeper(
 
 pub async fn run(opts: &RunOptions) -> Result<()> {
     let config = Config::load(&opts.config.config)?;
-    let provider_config = ProviderConfig::load(&opts.provider_config.provider_config)?;
     let secret = opts.randomness.load_secret()?;
     let (tx_exit, rx_exit) = watch::channel(false);
 
     let mut chains: HashMap<ChainId, BlockchainState> = HashMap::new();
     for (chain_id, chain_config) in &config.chains {
-        let contract = Arc::new(PythContract::from_config(&chain_config)?);
-        let provider_chain_config = provider_config.get_chain_config(chain_id)?;
-        let mut provider_commitments = provider_chain_config.get_sorted_commitments();
-        let provider_info = contract.get_provider_info(opts.provider).call().await?;
-        let latest_metadata =
-            bincode::deserialize::<CommitmentMetadata>(&provider_info.commitment_metadata)
-                .map_err(|e| {
-                    anyhow!(
-                        "Chain: {} - Failed to deserialize commitment metadata: {}",
-                        &chain_id,
-                        e
-                    )
-                })?;
-
-        provider_commitments.push(Commitment {
-            seed:                                latest_metadata.seed,
-            chain_length:                        latest_metadata.chain_length,
-            original_commitment_sequence_number: provider_info.original_commitment_sequence_number,
-        });
-
-        // TODO: we may want to load the hash chain in a lazy/fault-tolerant way. If there are many blockchains,
-        // then it's more likely that some RPC fails. We should tolerate these faults and generate the hash chain
-        // later when a user request comes in for that chain.
-
-        let mut offsets = Vec::<usize>::new();
-        let mut hash_chains = Vec::<PebbleHashChain>::new();
-
-        for commitment in &provider_commitments {
-            let offset = commitment.original_commitment_sequence_number.try_into()?;
-            offsets.push(offset);
-
-            let pebble_hash_chain = PebbleHashChain::from_config(
-                &secret,
-                &chain_id,
-                &opts.provider,
-                &chain_config.contract_addr,
-                &commitment.seed,
-                commitment.chain_length,
-            )?;
-            hash_chains.push(pebble_hash_chain);
-        }
-
-        let chain_state = HashChainState {
-            offsets,
-            hash_chains,
-        };
-
-        if chain_state.reveal(provider_info.original_commitment_sequence_number)?
-            != provider_info.original_commitment
-        {
-            return Err(anyhow!("The root of the generated hash chain for chain id {} does not match the commitment. Are the secret and chain length configured correctly?", &chain_id).into());
-        } else {
-            tracing::info!("Root of chain id {} matches commitment", &chain_id);
+        let state = setup_chain_state(&opts, &secret, chain_id, chain_config).await;
+        match state {
+            Ok(state) => {
+                chains.insert(chain_id.clone(), state);
+            }
+            Err(e) => {
+                tracing::error!("Failed to setup {} {}", chain_id, e);
+            }
         }
-
-        let state = api::BlockchainState {
-            id: chain_id.clone(),
-            state: Arc::new(chain_state),
-            contract,
-            provider_address: opts.provider,
-            reveal_delay_blocks: chain_config.reveal_delay_blocks,
-            confirmed_block_status: chain_config.confirmed_block_status,
-        };
-
-        chains.insert(chain_id.clone(), state);
+    }
+    if chains.is_empty() {
+        return Err(anyhow!("No chains were successfully setup"));
     }
 
 
@@ -254,6 +201,80 @@ pub async fn run(opts: &RunOptions) -> Result<()> {
     Ok(())
 }
 
+async fn setup_chain_state(
+    opts: &&RunOptions,
+    secret: &String,
+    chain_id: &ChainId,
+    chain_config: &EthereumConfig,
+) -> Result<BlockchainState> {
+    let provider_config = ProviderConfig::load(&opts.provider_config.provider_config)?;
+    let contract = Arc::new(PythContract::from_config(&chain_config)?);
+    let provider_chain_config = provider_config.get_chain_config(chain_id)?;
+    let mut provider_commitments = provider_chain_config.get_sorted_commitments();
+    let provider_info = contract.get_provider_info(opts.provider).call().await?;
+    let latest_metadata = bincode::deserialize::<CommitmentMetadata>(
+        &provider_info.commitment_metadata,
+    )
+    .map_err(|e| {
+        anyhow!(
+            "Chain: {} - Failed to deserialize commitment metadata: {}",
+            &chain_id,
+            e
+        )
+    })?;
+
+    provider_commitments.push(Commitment {
+        seed:                                latest_metadata.seed,
+        chain_length:                        latest_metadata.chain_length,
+        original_commitment_sequence_number: provider_info.original_commitment_sequence_number,
+    });
+
+    // TODO: we may want to load the hash chain in a lazy/fault-tolerant way. If there are many blockchains,
+    // then it's more likely that some RPC fails. We should tolerate these faults and generate the hash chain
+    // later when a user request comes in for that chain.
+
+    let mut offsets = Vec::<usize>::new();
+    let mut hash_chains = Vec::<PebbleHashChain>::new();
+
+    for commitment in &provider_commitments {
+        let offset = commitment.original_commitment_sequence_number.try_into()?;
+        offsets.push(offset);
+
+        let pebble_hash_chain = PebbleHashChain::from_config(
+            &secret,
+            &chain_id,
+            &opts.provider,
+            &chain_config.contract_addr,
+            &commitment.seed,
+            commitment.chain_length,
+        )?;
+        hash_chains.push(pebble_hash_chain);
+    }
+
+    let chain_state = HashChainState {
+        offsets,
+        hash_chains,
+    };
+
+    if chain_state.reveal(provider_info.original_commitment_sequence_number)?
+        != provider_info.original_commitment
+    {
+        return Err(anyhow!("The root of the generated hash chain for chain id {} does not match the commitment. Are the secret and chain length configured correctly?", &chain_id).into());
+    } else {
+        tracing::info!("Root of chain id {} matches commitment", &chain_id);
+    }
+
+    let state = BlockchainState {
+        id: chain_id.clone(),
+        state: Arc::new(chain_state),
+        contract,
+        provider_address: opts.provider,
+        reveal_delay_blocks: chain_config.reveal_delay_blocks,
+        confirmed_block_status: chain_config.confirmed_block_status,
+    };
+    Ok(state)
+}
+
 
 #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
 pub struct ChainLabel {

+ 0 - 4
apps/fortuna/src/config.rs

@@ -148,10 +148,6 @@ pub struct EthereumConfig {
     /// its commitment.
     pub reveal_delay_blocks: BlockNumber,
 
-    /// Use the legacy transaction format (for networks without EIP 1559)
-    #[serde(default)]
-    pub legacy_tx: bool,
-
     /// The BlockStatus of the block that is considered confirmed.
     /// For example, Finalized, Safe, Latest
     #[serde(default)]