Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions apps/argus/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use {
crate::{
chain::reader::{BlockNumber, BlockStatus, EntropyReader},
state::HashChainState,
},
anyhow::Result,
axum::{
Expand Down Expand Up @@ -78,8 +77,6 @@ impl ApiState {
pub struct BlockchainState {
/// The chain id for this blockchain, useful for logging
pub id: ChainId,
/// The hash chain(s) required to serve random numbers for this blockchain
pub state: Arc<HashChainState>,
/// The contract that the server is fulfilling requests for.
pub contract: Arc<dyn EntropyReader>,
/// The address of the provider that this server is operating for.
Expand Down
22 changes: 3 additions & 19 deletions apps/argus/src/command/register_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ use {
api::{get_register_uri, ChainId},
chain::ethereum::SignablePythContract,
config::{Config, EthereumConfig, ProviderConfig, RegisterProviderOptions},
state::PebbleHashChain,
},
anyhow::{anyhow, Result},
ethers::{
abi::Bytes,
signers::{LocalWallet, Signer},
types::U256,
},
std::sync::Arc,
Expand Down Expand Up @@ -45,27 +43,13 @@ pub async fn register_provider_from_config(
Arc::new(SignablePythContract::from_config(chain_config, &private_key_string).await?);
// Create a new random hash chain.
let random = rand::random::<[u8; 32]>();
let secret = provider_config
.secret
.load()?
.ok_or(anyhow!("Please specify a provider secret in the config"))?;

let commitment_length = provider_config.chain_length;
tracing::info!("Generating hash chain");
let chain = PebbleHashChain::from_config(
&secret,
chain_id,
&private_key_string.parse::<LocalWallet>()?.address(),
&chain_config.contract_addr,
&random,
commitment_length,
provider_config.chain_sample_interval,
)?;
tracing::info!("Done generating hash chain");
// FIXME: delete this
let commitment_length = 1000;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this stuff will all get deleted later so I think it's fine to mock them out for now.


// Arguments to the contract to register our new provider.
let fee_in_wei = chain_config.fee;
let commitment = chain.reveal_ith(0)?;
let commitment = [0; 32];
// Store the random seed and chain length in the metadata field so that we can regenerate the hash
// chain at-will. (This is secure because you can't generate the chain unless you also have the secret)
let commitment_metadata = CommitmentMetadata {
Expand Down
83 changes: 1 addition & 82 deletions apps/argus/src/command/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ use {
crate::{
api::{self, BlockchainState, ChainId},
chain::ethereum::InstrumentedPythContract,
command::register_provider::CommitmentMetadata,
config::{Commitment, Config, EthereumConfig, RunOptions},
config::{Config, EthereumConfig, RunOptions},
keeper::{self, keeper_metrics::KeeperMetrics},
state::{HashChainState, PebbleHashChain},
},
fortuna::eth_utils::traced_client::{RpcMetrics, TracedClient},
anyhow::{anyhow, Error, Result},
Expand Down Expand Up @@ -107,22 +105,16 @@ pub async fn run_keeper(

pub async fn run(opts: &RunOptions) -> Result<()> {
let config = Config::load(&opts.config.config)?;
let secret = config.provider.secret.load()?.ok_or(anyhow!(
"Please specify a provider secret in the config file."
))?;
let (tx_exit, rx_exit) = watch::channel(false);
let metrics_registry = Arc::new(RwLock::new(Registry::default()));
let rpc_metrics = Arc::new(RpcMetrics::new(metrics_registry.clone()).await);

let mut tasks = Vec::new();
for (chain_id, chain_config) in config.chains.clone() {
let secret_copy = secret.clone();
let rpc_metrics = rpc_metrics.clone();
tasks.push(spawn(async move {
let state = setup_chain_state(
&config.provider.address,
&secret_copy,
config.provider.chain_sample_interval,
&chain_id,
&chain_config,
rpc_metrics,
Expand Down Expand Up @@ -189,8 +181,6 @@ pub async fn run(opts: &RunOptions) -> Result<()> {

async fn setup_chain_state(
provider: &Address,
secret: &str,
chain_sample_interval: u64,
chain_id: &ChainId,
chain_config: &EthereumConfig,
rpc_metrics: Arc<RpcMetrics>,
Expand All @@ -200,80 +190,9 @@ async fn setup_chain_state(
chain_id.clone(),
rpc_metrics,
)?);
let mut provider_commitments = chain_config.commitments.clone().unwrap_or_default();
provider_commitments.sort_by(|c1, c2| {
c1.original_commitment_sequence_number
.cmp(&c2.original_commitment_sequence_number)
});

let provider_info = contract.get_provider_info(*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
)
})?;

let last_prior_commitment = provider_commitments.last();
if last_prior_commitment.is_some()
&& last_prior_commitment
.unwrap()
.original_commitment_sequence_number
>= provider_info.original_commitment_sequence_number
{
return Err(anyhow!("The current hash chain for chain id {} has configured commitments for sequence numbers greater than the current on-chain sequence number. Are the commitments configured correctly?", &chain_id));
}

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,
provider,
&chain_config.contract_addr,
&commitment.seed,
commitment.chain_length,
chain_sample_interval,
)
.map_err(|e| anyhow!("Failed to create hash chain: {}", e))?;
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));
} 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: *provider,
reveal_delay_blocks: chain_config.reveal_delay_blocks,
Expand Down
76 changes: 6 additions & 70 deletions apps/argus/src/command/setup_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use {
crate::{
api::{get_register_uri, ChainId},
chain::ethereum::{ProviderInfo, SignablePythContract},
command::register_provider::{register_provider_from_config, CommitmentMetadata},
command::register_provider::register_provider_from_config,
config::{Config, EthereumConfig, SetupProviderOptions},
state::{HashChainState, PebbleHashChain},
},
anyhow::{anyhow, Result},
ethers::{
Expand Down Expand Up @@ -56,8 +55,6 @@ pub async fn setup_provider(opts: &SetupProviderOptions) -> Result<()> {

/// Setup provider for a single chain.
/// 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.
#[tracing::instrument(name = "setup_chain_provider", skip_all, fields(chain_id = chain_id))]
Expand All @@ -79,72 +76,11 @@ async fn setup_chain_provider(
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={}, sequenceNumber={}",
provider_info.end_sequence_number,
provider_info.sequence_number
);
register = true;
} else {
let metadata =
bincode::deserialize::<CommitmentMetadata>(&provider_info.commitment_metadata)
.map_err(|e| {
anyhow!(
"Chain: {} - Failed to deserialize commitment metadata: {}",
&chain_id,
e
)
})?;

let secret = provider_config.secret.load()?.ok_or(anyhow!(
"Please specify a provider secret in the config file."
))?;
if metadata.chain_length != provider_config.chain_length {
tracing::info!(
"Chain length mismatch. metadata.chain_length={}, provider_config.chain_length={}",
metadata.chain_length,
provider_config.chain_length
);
register = true;
} else {
let hash_chain = PebbleHashChain::from_config(
&secret,
chain_id,
&provider_address,
&chain_config.contract_addr,
&metadata.seed,
provider_config.chain_length,
provider_config.chain_sample_interval,
)?;
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 does not match the commitment",
);
register = true;
}
}
}
if register {
tracing::info!("Registering");
register_provider_from_config(provider_config, chain_id, chain_config)
.await
.map_err(|e| anyhow!("Chain: {} - Failed to register provider: {}", &chain_id, e))?;
tracing::info!("Registered");
}
tracing::info!("Registering");
register_provider_from_config(provider_config, chain_id, chain_config)
.await
.map_err(|e| anyhow!("Chain: {} - Failed to register provider: {}", &chain_id, e))?;
tracing::info!("Registered");

let provider_info = contract.get_provider_info(provider_address).call().await?;

Expand Down
30 changes: 0 additions & 30 deletions apps/argus/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,6 @@ pub struct EthereumConfig {
#[serde(default)]
pub fee: u128,

/// Historical commitments made by the provider.
pub commitments: Option<Vec<Commitment>>,

/// Maximum number of hashes to record in a request.
/// This should be set according to the maximum gas limit the provider supports for callbacks.
pub max_num_hashes: Option<u32>,
Expand Down Expand Up @@ -272,17 +269,6 @@ impl EscalationPolicyConfig {
}
}

/// A commitment that the provider used to generate random numbers at some point in the past.
/// These historical commitments need to be stored in the configuration to support transition points where
/// the commitment changes. In theory, this information is stored on the blockchain, but unfortunately it
/// is hard to retrieve from there.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct Commitment {
pub seed: [u8; 32],
pub chain_length: u64,
pub original_commitment_sequence_number: u64,
}

/// Configuration values that are common to a single provider (and shared across chains).
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ProviderConfig {
Expand All @@ -298,27 +284,11 @@ pub struct ProviderConfig {
/// the private key (e.g., running the server).
pub private_key: SecretString,

/// The provider's secret which is a 64-char hex string.
/// The secret is used for generating new hash chains
pub secret: SecretString,

/// The length of the hash chain to generate.
pub chain_length: u64,

/// How frequently the hash chain is sampled -- increase this value to tradeoff more
/// compute per request for less RAM use.
#[serde(default = "default_chain_sample_interval")]
pub chain_sample_interval: u64,

/// The address of the fee manager for the provider. Set this value to the keeper wallet address to
/// enable keeper balance top-ups.
pub fee_manager: Option<Address>,
}

fn default_chain_sample_interval() -> u64 {
1
}

/// Configuration values for the keeper service that are shared across chains.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct KeeperConfig {
Expand Down
4 changes: 0 additions & 4 deletions apps/argus/src/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use {
get_latest_safe_block, process_backlog, process_new_blocks, watch_blocks_wrapper,
BlockRange,
},
keeper::commitment::update_commitments_loop,
keeper::fee::adjust_fee_wrapper,
keeper::fee::withdraw_fees_wrapper,
keeper::track::track_accrued_pyth_fees,
Expand All @@ -27,7 +26,6 @@ use {
};

pub(crate) mod block;
pub(crate) mod commitment;
pub(crate) mod fee;
pub(crate) mod keeper_metrics;
pub(crate) mod process_event;
Expand Down Expand Up @@ -166,8 +164,6 @@ pub async fn run_keeper_threads(
.in_current_span(),
);

spawn(update_commitments_loop(contract.clone(), chain_state.clone()).in_current_span());

// Spawn a thread to track the provider info and the balance of the keeper
spawn(
async move {
Expand Down
Loading
Loading