Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: posting ECDSARegistry signature to s3 bucket for validators #3674

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c5ac704
forge install: eigenlayer-middleware
aroralanuk Apr 16, 2024
8873f20
install
aroralanuk Apr 22, 2024
2158670
getRestakeableStrategies
aroralanuk Apr 22, 2024
1ee6b10
comment
aroralanuk Apr 22, 2024
42ae9a6
enroll tc
aroralanuk Apr 23, 2024
325031e
add challenger
aroralanuk Apr 23, 2024
0488bc5
add enumerablemap
aroralanuk Apr 25, 2024
f737489
remove challengers
aroralanuk Apr 25, 2024
0eaffff
add unenroll tests
aroralanuk Apr 26, 2024
ef35202
fin testing
aroralanuk Apr 26, 2024
5c1c827
Merge branch 'main' into kunal/avs-contracts
aroralanuk Apr 26, 2024
a95a8c5
setSlasher
aroralanuk Apr 26, 2024
e348bdc
rm console.sol
aroralanuk Apr 26, 2024
5680d72
fix deregister bug
aroralanuk Apr 27, 2024
98704f5
announce_to_avs
aroralanuk Apr 29, 2024
b8afaae
address yorke's comments
aroralanuk Apr 30, 2024
59c7019
Merge branch 'main' into kunal/avs-contracts
aroralanuk Apr 30, 2024
c176526
inter
aroralanuk Apr 30, 2024
d7c2032
hardhat config filtering fail
aroralanuk Apr 30, 2024
01b1940
Revert "hardhat config filtering fail"
aroralanuk May 1, 2024
317d814
vendor interfaces fail
aroralanuk May 1, 2024
38e3ac5
check sig
aroralanuk May 2, 2024
bf3e8df
vendor
aroralanuk May 4, 2024
421353e
Merge branch 'main' into kunal/avs-contracts
aroralanuk May 4, 2024
ff781c3
cleanup
aroralanuk May 4, 2024
05d7979
using steven's SMBase
aroralanuk May 6, 2024
df4a172
rm remapping upgrade
aroralanuk May 6, 2024
f045045
adding el core addresses
aroralanuk May 6, 2024
3abf566
Merge branch 'main' into kunal/avs-contracts
aroralanuk May 6, 2024
2ef337c
reading strategies from json
aroralanuk May 7, 2024
b50e0b2
add test for check man unenrollment
aroralanuk May 7, 2024
828f4e9
unenroll with address[]
aroralanuk May 7, 2024
7112431
function for single challenger enroll/unenroll
aroralanuk May 7, 2024
4cf5b02
separate vendored folder
aroralanuk May 7, 2024
7f3540b
add proxy deployment to forge
aroralanuk May 7, 2024
b159fdf
Merge branch 'main' into kunal/avs-contracts
aroralanuk May 7, 2024
23aa155
add global fuzz.runs config
aroralanuk May 7, 2024
e11ed99
update spelling
aroralanuk May 7, 2024
2f67212
optional signer for avs
aroralanuk May 7, 2024
0e29c58
no unwrap
aroralanuk May 7, 2024
e62daa4
add incomp attribution to LL
aroralanuk May 7, 2024
2cd2d6a
Merge branch 'kunal/avs-contracts' into kunal/validator-el-sig-posting
aroralanuk May 7, 2024
ed089e3
inter sig check
aroralanuk May 8, 2024
25f4a0d
Run the AVS singleton signer
tkporter May 8, 2024
e8a199b
update separate init
aroralanuk May 9, 2024
3800b6d
resolve double hashing
aroralanuk May 9, 2024
85ab916
config avs_domain
aroralanuk May 9, 2024
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
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
typescript/sdk/src/cw-types/*.types.ts linguist-generated=true
rust/chains/hyperlane-ethereum/abis/*.abi.json linguist-generated=true
solidity/contracts/interfaces/avs/*.sol linguist-vendored=true
solidity/contracts/avs/ECDSA*.sol linguist-vendored=true
1 change: 1 addition & 0 deletions rust/Cargo.lock

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

31 changes: 31 additions & 0 deletions rust/agents/validator/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use hyperlane_base::{
impl_loadable_from_settings,
settings::{
parser::{RawAgentConf, RawAgentSignerConf, ValueParser},
staking_config::StakingConf,
CheckpointSyncerConf, Settings, SignerConf,
},
};
Expand All @@ -34,12 +35,18 @@ pub struct ValidatorSettings {
pub origin_chain: HyperlaneDomain,
/// The validator attestation signer
pub validator: SignerConf,
/// The AVS domain to register the operator with ()
pub avs_domain: Option<u32>,
/// The optional signer for registering the AVS operator
pub avs_operator: Option<SignerConf>,
/// The checkpoint syncer configuration
pub checkpoint_syncer: CheckpointSyncerConf,
/// The reorg_period in blocks
pub reorg_period: u64,
/// How frequently to check for new checkpoints
pub interval: Duration,

pub staking_config: StakingConf,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you expect to ever have this be set via settings?

if we won't ever have a different config other than the default_staking_config, imo you could just not even have this in ValidatorSettings, and just create it in impl BaseAgent for Validator {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

given the above comment, I was anticipating we may need to set it via settings as you mentioned

}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -91,6 +98,27 @@ impl FromRawConf<RawValidatorSettings> for ValidatorSettings {
)
.end();

let avs_chain_name = p
.chain(&mut err)
.get_key("avsChainName")
.parse_string()
.end();

let avs_domain: Option<u32> = match avs_chain_name {
Some("ethereum") => Some(1),
Some("holesky") => Some(17000),
_ => None,
};

let avs_operator = p
.chain(&mut err)
.get_opt_key("avs_operator")
.parse_from_raw_config::<SignerConf, RawAgentSignerConf, NoFilter>(
(),
"Expected valid validator configuration",
)
.end();

let db = p
.chain(&mut err)
.get_opt_key("db")
Expand Down Expand Up @@ -140,9 +168,12 @@ impl FromRawConf<RawValidatorSettings> for ValidatorSettings {
db,
origin_chain,
validator,
avs_domain,
avs_operator,
checkpoint_syncer,
reorg_period,
interval,
staking_config: StakingConf::default_staking_config(),
})
}
}
Expand Down
77 changes: 74 additions & 3 deletions rust/agents/validator/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ use tracing::{error, info, info_span, instrument::Instrumented, warn, Instrument
use hyperlane_base::{
db::{HyperlaneRocksDB, DB},
metrics::AgentMetrics,
settings::ChainConf,
settings::{staking_config::StakingConf, ChainConf},
BaseAgent, ChainMetrics, CheckpointSyncer, ContractSyncMetrics, ContractSyncer, CoreMetrics,
HyperlaneAgentCore, MetricsUpdater, SequencedDataContractSync,
};

use hyperlane_core::{
Announcement, ChainResult, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneSigner,
HyperlaneSignerExt, Mailbox, MerkleTreeHook, MerkleTreeInsertion, TxOutcome, ValidatorAnnounce,
utils::operator_registration_signature_expiry, Announcement, ChainResult, HyperlaneChain,
HyperlaneContract, HyperlaneDomain, HyperlaneSigner, HyperlaneSignerExt, Mailbox,
MerkleTreeHook, MerkleTreeInsertion, OperatorRegistrationBuilder, TxOutcome, ValidatorAnnounce,
H256, U256,
};
use hyperlane_ethereum::{SingletonSigner, SingletonSignerHandle};
Expand All @@ -44,12 +45,16 @@ pub struct Validator {
signer: SingletonSignerHandle,
// temporary holder until `run` is called
signer_instance: Option<Box<SingletonSigner>>,
avs_domain: Option<u32>,
avs_signer: Option<SingletonSignerHandle>,
avs_signer_instance: Option<Box<SingletonSigner>>,
reorg_period: u64,
interval: Duration,
checkpoint_syncer: Arc<dyn CheckpointSyncer>,
core_metrics: Arc<CoreMetrics>,
agent_metrics: AgentMetrics,
chain_metrics: ChainMetrics,
staking_config: StakingConf,
}

#[async_trait]
Expand All @@ -73,6 +78,16 @@ impl BaseAgent for Validator {
// Intentionally using hyperlane_ethereum for the validator's signer
let (signer_instance, signer) = SingletonSigner::new(settings.validator.build().await?);

// If the AVS operator is provided, create a signer for it to write the announcement
let (avs_signer_instance, avs_signer) = match &settings.avs_operator {
Some(avs_operator) => {
let (avs_signer_instance, avs_signer) =
SingletonSigner::new(avs_operator.build().await?);
(Some(avs_signer_instance), Some(avs_signer))
}
None => (None, None),
};

let core = settings.build_hyperlane_core(metrics.clone());
let checkpoint_syncer = settings.checkpoint_syncer.build(None).await?.into();

Expand Down Expand Up @@ -116,12 +131,16 @@ impl BaseAgent for Validator {
validator_announce: validator_announce.into(),
signer,
signer_instance: Some(Box::new(signer_instance)),
avs_domain: settings.avs_domain,
avs_signer,
avs_signer_instance: avs_signer_instance.map(Box::new),
reorg_period: settings.reorg_period,
interval: settings.interval,
checkpoint_syncer,
agent_metrics,
chain_metrics,
core_metrics: metrics,
staking_config: settings.staking_config,
Copy link
Collaborator

Choose a reason for hiding this comment

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

imo instead of storing a config in the Validator that you can then lookup

let service_manager = self
            .staking_config
            .service_managers
            .get(&avs_domain)

it'd be nicer to just do that lookup in here when building the Validator once, and then store the service_manager as the config in the Validator

})
}

Expand Down Expand Up @@ -152,6 +171,15 @@ impl BaseAgent for Validator {
);
}

if let Some(avs_signer_instance) = self.avs_signer_instance.take() {
tasks.push(
tokio::spawn(async move {
avs_signer_instance.run().await;
})
.instrument(info_span!("AvsSingletonSigner")),
);
}

let metrics_updater = MetricsUpdater::new(
&self.origin_chain_conf,
self.core_metrics.clone(),
Expand All @@ -171,6 +199,10 @@ impl BaseAgent for Validator {
// announce the validator after spawning the signer task
self.announce().await.expect("Failed to announce validator");

self.write_operator_registration()
.await
.expect("Failed to announce to AVS");

let reorg_period = NonZeroU64::new(self.reorg_period);

// Ensure that the merkle tree hook has count > 0 before we begin indexing
Expand Down Expand Up @@ -286,6 +318,45 @@ impl Validator {
}
}

async fn write_operator_registration(&self) -> Result<()> {
if let Some(ref avs_signer) = &self.avs_signer {
let address = avs_signer.eth_address();
let registration_location = self.checkpoint_syncer.announcement_location();

println!(
"Announcing to AVS, location: {:?} for validator: {:?}",
registration_location, address
);

let avs_domain = self.avs_domain.unwrap();

let service_manager = match self.staking_config.service_managers.get(&avs_domain) {
Some(service_manager) => service_manager,
None => {
info!("No service manager found for AVS domain {}", avs_domain);
return Ok(());
}
};

let registration = OperatorRegistrationBuilder::default()
.domain(avs_domain)
.operator(address)
.service_manager_address(*service_manager) // Dereference the service_manager variable
.salt(H256::zero()) // TODO: is this ok?
.expiry(operator_registration_signature_expiry())
.build()
.unwrap();

let signed_registration = avs_signer.sign(registration.clone()).await?;
self.checkpoint_syncer
.write_operator_registration(&signed_registration)
.await?;
} else {
info!("No AVS signer configured, skipping AVS announcement");
}
Ok(())
}

async fn announce(&self) -> Result<()> {
let address = self.signer.eth_address();
let announcement_location = self.checkpoint_syncer.announcement_location();
Expand Down
13 changes: 13 additions & 0 deletions rust/chains/hyperlane-ethereum/src/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,25 @@ impl HyperlaneSigner for Signers {
}

async fn sign_hash(&self, hash: &H256) -> Result<HyperlaneSignature, HyperlaneSignerError> {
print!("non_sign_hash: {:?}", hash);
let mut signature = Signer::sign_message(self, hash)
.await
.map_err(|err| HyperlaneSignerError::from(Box::new(err) as Box<_>))?;
signature.v = 28 - (signature.v % 2);
Ok(signature.into())
}

async fn sign_hash_directly(
&self,
hash: &H256,
) -> Result<HyperlaneSignature, HyperlaneSignerError> {
let mut signature = match self {
Signers::Local(signer) => signer.sign_hash(hash.into()),
Signers::Aws(_signer) => !unimplemented!(),
}; // TODO: map_err
signature.v = 28 - (signature.v % 2);
Ok(signature.into())
}
}

/// Error types for Signers
Expand Down
7 changes: 7 additions & 0 deletions rust/chains/hyperlane-ethereum/src/signer/singleton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ impl HyperlaneSigner for SingletonSignerHandle {
Err(err) => Err(SingletonSignerError::from(err).into()),
}
}

async fn sign_hash_directly(
&self,
hash: &H256,
) -> Result<HyperlaneSignature, HyperlaneSignerError> {
self.sign_hash(hash).await
}
}

impl SingletonSigner {
Expand Down
2 changes: 2 additions & 0 deletions rust/hyperlane-base/src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ mod trace;
mod checkpoint_syncer;
pub mod parser;

pub mod staking_config;

/// Declare that an agent can be constructed from settings.
///
/// E.g.
Expand Down
24 changes: 24 additions & 0 deletions rust/hyperlane-base/src/settings/staking_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use hyperlane_core::H160;
use std::{collections::HashMap, str::FromStr};

#[derive(Clone, Debug, Default)]
pub struct StakingConf {
/// Address of the HyperlaneServiceManager contract
pub service_managers: HashMap<u32, H160>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

will there be stuff in here other than the service_managers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I imagine we'll have more config once we have native staking which will also have some form of registration announcement in a json form.

}

impl StakingConf {
pub fn default_staking_config() -> StakingConf {
let mut service_managers = HashMap::new();
service_managers.insert(
1,
H160::from_str("0xa3aC2db78AC678D9609637e23020dc210110DAE4").unwrap(),
);
service_managers.insert(
17000,
H160::from_str("0x055733000064333CaDDbC92763c58BF0192fFeBf").unwrap(),
); // holesky

StakingConf { service_managers }
}
}
9 changes: 8 additions & 1 deletion rust/hyperlane-base/src/traits/checkpoint_syncer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use std::fmt::Debug;
use async_trait::async_trait;
use eyre::Result;

use hyperlane_core::{SignedAnnouncement, SignedCheckpointWithMessageId};
use hyperlane_core::{
SignedAnnouncement, SignedCheckpointWithMessageId, SignedOperatorRegistration,
};

/// A generic trait to read/write Checkpoints offchain
#[async_trait]
Expand All @@ -29,6 +31,11 @@ pub trait CheckpointSyncer: Debug + Send + Sync {
) -> Result<()>;
/// Write the signed announcement to this syncer
async fn write_announcement(&self, signed_announcement: &SignedAnnouncement) -> Result<()>;
/// Write the signed announcement to this syncer
async fn write_operator_registration(
&self,
signed_operator_registration: &SignedOperatorRegistration,
) -> Result<()>;
/// Return the announcement storage location for this syncer
fn announcement_location(&self) -> String;
}
11 changes: 10 additions & 1 deletion rust/hyperlane-base/src/types/gcs_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use crate::CheckpointSyncer;
use async_trait::async_trait;
use derive_new::new;
use eyre::{bail, Result};
use hyperlane_core::{SignedAnnouncement, SignedCheckpointWithMessageId};
use hyperlane_core::{
SignedAnnouncement, SignedCheckpointWithMessageId, SignedOperatorRegistration,
};
use std::fmt;
use ya_gcp::{storage::StorageClient, AuthFlow, ClientBuilder, ClientBuilderConfig};

Expand Down Expand Up @@ -186,6 +188,13 @@ impl CheckpointSyncer for GcsStorageClient {
Ok(())
}

async fn write_operator_registration(
&self,
_signed_operator_registration: &SignedOperatorRegistration,
) -> Result<()> {
unimplemented!()
}

/// Return the announcement storage location for this syncer
fn announcement_location(&self) -> String {
format!("gs://{}/{}", &self.bucket, ANNOUNCEMENT_KEY)
Expand Down
21 changes: 20 additions & 1 deletion rust/hyperlane-base/src/types/local_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::path::PathBuf;

use async_trait::async_trait;
use eyre::{Context, Result};
use hyperlane_core::{SignedAnnouncement, SignedCheckpointWithMessageId};
use hyperlane_core::{
SignedAnnouncement, SignedCheckpointWithMessageId, SignedOperatorRegistration,
};
use prometheus::IntGauge;

use crate::traits::CheckpointSyncer;
Expand Down Expand Up @@ -40,6 +42,10 @@ impl LocalStorage {
fn announcement_file_path(&self) -> PathBuf {
self.path.join("announcement.json")
}

fn operator_registration_file_path(&self) -> PathBuf {
self.path.join("eigenlayer_operator_registration.json")
}
}

#[async_trait]
Expand Down Expand Up @@ -100,6 +106,19 @@ impl CheckpointSyncer for LocalStorage {
Ok(())
}

async fn write_operator_registration(
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
&self,
signed_operator_registration: &SignedOperatorRegistration,
) -> Result<()> {
let serialized_operator_registration =
serde_json::to_string_pretty(signed_operator_registration)?;
let path = self.operator_registration_file_path();
tokio::fs::write(&path, &serialized_operator_registration)
.await
.with_context(|| format!("Writing operator registration to {path:?}"))?;
Ok(())
}

fn announcement_location(&self) -> String {
format!("file://{}", self.path.to_str().unwrap())
}
Expand Down
Loading
Loading