From d620c746c3ae83827cf42d9115eee4e9ce37b520 Mon Sep 17 00:00:00 2001 From: elizabeth Date: Thu, 1 Feb 2024 16:43:18 -0500 Subject: [PATCH] add ibc_sudo_address to genesis, only allow IbcRelay from this addres --- .../src/accounts/component.rs | 3 ++ .../src/accounts/state_ext.rs | 33 +++++++++++++++++++ crates/astria-sequencer/src/app.rs | 20 +++++++---- .../src/authority/component.rs | 4 +-- crates/astria-sequencer/src/genesis.rs | 4 ++- .../astria-sequencer/src/service/consensus.rs | 3 +- .../astria-sequencer/src/transaction/mod.rs | 9 ++++- .../test-genesis-app-state.json | 3 +- 8 files changed, 66 insertions(+), 13 deletions(-) diff --git a/crates/astria-sequencer/src/accounts/component.rs b/crates/astria-sequencer/src/accounts/component.rs index 3bb0af3556..dfa1917d66 100644 --- a/crates/astria-sequencer/src/accounts/component.rs +++ b/crates/astria-sequencer/src/accounts/component.rs @@ -32,6 +32,9 @@ impl Component for AccountsComponent { .put_account_balance(account.address, native_asset.id(), account.balance) .context("failed writing account balance to state")?; } + state + .put_ibc_sudo_address(app_state.ibc_sudo_address) + .context("failed to set IBC sudo key")?; Ok(()) } diff --git a/crates/astria-sequencer/src/accounts/state_ext.rs b/crates/astria-sequencer/src/accounts/state_ext.rs index ca74bb9460..80c8288c12 100644 --- a/crates/astria-sequencer/src/accounts/state_ext.rs +++ b/crates/astria-sequencer/src/accounts/state_ext.rs @@ -6,6 +6,7 @@ use astria_core::sequencer::v1alpha1::{ account::AssetBalance, asset, Address, + ADDRESS_LEN, }; use async_trait::async_trait; use borsh::{ @@ -32,8 +33,14 @@ struct Nonce(u32); #[derive(BorshSerialize, BorshDeserialize, Debug)] struct Balance(u128); +/// Newtype wrapper to read and write an address from rocksdb. +#[derive(BorshSerialize, BorshDeserialize, Debug)] +struct SudoAddress([u8; ADDRESS_LEN]); + const ACCOUNTS_PREFIX: &str = "accounts"; +const IBC_SUDO_STORAGE_KEY: &str = "ibcsudo"; + fn storage_key(address: &str) -> String { format!("{ACCOUNTS_PREFIX}/{address}") } @@ -151,6 +158,21 @@ pub(crate) trait StateReadExt: StateRead { let Balance(balance) = Balance::try_from_slice(&bytes).context("invalid balance bytes")?; Ok(balance) } + + #[instrument(skip(self))] + async fn get_ibc_sudo_address(&self) -> Result
{ + let Some(bytes) = self + .get_raw(IBC_SUDO_STORAGE_KEY) + .await + .context("failed reading raw ibc sudo key from state")? + else { + // ibc sudo key must be set + return Err(anyhow::anyhow!("ibc sudo key not found")); + }; + let SudoAddress(address) = + SudoAddress::try_from_slice(&bytes).context("invalid ibc sudo key bytes")?; + Ok(Address(address)) + } } impl StateReadExt for T {} @@ -193,6 +215,17 @@ pub(crate) trait StateWriteExt: StateWrite { self.put_raw(channel_balance_storage_key(channel, asset), bytes); Ok(()) } + + #[instrument(skip(self))] + fn put_ibc_sudo_address(&mut self, address: Address) -> Result<()> { + self.put_raw( + IBC_SUDO_STORAGE_KEY.to_string(), + SudoAddress(address.0) + .try_to_vec() + .context("failed to convert sudo address to vec")?, + ); + Ok(()) + } } impl StateWriteExt for T {} diff --git a/crates/astria-sequencer/src/app.rs b/crates/astria-sequencer/src/app.rs index 5f00577e40..24f86a8352 100644 --- a/crates/astria-sequencer/src/app.rs +++ b/crates/astria-sequencer/src/app.rs @@ -178,7 +178,7 @@ impl App { AuthorityComponent::init_chain( &mut state_tx, &AuthorityComponentAppState { - authority_sudo_key: genesis_state.authority_sudo_key, + authority_sudo_address: genesis_state.authority_sudo_address, genesis_validators, }, ) @@ -772,7 +772,8 @@ mod test { let genesis_state = genesis_state.unwrap_or_else(|| GenesisState { accounts: default_genesis_accounts(), - authority_sudo_key: Address::from([0; 20]), + authority_sudo_address: Address::from([0; 20]), + ibc_sudo_address: Address::from([0; 20]), native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), }); @@ -1096,7 +1097,8 @@ mod test { let genesis_state = GenesisState { accounts: default_genesis_accounts(), - authority_sudo_key: alice_address, + authority_sudo_address: alice_address, + ibc_sudo_address: alice_address, native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), }; let mut app = initialize_app(Some(genesis_state), vec![]).await; @@ -1128,7 +1130,8 @@ mod test { let genesis_state = GenesisState { accounts: default_genesis_accounts(), - authority_sudo_key: alice_address, + authority_sudo_address: alice_address, + ibc_sudo_address: alice_address, native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), }; let mut app = initialize_app(Some(genesis_state), vec![]).await; @@ -1158,7 +1161,8 @@ mod test { let genesis_state = GenesisState { accounts: default_genesis_accounts(), - authority_sudo_key: sudo_address, + authority_sudo_address: sudo_address, + ibc_sudo_address: [0u8; 20].into(), native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), }; let mut app = initialize_app(Some(genesis_state), vec![]).await; @@ -1188,7 +1192,8 @@ mod test { let genesis_state = GenesisState { accounts: default_genesis_accounts(), - authority_sudo_key: alice_address, + authority_sudo_address: alice_address, + ibc_sudo_address: [0u8; 20].into(), native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), }; let mut app = initialize_app(Some(genesis_state), vec![]).await; @@ -1335,7 +1340,8 @@ mod test { async fn app_commit() { let genesis_state = GenesisState { accounts: default_genesis_accounts(), - authority_sudo_key: Address::from([0; 20]), + authority_sudo_address: Address::from([0; 20]), + ibc_sudo_address: Address::from([0; 20]), native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), }; diff --git a/crates/astria-sequencer/src/authority/component.rs b/crates/astria-sequencer/src/authority/component.rs index 2185896e92..c7a5a9c8c7 100644 --- a/crates/astria-sequencer/src/authority/component.rs +++ b/crates/astria-sequencer/src/authority/component.rs @@ -26,7 +26,7 @@ pub(crate) struct AuthorityComponent; #[derive(Debug)] pub(crate) struct AuthorityComponentAppState { - pub(crate) authority_sudo_key: Address, + pub(crate) authority_sudo_address: Address, pub(crate) genesis_validators: Vec, } @@ -38,7 +38,7 @@ impl Component for AuthorityComponent { async fn init_chain(mut state: S, app_state: &Self::AppState) -> Result<()> { // set sudo key and initial validator set state - .put_sudo_address(app_state.authority_sudo_key) + .put_sudo_address(app_state.authority_sudo_address) .context("failed to set sudo key")?; state .put_validator_set(ValidatorSet::new_from_updates( diff --git a/crates/astria-sequencer/src/genesis.rs b/crates/astria-sequencer/src/genesis.rs index f24bd2364c..654273af2e 100644 --- a/crates/astria-sequencer/src/genesis.rs +++ b/crates/astria-sequencer/src/genesis.rs @@ -9,7 +9,9 @@ use serde::{ pub(crate) struct GenesisState { pub(crate) accounts: Vec, #[serde(deserialize_with = "deserialize_address")] - pub(crate) authority_sudo_key: Address, + pub(crate) authority_sudo_address: Address, + #[serde(deserialize_with = "deserialize_address")] + pub(crate) ibc_sudo_address: Address, pub(crate) native_asset_base_denomination: String, } diff --git a/crates/astria-sequencer/src/service/consensus.rs b/crates/astria-sequencer/src/service/consensus.rs index e112668118..bb13bb6e16 100644 --- a/crates/astria-sequencer/src/service/consensus.rs +++ b/crates/astria-sequencer/src/service/consensus.rs @@ -502,7 +502,8 @@ mod test { fn default() -> Self { Self { accounts: vec![], - authority_sudo_key: Address::from([0; 20]), + authority_sudo_address: Address::from([0; 20]), + ibc_sudo_address: Address::from([0; 20]), native_asset_base_denomination: DEFAULT_NATIVE_ASSET_DENOM.to_string(), } } diff --git a/crates/astria-sequencer/src/transaction/mod.rs b/crates/astria-sequencer/src/transaction/mod.rs index 9478f4c86e..9a39f75b4d 100644 --- a/crates/astria-sequencer/src/transaction/mod.rs +++ b/crates/astria-sequencer/src/transaction/mod.rs @@ -165,7 +165,14 @@ impl ActionHandler for UnsignedTransaction { .await .context("stateful check failed for SudoAddressChangeAction")?, Action::Ibc(_) => { - // no-op; IBC actions merge check_stateful and execute. + let ibc_sudo_address = state + .get_ibc_sudo_address() + .await + .context("failed to get IBC sudo address")?; + ensure!( + from == ibc_sudo_address, + "only IBC sudo address can execute IBC actions" + ); } Action::Ics20Withdrawal(act) => act .check_stateful(state, from, fee_asset_id) diff --git a/crates/astria-sequencer/test-genesis-app-state.json b/crates/astria-sequencer/test-genesis-app-state.json index fb22c4a93b..0f2fffb80c 100644 --- a/crates/astria-sequencer/test-genesis-app-state.json +++ b/crates/astria-sequencer/test-genesis-app-state.json @@ -13,6 +13,7 @@ "balance": 1000000000000000000 } ], - "authority_sudo_key": "1c0c490f1b5528d8173c5de46d131160e4b2c0c3", + "authority_sudo_address": "1c0c490f1b5528d8173c5de46d131160e4b2c0c3", + "ibc_sudo_address": "1c0c490f1b5528d8173c5de46d131160e4b2c0c3", "native_asset_base_denomination": "nria" }