[fortuna] script to setup a provider for all chains (#1229)

* auto register script

* renaming

* add comments

* update abi file path

* pre commit

* pre commit

* resolved some

* better comment

* resolve comments

* fix bug

* pre commit

* fix

* update version
This commit is contained in:
Dev Kalra 2024-01-23 01:53:19 +05:30 committed by GitHub
parent 7529b053e3
commit ab10b9f5fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 180 additions and 1029 deletions

1
fortuna/.gitignore vendored
View File

@ -1,3 +1,4 @@
/target
config.yaml
*secret*
*private-key*

2
fortuna/Cargo.lock generated
View File

@ -1486,7 +1486,7 @@ dependencies = [
[[package]]
name = "fortuna"
version = "3.2.0"
version = "3.2.1"
dependencies = [
"anyhow",
"axum",

View File

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

View File

@ -9,6 +9,7 @@ RUN rustup default nightly-2023-07-23
WORKDIR /src
COPY fortuna fortuna
COPY pythnet pythnet
COPY target_chains/ethereum/entropy_sdk/solidity/abis target_chains/ethereum/entropy_sdk/solidity/abis
WORKDIR /src/fortuna

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,10 @@ use {
// TODO: Programmatically generate this so we don't have to keep committed ABI in sync with the
// contract in the same repo.
abigen!(PythRandom, "src/abi.json");
abigen!(
PythRandom,
"../target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json"
);
pub type SignablePythContract = PythRandom<
TransformerMiddleware<SignerMiddleware<Provider<Http>, LocalWallet>, LegacyTxTransformer>,

View File

@ -3,6 +3,7 @@ mod get_request;
mod register_provider;
mod request_randomness;
mod run;
mod setup_provider;
pub use {
generate::generate,
@ -10,4 +11,5 @@ pub use {
register_provider::register_provider,
request_randomness::request_randomness,
run::run,
setup_provider::setup_provider,
};

View File

@ -8,12 +8,9 @@ use {
state::PebbleHashChain,
},
anyhow::Result,
ethers::{
signers::{
LocalWallet,
Signer,
},
types::Address,
ethers::signers::{
LocalWallet,
Signer,
},
std::sync::Arc,
};

View File

@ -0,0 +1,117 @@
use {
crate::{
chain::ethereum::SignablePythContract,
command::{
register_provider,
register_provider::CommitmentMetadata,
},
config::{
Config,
RegisterProviderOptions,
SetupProviderOptions,
},
state::{
HashChainState,
PebbleHashChain,
},
},
anyhow::Result,
ethers::signers::{
LocalWallet,
Signer,
},
std::sync::Arc,
};
/// Setup provider for all the chains.
/// 1. Register if there was no previous registration.
/// 2. Re-register if there are no more random numbers to request on the contract.
/// 3. Re-register if there is a mismatch in generated hash chain.
/// 4. Update provider fee if there is a mismatch with the fee set on contract.
/// 5. Update provider uri if there is a mismatch with the uri set on contract.
pub async fn setup_provider(opts: &SetupProviderOptions) -> Result<()> {
let config = Config::load(&opts.config.config)?;
let private_key = opts.load_private_key()?;
let secret = opts.randomness.load_secret()?;
let provider_address = private_key.clone().parse::<LocalWallet>()?.address();
for (chain_id, chain_config) in &config.chains {
// Initialize a Provider to interface with the EVM contract.
let contract =
Arc::new(SignablePythContract::from_config(&chain_config, &private_key).await?);
let provider_info = contract.get_provider_info(provider_address).call().await?;
tracing::info!("Provider info: {:?}", provider_info);
let mut register = false;
// This condition satisfies for both when there is no registration and when there are no
// more random numbers left to request
if provider_info.end_sequence_number <= provider_info.sequence_number {
tracing::info!(
"endSequenceNumber <= sequenceNumber. endSequenceNumber={0}, sequenceNumber={1}",
provider_info.end_sequence_number,
provider_info.sequence_number
);
tracing::info!("Registering to {}", &chain_id);
register = true;
} else {
let metadata =
bincode::deserialize::<CommitmentMetadata>(&provider_info.commitment_metadata)?;
let hash_chain = PebbleHashChain::from_config(
&secret,
&chain_id,
&provider_address,
&chain_config.contract_addr,
&metadata.seed,
metadata.chain_length,
)?;
let chain_state = HashChainState {
offsets: vec![provider_info
.original_commitment_sequence_number
.try_into()?],
hash_chains: vec![hash_chain],
};
if chain_state.reveal(provider_info.original_commitment_sequence_number)?
!= provider_info.original_commitment
{
tracing::info!("The root of the generated hash chain for chain id {} does not match the commitment", &chain_id);
tracing::info!("Registering to {}", &chain_id);
register = true;
}
}
if register {
register_provider(&RegisterProviderOptions {
config: opts.config.clone(),
chain_id: chain_id.clone(),
private_key: private_key.clone(),
randomness: opts.randomness.clone(),
fee: opts.fee,
uri: opts.uri.clone(),
})
.await?;
} else {
if provider_info.fee_in_wei != opts.fee {
if let Some(r) = contract.set_provider_fee(opts.fee).send().await?.await? {
tracing::info!("Updated provider fee: {:?}", r);
}
}
if bincode::deserialize::<String>(&provider_info.uri)? != opts.uri {
if let Some(receipt) = contract
.set_provider_uri(bincode::serialize(&opts.uri)?.into())
.send()
.await?
.log_msg("Pending transfer hash")
.await?
{
tracing::info!("Updated provider uri: {:?}", receipt);
}
}
}
}
Ok(())
}

View File

@ -27,6 +27,7 @@ pub use {
register_provider::RegisterProviderOptions,
request_randomness::RequestRandomnessOptions,
run::RunOptions,
setup_provider::SetupProviderOptions,
};
mod generate;
@ -34,6 +35,7 @@ mod get_request;
mod register_provider;
mod request_randomness;
mod run;
mod setup_provider;
const DEFAULT_RPC_ADDR: &str = "127.0.0.1:34000";
const DEFAULT_HTTP_ADDR: &str = "http://127.0.0.1:34000";
@ -51,6 +53,10 @@ pub enum Options {
/// Register a new provider with the Pyth Random oracle.
RegisterProvider(RegisterProviderOptions),
/// Set up the provider for all the provided chains.
/// It registers, re-registers, or updates provider config on chain.
SetupProvider(SetupProviderOptions),
/// Request a random number from the contract.
RequestRandomness(RequestRandomnessOptions),

View File

@ -0,0 +1,43 @@
use {
crate::config::{
ConfigOptions,
RandomnessOptions,
},
anyhow::Result,
clap::Args,
std::fs,
};
#[derive(Args, Clone, Debug)]
#[command(next_help_heading = "Setup Provider Options")]
#[group(id = "SetupProviderOptions")]
pub struct SetupProviderOptions {
#[command(flatten)]
pub config: ConfigOptions,
/// Path to a file containing a 20-byte (40 char) hex encoded Ethereum private key.
/// This key is required to submit transactions (such as registering with the contract).
#[arg(long = "private-key")]
#[arg(env = "PRIVATE_KEY")]
pub private_key_file: String,
#[command(flatten)]
pub randomness: RandomnessOptions,
/// The fee to charge (in wei) for each requested random number
#[arg(long = "pyth-contract-fee")]
#[arg(default_value = "100")]
pub fee: u128,
/// The URI where clients can retrieve random values from this provider,
/// i.e., wherever fortuna for this provider will be hosted.
#[arg(long = "uri")]
#[arg(default_value = "")]
pub uri: String,
}
impl SetupProviderOptions {
pub fn load_private_key(&self) -> Result<String> {
return Ok((fs::read_to_string(&self.private_key_file))?);
}
}

View File

@ -39,6 +39,7 @@ async fn main() -> Result<()> {
config::Options::Generate(opts) => command::generate(&opts).await,
config::Options::Run(opts) => command::run(&opts).await,
config::Options::RegisterProvider(opts) => command::register_provider(&opts).await,
config::Options::SetupProvider(opts) => command::setup_provider(&opts).await,
config::Options::RequestRandomness(opts) => command::request_randomness(&opts).await,
}
}