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

chore(sequencer)!: update storage keys locations and values (ENG-898) #1616

Merged
merged 8 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
32 changes: 28 additions & 4 deletions crates/astria-core/src/primitive/v1/asset/denom.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
borrow::Cow,
collections::VecDeque,
str::FromStr,
};
Expand Down Expand Up @@ -140,6 +141,27 @@ impl<'a> From<&'a IbcPrefixed> for IbcPrefixed {
}
}

impl<'a> From<&'a IbcPrefixed> for Cow<'a, IbcPrefixed> {
fn from(ibc_prefixed: &'a IbcPrefixed) -> Self {
Cow::Borrowed(ibc_prefixed)
}
}

impl<'a> From<&'a TracePrefixed> for Cow<'a, IbcPrefixed> {
fn from(trace_prefixed: &'a TracePrefixed) -> Self {
Cow::Owned(trace_prefixed.to_ibc_prefixed())
}
}

impl<'a> From<&'a Denom> for Cow<'a, IbcPrefixed> {
fn from(value: &'a Denom) -> Self {
match value {
Denom::TracePrefixed(trace_prefixed) => Cow::from(trace_prefixed),
Denom::IbcPrefixed(ibc_prefixed) => Cow::from(ibc_prefixed),
}
}
}

impl FromStr for Denom {
type Err = ParseDenomError;

Expand Down Expand Up @@ -543,20 +565,22 @@ pub struct IbcPrefixed {
}

impl IbcPrefixed {
pub const LENGTH: usize = 32;
Fraser999 marked this conversation as resolved.
Show resolved Hide resolved

#[must_use]
pub fn new(id: [u8; 32]) -> Self {
pub const fn new(id: [u8; Self::LENGTH]) -> Self {
Self {
id,
}
}

#[must_use]
pub fn as_bytes(&self) -> &[u8; 32] {
pub const fn as_bytes(&self) -> &[u8; Self::LENGTH] {
&self.id
}

#[must_use]
pub fn display_len(&self) -> usize {
pub const fn display_len(&self) -> usize {
68 // "ibc/" + 64 hex characters
}
}
Expand Down Expand Up @@ -586,7 +610,7 @@ impl FromStr for IbcPrefixed {
if segments.next().is_some() {
return Err(ParseIbcPrefixedError::too_many_segments());
}
let id = <[u8; 32]>::from_hex(hex).map_err(Self::Err::hex)?;
let id = <[u8; Self::LENGTH]>::from_hex(hex).map_err(Self::Err::hex)?;
Ok(Self {
id,
})
Expand Down

This file was deleted.

109 changes: 28 additions & 81 deletions crates/astria-sequencer/src/accounts/state_ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
borrow::Cow,
fmt::Display,
pin::Pin,
task::{
Expand Down Expand Up @@ -27,44 +28,21 @@ use futures::Stream;
use pin_project_lite::pin_project;
use tracing::instrument;

use super::storage;
use super::storage::{
self,
keys::{
balance_key,
balance_prefix,
extract_asset_from_key,
nonce_key,
TRANSFER_BASE_FEE_KEY,
},
};
use crate::{
accounts::AddressBytes,
storage::StoredValue,
};

const ACCOUNTS_PREFIX: &str = "accounts";
const TRANSFER_BASE_FEE_STORAGE_KEY: &str = "transferfee";

struct StorageKey<'a, T>(&'a T);
impl<'a, T: AddressBytes> std::fmt::Display for StorageKey<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(ACCOUNTS_PREFIX)?;
f.write_str("/")?;
for byte in self.0.address_bytes() {
f.write_fmt(format_args!("{byte:02x}"))?;
}
Ok(())
}
}

fn balance_storage_key<'a, TAddress, TAsset>(address: &TAddress, asset: &'a TAsset) -> String
where
TAddress: AddressBytes,
asset::IbcPrefixed: From<&'a TAsset>,
{
let asset: asset::IbcPrefixed = asset.into();
format!(
"{}/balance/{}",
StorageKey(address),
crate::storage_keys::hunks::Asset::from(asset)
)
}

fn nonce_storage_key<T: AddressBytes>(address: &T) -> String {
format!("{}/nonce", StorageKey(address))
}

pin_project! {
/// A stream of IBC prefixed assets for a given account.
pub(crate) struct AccountAssetsStream<St> {
Expand Down Expand Up @@ -141,23 +119,14 @@ where
}
}

fn extract_asset_from_key(s: &str) -> Result<asset::IbcPrefixed> {
Ok(s.strip_prefix("accounts/")
.and_then(|s| s.split_once("/balance/").map(|(_, asset)| asset))
.ok_or_eyre("failed to strip prefix from account balance key")?
.parse::<crate::storage_keys::hunks::Asset>()
.context("failed to parse storage key suffix as address hunk")?
.get())
}

#[async_trait]
pub(crate) trait StateReadExt: StateRead + crate::assets::StateReadExt {
#[instrument(skip_all)]
fn account_asset_keys<T: AddressBytes>(
&self,
address: &T,
) -> AccountAssetsStream<Self::PrefixKeysStream> {
let prefix = format!("{}/balance/", StorageKey(address));
let prefix = balance_prefix(address);
AccountAssetsStream {
underlying: self.prefix_keys(&prefix),
}
Expand All @@ -168,7 +137,7 @@ pub(crate) trait StateReadExt: StateRead + crate::assets::StateReadExt {
&self,
address: &T,
) -> AccountAssetBalancesStream<Self::PrefixRawStream> {
let prefix = format!("{}/balance/", StorageKey(address));
let prefix = balance_prefix(address);
AccountAssetBalancesStream {
underlying: self.prefix_raw(&prefix),
}
Expand All @@ -183,10 +152,10 @@ pub(crate) trait StateReadExt: StateRead + crate::assets::StateReadExt {
where
TAddress: AddressBytes,
TAsset: Sync + Display,
asset::IbcPrefixed: From<&'a TAsset> + Send + Sync,
&'a TAsset: Into<Cow<'a, asset::IbcPrefixed>>,
{
let Some(bytes) = self
.get_raw(&balance_storage_key(address, asset))
.get_raw(&balance_key(address, asset))
.await
.map_err(anyhow_to_eyre)
.wrap_err("failed reading raw account balance from state")?
Expand All @@ -201,7 +170,7 @@ pub(crate) trait StateReadExt: StateRead + crate::assets::StateReadExt {
#[instrument(skip_all)]
async fn get_account_nonce<T: AddressBytes>(&self, address: &T) -> Result<u32> {
let bytes = self
.get_raw(&nonce_storage_key(address))
.get_raw(&nonce_key(address))
.await
.map_err(anyhow_to_eyre)
.wrap_err("failed reading raw account nonce from state")?;
Expand All @@ -217,7 +186,7 @@ pub(crate) trait StateReadExt: StateRead + crate::assets::StateReadExt {
#[instrument(skip_all)]
async fn get_transfer_base_fee(&self) -> Result<u128> {
let bytes = self
.get_raw(TRANSFER_BASE_FEE_STORAGE_KEY)
.get_raw(TRANSFER_BASE_FEE_KEY)
.await
.map_err(anyhow_to_eyre)
.wrap_err("failed reading raw transfer base fee from state")?;
Expand All @@ -244,12 +213,12 @@ pub(crate) trait StateWriteExt: StateWrite {
where
TAddress: AddressBytes,
TAsset: Display,
asset::IbcPrefixed: From<&'a TAsset> + Send,
&'a TAsset: Into<Cow<'a, asset::IbcPrefixed>>,
{
let bytes = StoredValue::from(storage::Balance::from(balance))
.serialize()
.wrap_err("failed to serialize balance")?;
self.put_raw(balance_storage_key(address, asset), bytes);
self.put_raw(balance_key(address, asset), bytes);
Ok(())
}

Expand All @@ -258,7 +227,7 @@ pub(crate) trait StateWriteExt: StateWrite {
let bytes = StoredValue::from(storage::Nonce::from(nonce))
.serialize()
.wrap_err("failed to serialize nonce")?;
self.put_raw(nonce_storage_key(address), bytes);
self.put_raw(nonce_key(address), bytes);
Ok(())
}

Expand All @@ -272,7 +241,7 @@ pub(crate) trait StateWriteExt: StateWrite {
where
TAddress: AddressBytes,
TAsset: Sync + Display,
asset::IbcPrefixed: From<&'a TAsset> + Send,
&'a TAsset: Into<Cow<'a, asset::IbcPrefixed>>,
{
let balance = self
.get_account_balance(address, asset)
Expand All @@ -299,7 +268,7 @@ pub(crate) trait StateWriteExt: StateWrite {
where
TAddress: AddressBytes,
TAsset: Sync + Display,
asset::IbcPrefixed: From<&'a TAsset> + Send,
&'a TAsset: Into<Cow<'a, asset::IbcPrefixed>>,
{
let balance = self
.get_account_balance(address, asset)
Expand All @@ -321,7 +290,7 @@ pub(crate) trait StateWriteExt: StateWrite {
let bytes = StoredValue::from(storage::Fee::from(fee))
.serialize()
.wrap_err("failed to serialize fee")?;
self.put_raw(TRANSFER_BASE_FEE_STORAGE_KEY.to_string(), bytes);
self.put_raw(TRANSFER_BASE_FEE_KEY.to_string(), bytes);
Ok(())
}
}
Expand All @@ -330,17 +299,10 @@ impl<T: StateWrite> StateWriteExt for T {}

#[cfg(test)]
mod tests {
use astria_core::primitive::v1::Address;
use cnidarium::StateDelta;
use futures::TryStreamExt as _;
use insta::assert_snapshot;

use super::{
balance_storage_key,
nonce_storage_key,
StateReadExt as _,
StateWriteExt as _,
};
use super::*;
use crate::{
assets::{
StateReadExt as _,
Expand All @@ -352,14 +314,15 @@ mod tests {
},
};

fn asset_0() -> astria_core::primitive::v1::asset::Denom {
fn asset_0() -> asset::Denom {
"asset_0".parse().unwrap()
}

fn asset_1() -> astria_core::primitive::v1::asset::Denom {
fn asset_1() -> asset::Denom {
"asset_1".parse().unwrap()
}
fn asset_2() -> astria_core::primitive::v1::asset::Denom {

fn asset_2() -> asset::Denom {
"asset_2".parse().unwrap()
}

Expand Down Expand Up @@ -834,20 +797,4 @@ mod tests {
let retrieved_fee = state.get_transfer_base_fee().await.unwrap();
assert_eq!(retrieved_fee, 123);
}

#[test]
fn storage_keys_have_not_changed() {
let address: Address = "astria1rsxyjrcm255ds9euthjx6yc3vrjt9sxrm9cfgm"
.parse()
.unwrap();
let asset = "an/asset/with/a/prefix"
.parse::<astria_core::primitive::v1::asset::Denom>()
.unwrap();
assert_eq!(
balance_storage_key(&address, &asset),
balance_storage_key(&address, &asset.to_ibc_prefixed())
);
assert_snapshot!(balance_storage_key(&address, &asset));
assert_snapshot!(nonce_storage_key(&address));
}
}
Loading
Loading