diff --git a/crates/steward-proto/src/gen/descriptor.bin b/crates/steward-proto/src/gen/descriptor.bin index 13d29249..fb227094 100644 Binary files a/crates/steward-proto/src/gen/descriptor.bin and b/crates/steward-proto/src/gen/descriptor.bin differ diff --git a/crates/steward-proto/src/gen/steward.v4.rs b/crates/steward-proto/src/gen/steward.v4.rs index 43b1acf9..8758f1fe 100644 --- a/crates/steward-proto/src/gen/steward.v4.rs +++ b/crates/steward-proto/src/gen/steward.v4.rs @@ -5515,6 +5515,9 @@ pub struct ScheduleResponse { /// The ID of the chain on which the target Cellar resides #[prost(uint64, tag = "2")] pub chain_id: u64, + /// Invalidation scope for the gravity tx, keccak256 of the target contract address and encoded contract call + #[prost(string, tag = "3")] + pub invalidation_scope: ::prost::alloc::string::String, } #[derive(serde::Deserialize, serde::Serialize, Clone, PartialEq, ::prost::Message)] pub struct EncodeRequest { diff --git a/hash_proto b/hash_proto index e282adcf..4d7f20fe 100644 --- a/hash_proto +++ b/hash_proto @@ -1 +1 @@ -ff574cfd864f6ae653c2cfd2c1a0e022a8d6ea125630c72712eec9ccb1ec6772 \ No newline at end of file +4e0284025de03d59dfec8ca9913874737e4a310150543686ae35adbe406dbb42 \ No newline at end of file diff --git a/proto/steward/v4/steward.proto b/proto/steward/v4/steward.proto index 25803615..32367499 100644 --- a/proto/steward/v4/steward.proto +++ b/proto/steward/v4/steward.proto @@ -68,6 +68,8 @@ message ScheduleResponse { string id = 1; // The ID of the chain on which the target Cellar resides uint64 chain_id = 2; + // Invalidation scope for the gravity tx, keccak256 of the target contract address and encoded contract call + string invalidation_scope = 3; } message EncodeRequest { diff --git a/src/cellars.rs b/src/cellars.rs index 439dc639..475c7a46 100644 --- a/src/cellars.rs +++ b/src/cellars.rs @@ -372,7 +372,7 @@ pub async fn validate_cellar_id(chain_id: u64, cellar_id: &str) -> Result<(), Er .into()); } - let cellar_id = to_checksum_address(cellar_id)?; + let (cellar_id, _) = to_checksum_address(cellar_id)?; if !is_approved(chain_id, &cellar_id) { if let Err(err) = cache::refresh_approved_cellars().await { @@ -394,7 +394,7 @@ pub async fn validate_cellar_id(chain_id: u64, cellar_id: &str) -> Result<(), Er Ok(()) } -pub(crate) fn to_checksum_address(address: &str) -> Result { +pub(crate) fn to_checksum_address(address: &str) -> Result<(String, Vec), Error> { let address = match address.parse::
() { Ok(a) => a, Err(e) => { @@ -403,9 +403,10 @@ pub(crate) fn to_checksum_address(address: &str) -> Result { .into()) } }; + let address_bytes = address.as_bytes().to_vec(); let address = ethers::utils::to_checksum(&address, None); - Ok(address) + Ok((address, address_bytes)) } #[cfg(test)] diff --git a/src/cork.rs b/src/cork.rs index 6a1cfd2c..7863bdf8 100644 --- a/src/cork.rs +++ b/src/cork.rs @@ -47,7 +47,7 @@ impl proto::contract_call_service_server::ContractCallService for CorkHandler { )); } - let cellar_id = match to_checksum_address(&request.cellar_id.clone()) { + let (cellar_id, cellar_id_bytes) = match to_checksum_address(&request.cellar_id.clone()) { Ok(id) => id, Err(err) => { debug!( @@ -92,12 +92,17 @@ impl proto::contract_call_service_server::ContractCallService for CorkHandler { } let id = id_hash(height, chain_id, &cellar_id, &encoded_call); + let invalidation_scope = invalidation_scope(cellar_id_bytes, &encoded_call); info!( "scheduled cork {} for cellar {} on chain {} at height {}", id, cellar_id, chain_id, height ); - Ok(Response::new(ScheduleResponse { id, chain_id })) + Ok(Response::new(ScheduleResponse { + id, + chain_id, + invalidation_scope, + })) } } @@ -267,6 +272,17 @@ pub fn id_hash( format!("{:x}", hasher.finalize()) } +// returns the hex encoded invalidation scope of the contract call. this calculation mirrors +// what is done by the cork module when submitting the contract call to gravity. +pub fn invalidation_scope(target_contract_address_bytes: Vec, encoded_call: &[u8]) -> String { + let mut hasher = Keccak256::new(); + let input = [&target_contract_address_bytes, encoded_call].concat(); + + hasher.update(input); + + format!("{:x}", hasher.finalize()) +} + #[cfg(test)] mod tests { use super::*; @@ -285,4 +301,12 @@ mod tests { assert_eq!(expected, actual); } + + #[test] + fn test_invalidation_scope() { + let expected = "47c8800f7dd3fa4b8c7a08a30bdcf2c206574760663d30f1fbc78b5f632e2209"; + let actual = invalidation_scope("bleep".as_bytes().to_vec(), "bloop".as_bytes()); + + assert_eq!(expected, actual); + } } diff --git a/src/cork/client.rs b/src/cork/client.rs index 5679714f..7166e28d 100644 --- a/src/cork/client.rs +++ b/src/cork/client.rs @@ -46,7 +46,7 @@ impl CorkQueryClient { let mut result: HashMap> = HashMap::new(); for id in cork_result.into_inner().cellar_ids { - let normalized_id = match to_checksum_address(&id) { + let (normalized_id, _) = match to_checksum_address(&id) { Ok(addr) => addr, Err(err) => { error!("failed to get checksum of cellar ID {}, it will not be cached as approved: {}", id, err); @@ -61,7 +61,7 @@ impl CorkQueryClient { let chain_id = set.chain_id; let cellar_ids = set.ids.clone(); for id in cellar_ids.into_iter() { - let normalized_id = match to_checksum_address(&id) { + let (normalized_id, _) = match to_checksum_address(&id) { Ok(addr) => addr, Err(err) => { error!("failed to get checksum of axelar cellar ID {}, it will not be cached as approved: {}", id, err); diff --git a/src/gen/proto/descriptor.bin b/src/gen/proto/descriptor.bin new file mode 100644 index 00000000..43d79776 Binary files /dev/null and b/src/gen/proto/descriptor.bin differ diff --git a/src/pubsub.rs b/src/pubsub.rs index 8c6b97b4..f504d5fd 100644 --- a/src/pubsub.rs +++ b/src/pubsub.rs @@ -89,7 +89,7 @@ pub(crate) async fn get_trust_state() -> Result> return None; } }; - let Ok(cellar_id) = to_checksum_address(&cellar_id) else { + let Ok((cellar_id, _)) = to_checksum_address(&cellar_id) else { error!("failed to convert cellarID part of subscription ID to checksum: {sid}, it will not be included in trust store"); return None; };