diff --git a/sequencer/api/merklized_state.toml b/sequencer/api/merklized_state.toml new file mode 100644 index 0000000000..03d04a2e28 --- /dev/null +++ b/sequencer/api/merklized_state.toml @@ -0,0 +1,4 @@ +[route.getfeebalance] +PATH = ["fee-balance/latest/:address"] +":address" = "Literal" +DOC = "Get current balance in fee state. Expected parameter is an Ethereum address in hex format." \ No newline at end of file diff --git a/sequencer/src/api.rs b/sequencer/src/api.rs index 1af0cab081..00829ad05a 100644 --- a/sequencer/src/api.rs +++ b/sequencer/src/api.rs @@ -1326,6 +1326,17 @@ mod test { assert_eq!(*path.index(), account); assert!(*path.elem().unwrap() > 0.into(), "{:?}", path.elem()); } + + // testing fee_balance api + let account = TestConfig::<5>::builder_key().fee_account(); + let amount = client + .get::>(&format!("fee-state/fee-balance/latest/{}", account)) + .send() + .await + .unwrap() + .unwrap(); + let expected = ethers::types::U256::max_value(); + assert_eq!(expected, amount.0); } #[async_std::test] diff --git a/sequencer/src/api/endpoints.rs b/sequencer/src/api/endpoints.rs index 8b22fe9857..3ccc819c7a 100644 --- a/sequencer/src/api/endpoints.rs +++ b/sequencer/src/api/endpoints.rs @@ -7,8 +7,11 @@ use std::{ use anyhow::Result; use committable::Committable; -use espresso_types::{FeeAccount, NamespaceId, NsProof, PubKey, Transaction}; +use espresso_types::{ + FeeAccount, FeeMerkleTree, NamespaceId, NsProof, PubKey, Transaction, FEE_MERKLE_TREE_ARITY, +}; use futures::{try_join, FutureExt}; +use hotshot_query_service::merklized_state::Snapshot; use hotshot_query_service::{ availability::{self, AvailabilityDataSource, CustomSnafu, FetchBlockSnafu}, explorer::{self, ExplorerDataSource}, @@ -45,6 +48,41 @@ pub struct NamespaceProofQueryData { pub transactions: Vec, } +pub(super) fn get_balance() -> Result> +where + State: 'static + Send + Sync + ReadState, + Ver: 'static + StaticVersionType, + ::State: Send + + Sync + + MerklizedStateDataSource + + MerklizedStateHeightPersistence, +{ + let mut options = merklized_state::Options::default(); + let extension = toml::from_str(include_str!("../../api/merklized_state.toml"))?; + options.extensions.push(extension); + + let mut api = + merklized_state::define_api::(&options)?; + + api.get("getfeebalance", move |req, state| { + async move { + let address = req.string_param("address")?; + let height = state.get_last_state_height().await?; + let snapshot = Snapshot::Index(height as u64); + let key = address + .parse() + .map_err(|_| merklized_state::Error::Custom { + message: "failed to parse address".to_string(), + status: StatusCode::BAD_REQUEST, + })?; + let path = state.get_path(snapshot, key).await?; + Ok(path.elem().copied()) + } + .boxed() + })?; + Ok(api) +} + pub(super) type AvailState = ApiState>; type AvailabilityApi = Api, availability::Error, ApiVer>; diff --git a/sequencer/src/api/options.rs b/sequencer/src/api/options.rs index 79f35d7af1..22e23ed7d0 100644 --- a/sequencer/src/api/options.rs +++ b/sequencer/src/api/options.rs @@ -5,7 +5,7 @@ use async_std::sync::Arc; use clap::Parser; use espresso_types::{ v0::traits::{EventConsumer, NullEventConsumer, SequencerPersistence}, - BlockMerkleTree, FeeMerkleTree, PubKey, + BlockMerkleTree, PubKey, }; use futures::{ channel::oneshot, @@ -357,7 +357,7 @@ impl Options { // Initialize merklized state module for fee merkle tree app.register_module( "fee-state", - endpoints::merklized_state::()?, + endpoints::get_balance::<_, SequencerApiVersion>()?, )?; let state = state.clone(); diff --git a/types/src/v0/mod.rs b/types/src/v0/mod.rs index a21ca1ade0..1429e4f7d5 100644 --- a/types/src/v0/mod.rs +++ b/types/src/v0/mod.rs @@ -181,7 +181,7 @@ pub type NetworkConfig = hotshot_types::network::NetworkConfig; pub use self::impls::{NodeState, SolverAuctionResultsProvider, ValidatedState}; pub use crate::v0_1::{ - BLOCK_MERKLE_TREE_HEIGHT, FEE_MERKLE_TREE_HEIGHT, NS_ID_BYTE_LEN, NS_OFFSET_BYTE_LEN, - NUM_NSS_BYTE_LEN, NUM_TXS_BYTE_LEN, TX_OFFSET_BYTE_LEN, + BLOCK_MERKLE_TREE_HEIGHT, FEE_MERKLE_TREE_ARITY, FEE_MERKLE_TREE_HEIGHT, NS_ID_BYTE_LEN, + NS_OFFSET_BYTE_LEN, NUM_NSS_BYTE_LEN, NUM_TXS_BYTE_LEN, TX_OFFSET_BYTE_LEN, }; use crate::v0_3::SolverAuctionResults; diff --git a/types/src/v0/v0_1/state.rs b/types/src/v0/v0_1/state.rs index 5dcdc04440..7711d37c0b 100644 --- a/types/src/v0/v0_1/state.rs +++ b/types/src/v0/v0_1/state.rs @@ -15,11 +15,12 @@ use std::collections::HashSet; pub type BlockMerkleTree = LightWeightSHA3MerkleTree>; pub type BlockMerkleCommitment = ::Commitment; -pub type FeeMerkleTree = UniversalMerkleTree; +pub type FeeMerkleTree = UniversalMerkleTree; pub type FeeMerkleCommitment = ::Commitment; pub const BLOCK_MERKLE_TREE_HEIGHT: usize = 32; pub const FEE_MERKLE_TREE_HEIGHT: usize = 20; +pub const FEE_MERKLE_TREE_ARITY: usize = 256; #[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] pub struct Delta {