Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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: 3 additions & 0 deletions crates/astria-sequencer/src/accounts/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down
33 changes: 33 additions & 0 deletions crates/astria-sequencer/src/accounts/state_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use astria_core::sequencer::v1alpha1::{
account::AssetBalance,
asset,
Address,
ADDRESS_LEN,
};
use async_trait::async_trait;
use borsh::{
Expand All @@ -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}")
}
Expand Down Expand Up @@ -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<Address> {
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<T: StateRead> StateReadExt for T {}
Expand Down Expand Up @@ -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<T: StateWrite> StateWriteExt for T {}
20 changes: 13 additions & 7 deletions crates/astria-sequencer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
)
Expand Down Expand Up @@ -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(),
});

Expand Down Expand Up @@ -1097,7 +1098,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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1157,7 +1160,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;
Expand Down Expand Up @@ -1186,7 +1190,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;
Expand Down Expand Up @@ -1332,7 +1337,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(),
};

Expand Down
4 changes: 2 additions & 2 deletions crates/astria-sequencer/src/authority/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<validator::Update>,
}

Expand All @@ -38,7 +38,7 @@ impl Component for AuthorityComponent {
async fn init_chain<S: StateWriteExt>(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(
Expand Down
4 changes: 3 additions & 1 deletion crates/astria-sequencer/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use serde::{
pub(crate) struct GenesisState {
pub(crate) accounts: Vec<Account>,
#[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,
}

Expand Down
3 changes: 2 additions & 1 deletion crates/astria-sequencer/src/service/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}
Expand Down
9 changes: 8 additions & 1 deletion crates/astria-sequencer/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,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)
Expand Down
3 changes: 2 additions & 1 deletion crates/astria-sequencer/test-genesis-app-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"balance": 1000000000000000000
}
],
"authority_sudo_key": "1c0c490f1b5528d8173c5de46d131160e4b2c0c3",
"authority_sudo_address": "1c0c490f1b5528d8173c5de46d131160e4b2c0c3",
"ibc_sudo_address": "1c0c490f1b5528d8173c5de46d131160e4b2c0c3",
"native_asset_base_denomination": "nria"
}