Skip to content

Commit

Permalink
fix(fortuna): Eip1559 fixes (#1597)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
m30m authored May 23, 2024
1 parent 6782770 commit 1e25f3f
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 82 deletions.
2 changes: 1 addition & 1 deletion apps/fortuna/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/fortuna/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fortuna"
version = "5.4.0"
version = "5.4.1"
edition = "2021"

[dependencies]
Expand Down
26 changes: 15 additions & 11 deletions apps/fortuna/src/chain/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>;
Expand Down Expand Up @@ -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
Expand All @@ -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,
)),
))
}
Expand Down
151 changes: 86 additions & 65 deletions apps/fortuna/src/command/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use {
config::{
Commitment,
Config,
EthereumConfig,
ProviderConfig,
RunOptions,
},
Expand Down Expand Up @@ -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"));
}


Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 0 additions & 4 deletions apps/fortuna/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down

0 comments on commit 1e25f3f

Please sign in to comment.