Skip to content

Commit f55a98d

Browse files
committed
feat(rpc): get state proof
1 parent d3df76d commit f55a98d

File tree

11 files changed

+335
-10
lines changed

11 files changed

+335
-10
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -7548,6 +7548,7 @@ name = "lightning-types"
75487548
version = "0.1.0"
75497549
dependencies = [
75507550
"anyhow",
7551+
"atomo",
75517552
"bincode",
75527553
"cid 0.10.1",
75537554
"compile-time-run",

core/application/src/state/query.rs

+22
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ use lightning_interfaces::types::{
2929
Service,
3030
ServiceId,
3131
ServiceRevenue,
32+
StateProofKey,
33+
StateProofValue,
3234
TotalServed,
3335
TransactionRequest,
3436
TransactionResponse,
@@ -268,4 +270,24 @@ impl SyncQueryRunnerInterface for QueryRunner {
268270
fn get_state_root(&self) -> Result<StateRootHash> {
269271
self.run(|ctx| ApplicationStateTree::get_state_root(ctx))
270272
}
273+
274+
/// Returns the state proof for a given key from the application state using the state tree.
275+
fn get_state_proof(
276+
&self,
277+
key: StateProofKey,
278+
) -> Result<(
279+
Option<StateProofValue>,
280+
<ApplicationStateTree as StateTree>::Proof,
281+
)> {
282+
type Serde = <ApplicationStateTree as StateTree>::Serde;
283+
284+
self.run(|ctx| {
285+
let (table, serialized_key) = key.raw::<Serde>();
286+
let proof = ApplicationStateTree::get_state_proof(ctx, &table, serialized_key.clone())?;
287+
let value = self
288+
.run(|ctx| ctx.get_raw_value(table, &serialized_key))
289+
.map(|value| key.value::<Serde>(value));
290+
Ok((value, proof))
291+
})
292+
}
271293
}

core/interfaces/src/application.rs

+9
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ use lightning_types::{
1313
ChainId,
1414
Committee,
1515
NodeIndex,
16+
StateProofKey,
17+
StateProofValue,
1618
TransactionRequest,
1719
TxHash,
1820
Value,
1921
};
22+
use merklize::trees::mpt::MptStateProof;
2023
use merklize::StateRootHash;
2124
use serde::{Deserialize, Serialize};
2225

@@ -191,6 +194,12 @@ pub trait SyncQueryRunnerInterface: Clone + Send + Sync + 'static {
191194

192195
/// Returns the state root hash from the application state.
193196
fn get_state_root(&self) -> Result<StateRootHash>;
197+
198+
/// Returns the state proof for a given key from the application state using the state tree.
199+
fn get_state_proof(
200+
&self,
201+
key: StateProofKey,
202+
) -> Result<(Option<StateProofValue>, MptStateProof)>;
194203
}
195204

196205
#[derive(Clone, Debug)]

core/rpc/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ reqwest.workspace = true
3232
once_cell = "1.19"
3333
clap = { version = "4.4.10", features = ["derive"] }
3434

35+
lightning-application = { path = "../application" }
3536
lightning-firewall = { path = "../firewall" }
3637
lightning-types = { path = "../types" }
3738
lightning-interfaces = { path = "../interfaces" }
@@ -52,7 +53,6 @@ hex = "0.4.3"
5253
[dev-dependencies]
5354
reqwest.workspace = true
5455
lightning-test-utils = { path = "../test-utils" }
55-
lightning-application = { path = "../application" }
5656
lightning-fetcher = { path = "../fetcher" }
5757
lightning-blockstore = { path = "../blockstore" }
5858
lightning-blockstore-server = { path = "../blockstore-server" }

core/rpc/src/api/flk.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use fleek_crypto::{EthAddress, NodePublicKey};
44
use hp_fixed::unsigned::HpUfixed;
55
use jsonrpsee::core::{RpcResult, SubscriptionResult};
66
use jsonrpsee::proc_macros::rpc;
7+
use lightning_application::env::ApplicationStateTree;
78
use lightning_interfaces::types::{
89
AccountInfo,
910
Blake3Hash,
@@ -23,7 +24,8 @@ use lightning_interfaces::types::{
2324
};
2425
use lightning_interfaces::PagingParams;
2526
use lightning_openrpc_macros::open_rpc;
26-
use merklize::StateRootHash;
27+
use lightning_types::{StateProofKey, StateProofValue};
28+
use merklize::{StateRootHash, StateTree};
2729

2830
#[open_rpc(namespace = "flk", tag = "1.0.0")]
2931
#[rpc(client, server, namespace = "flk")]
@@ -189,6 +191,16 @@ pub trait FleekApi {
189191
#[method(name = "get_state_root")]
190192
async fn get_state_root(&self, epoch: Option<u64>) -> RpcResult<StateRootHash>;
191193

194+
#[method(name = "get_state_proof")]
195+
async fn get_state_proof(
196+
&self,
197+
key: StateProofKey,
198+
epoch: Option<u64>,
199+
) -> RpcResult<(
200+
Option<StateProofValue>,
201+
<ApplicationStateTree as StateTree>::Proof,
202+
)>;
203+
192204
#[method(name = "send_txn")]
193205
async fn send_txn(&self, tx: TransactionRequest) -> RpcResult<()>;
194206

core/rpc/src/logic/flk_impl.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use fleek_crypto::{EthAddress, NodePublicKey};
55
use hp_fixed::unsigned::HpUfixed;
66
use jsonrpsee::core::{RpcResult, SubscriptionResult};
77
use jsonrpsee::{PendingSubscriptionSink, SubscriptionMessage};
8+
use lightning_application::env::ApplicationStateTree;
89
use lightning_interfaces::prelude::*;
910
use lightning_interfaces::types::{
1011
AccountInfo,
@@ -29,8 +30,9 @@ use lightning_interfaces::types::{
2930
Value,
3031
};
3132
use lightning_interfaces::PagingParams;
33+
use lightning_types::{StateProofKey, StateProofValue};
3234
use lightning_utils::application::QueryRunnerExt;
33-
use merklize::StateRootHash;
35+
use merklize::{StateRootHash, StateTree};
3436

3537
use crate::api::FleekApiServer;
3638
use crate::error::RPCError;
@@ -388,6 +390,7 @@ impl<C: Collection> FleekApiServer for FleekApi<C> {
388390
Ok((sub_dag_index, self.data.query_runner.get_epoch_info().epoch))
389391
}
390392

393+
/// Returns the state root for the given epoch.
391394
async fn get_state_root(&self, epoch: Option<u64>) -> RpcResult<StateRootHash> {
392395
Ok(self
393396
.data
@@ -397,6 +400,24 @@ impl<C: Collection> FleekApiServer for FleekApi<C> {
397400
.map_err(|e| RPCError::custom(e.to_string()))?)
398401
}
399402

403+
/// Returns the state proof for a given key and epoch.
404+
async fn get_state_proof(
405+
&self,
406+
key: StateProofKey,
407+
epoch: Option<u64>,
408+
) -> RpcResult<(
409+
Option<StateProofValue>,
410+
<ApplicationStateTree as StateTree>::Proof,
411+
)> {
412+
let (value, proof) = self
413+
.data
414+
.query_runner(epoch)
415+
.await?
416+
.get_state_proof(key)
417+
.map_err(|e| RPCError::custom(e.to_string()))?;
418+
Ok((value, proof))
419+
}
420+
400421
async fn send_txn(&self, tx: TransactionRequest) -> RpcResult<()> {
401422
Ok(self
402423
.data

core/rpc/src/tests.rs

+68-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use hp_fixed::unsigned::HpUfixed;
1313
use jsonrpsee::http_client::{HttpClient, HttpClientBuilder};
1414
use lightning_application::app::Application;
1515
use lightning_application::config::Config as AppConfig;
16+
use lightning_application::env::ApplicationStateTree;
1617
use lightning_application::genesis::{Genesis, GenesisAccount, GenesisNode, GenesisNodeServed};
1718
use lightning_application::state::QueryRunner;
1819
use lightning_blockstore::blockstore::Blockstore;
@@ -38,8 +39,9 @@ use lightning_rep_collector::ReputationAggregator;
3839
use lightning_signer::Signer;
3940
use lightning_test_utils::json_config::JsonConfigProvider;
4041
use lightning_test_utils::keys::EphemeralKeystore;
41-
use lightning_types::FirewallConfig;
42+
use lightning_types::{AccountInfo, FirewallConfig, StateProofKey, StateProofValue};
4243
use lightning_utils::application::QueryRunnerExt;
44+
use merklize::StateProof;
4345
use reqwest::Client;
4446
use resolved_pathbuf::ResolvedPathBuf;
4547
use serde::{Deserialize, Serialize};
@@ -1181,3 +1183,68 @@ async fn test_rpc_get_state_root() -> Result<()> {
11811183
node.shutdown().await;
11821184
Ok(())
11831185
}
1186+
1187+
#[tokio::test(flavor = "multi_thread")]
1188+
async fn test_rpc_get_state_proof() -> Result<()> {
1189+
let temp_dir = tempdir()?;
1190+
1191+
// Create keys
1192+
let owner_secret_key = AccountOwnerSecretKey::generate();
1193+
let owner_public_key = owner_secret_key.to_pk();
1194+
let owner_eth_address: EthAddress = owner_public_key.into();
1195+
1196+
// Init application service
1197+
let mut genesis = Genesis::default();
1198+
genesis.account.push(GenesisAccount {
1199+
public_key: owner_public_key.into(),
1200+
flk_balance: 1000u64.into(),
1201+
stables_balance: 0,
1202+
bandwidth_balance: 0,
1203+
});
1204+
1205+
let genesis_path = genesis
1206+
.write_to_dir(temp_dir.path().to_path_buf().try_into().unwrap())
1207+
.unwrap();
1208+
1209+
let port = 30025;
1210+
let node = init_rpc(&temp_dir, genesis_path, port).await;
1211+
1212+
wait_for_server_start(port).await?;
1213+
1214+
let client = RpcClient::new_no_auth(&format!("http://127.0.0.1:{port}/rpc/v0"))?;
1215+
let state_key = StateProofKey::Accounts(owner_eth_address);
1216+
let (value, proof) =
1217+
FleekApiClient::get_state_proof(&client, StateProofKey::Accounts(owner_eth_address), None)
1218+
.await?;
1219+
1220+
assert!(value.is_some());
1221+
let value = value.unwrap();
1222+
assert_eq!(
1223+
value.clone(),
1224+
StateProofValue::Accounts(AccountInfo {
1225+
flk_balance: 1000u64.into(),
1226+
stables_balance: HpUfixed::zero(),
1227+
bandwidth_balance: 0,
1228+
nonce: 0,
1229+
})
1230+
);
1231+
1232+
// Verify proof.
1233+
let root_hash = FleekApiClient::get_state_root(&client, None).await?;
1234+
proof
1235+
.verify_membership::<_, _, ApplicationStateTree>(
1236+
state_key.table(),
1237+
owner_eth_address,
1238+
AccountInfo {
1239+
flk_balance: 1000u64.into(),
1240+
stables_balance: HpUfixed::zero(),
1241+
bandwidth_balance: 0,
1242+
nonce: 0,
1243+
},
1244+
root_hash,
1245+
)
1246+
.unwrap();
1247+
1248+
node.shutdown().await;
1249+
Ok(())
1250+
}

core/types/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77

88
[dependencies]
99
anyhow.workspace = true
10+
atomo.workspace = true
1011
cid.workspace = true
1112
serde.workspace = true
1213
ink-quill.workspace = true

core/types/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod reputation;
1818
mod response;
1919
mod rpc;
2020
mod state;
21+
mod state_proof;
2122
mod transaction;
2223

2324
pub use application::*;
@@ -38,6 +39,7 @@ pub use reputation::*;
3839
pub use response::*;
3940
pub use rpc::*;
4041
pub use state::*;
42+
pub use state_proof::*;
4143
pub use transaction::*;
4244

4345
/// The physical address of a node where it can be reached, the port numbers are

core/types/src/state.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ impl Tokens {
3737
}
3838
}
3939

40-
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default, schemars::JsonSchema)]
40+
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default, schemars::JsonSchema)]
4141
pub struct NodeServed {
4242
pub served: CommodityServed,
4343
pub stables_revenue: HpUfixed<6>,
4444
}
4545

46-
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default, schemars::JsonSchema)]
46+
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default, schemars::JsonSchema)]
4747
pub struct TotalServed {
4848
pub served: CommodityServed,
4949
pub reward_pool: HpUfixed<6>,
@@ -75,14 +75,14 @@ pub enum CommodityTypes {
7575
Gpu = 2,
7676
}
7777

78-
#[derive(Clone, Debug, Hash, Serialize, Deserialize, schemars::JsonSchema)]
78+
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
7979
pub struct ReportedReputationMeasurements {
8080
pub reporting_node: NodeIndex,
8181
pub measurements: ReputationMeasurements,
8282
}
8383

8484
/// Metadata, state stored in the blockchain that applies to the current block
85-
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
85+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, schemars::JsonSchema)]
8686
pub enum Metadata {
8787
ChainId,
8888
Epoch,
@@ -100,7 +100,7 @@ pub enum Metadata {
100100
}
101101

102102
/// The Value enum is a data type used to represent values in a key-value pair for a metadata table
103-
#[derive(Serialize, Deserialize, Debug, Clone)]
103+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
104104
pub enum Value {
105105
ChainId(u32),
106106
Epoch(u64),
@@ -378,7 +378,19 @@ pub struct Service {
378378
pub slashing: (),
379379
}
380380

381-
#[derive(Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, Clone, Default)]
381+
#[derive(
382+
Debug,
383+
Hash,
384+
PartialEq,
385+
PartialOrd,
386+
Ord,
387+
Eq,
388+
Serialize,
389+
Deserialize,
390+
Clone,
391+
Default,
392+
schemars::JsonSchema,
393+
)]
382394
pub struct Committee {
383395
pub members: Vec<NodeIndex>,
384396
pub ready_to_change: Vec<NodeIndex>,

0 commit comments

Comments
 (0)