Skip to content

Commit 81d36c8

Browse files
authored
Feat add context variable fetching functionalities (#1018)
1 parent ee20c8a commit 81d36c8

File tree

8 files changed

+538
-30
lines changed

8 files changed

+538
-30
lines changed

crates/context/config/src/client/env/proxy/query.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use active_proposals::ActiveProposalRequest;
2+
use context_storage_entries::ContextStorageEntriesRequest;
3+
use context_variable::ContextVariableRequest;
24
use proposal::ProposalRequest;
35
use proposal_approvals::ProposalApprovalsRequest;
46
use proposal_approvers::ProposalApproversRequest;
@@ -8,10 +10,12 @@ use crate::client::env::utils;
810
use crate::client::transport::Transport;
911
use crate::client::{CallClient, ClientError, Operation};
1012
use crate::repr::Repr;
11-
use crate::types::ContextIdentity;
13+
use crate::types::{ContextIdentity, ContextStorageEntry};
1214
use crate::{Proposal, ProposalId, ProposalWithApprovals};
1315

1416
mod active_proposals;
17+
mod context_storage_entries;
18+
mod context_variable;
1519
mod proposal;
1620
mod proposal_approvals;
1721
mod proposal_approvers;
@@ -73,4 +77,20 @@ impl<'a, T: Transport> ContextProxyQuery<'a, T> {
7377

7478
utils::send(&self.client, Operation::Read(params)).await
7579
}
80+
81+
pub async fn get_context_value(&self, key: Vec<u8>) -> Result<Vec<u8>, ClientError<T>> {
82+
let params = ContextVariableRequest { key };
83+
84+
utils::send(&self.client, Operation::Read(params)).await
85+
}
86+
87+
pub async fn get_context_storage_entries(
88+
&self,
89+
offset: usize,
90+
limit: usize,
91+
) -> Result<Vec<ContextStorageEntry>, ClientError<T>> {
92+
let params = ContextStorageEntriesRequest { offset, limit };
93+
94+
utils::send(&self.client, Operation::Read(params)).await
95+
}
7696
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use candid::{Decode, Encode};
2+
use serde::Serialize;
3+
use starknet::core::codec::{Decode as StarknetDecode, Encode as StarknetEncode};
4+
use starknet_crypto::Felt;
5+
6+
use crate::client::env::proxy::starknet::{
7+
CallData, ContextStorageEntriesResponse, StarknetContextStorageEntriesRequest,
8+
};
9+
use crate::client::env::Method;
10+
use crate::client::protocol::icp::Icp;
11+
use crate::client::protocol::near::Near;
12+
use crate::client::protocol::starknet::Starknet;
13+
use crate::types::ContextStorageEntry;
14+
15+
#[derive(Clone, Debug, Serialize)]
16+
pub(super) struct ContextStorageEntriesRequest {
17+
pub(super) offset: usize,
18+
pub(super) limit: usize,
19+
}
20+
21+
impl Method<Near> for ContextStorageEntriesRequest {
22+
const METHOD: &'static str = "context_storage_entries";
23+
24+
type Returns = Vec<ContextStorageEntry>;
25+
26+
fn encode(self) -> eyre::Result<Vec<u8>> {
27+
serde_json::to_vec(&self).map_err(Into::into)
28+
}
29+
30+
fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
31+
// Decode the response as Vec of tuples with boxed slices
32+
let entries: Vec<(Box<[u8]>, Box<[u8]>)> = serde_json::from_slice(&response)
33+
.map_err(|e| eyre::eyre!("Failed to decode response: {}", e))?;
34+
35+
// Convert to ContextStorageEntry
36+
Ok(entries
37+
.into_iter()
38+
.map(|(key, value)| ContextStorageEntry {
39+
key: key.into(),
40+
value: value.into(),
41+
})
42+
.collect())
43+
}
44+
}
45+
46+
impl Method<Starknet> for ContextStorageEntriesRequest {
47+
const METHOD: &'static str = "context_storage_entries";
48+
49+
type Returns = Vec<ContextStorageEntry>;
50+
51+
fn encode(self) -> eyre::Result<Vec<u8>> {
52+
let req = StarknetContextStorageEntriesRequest {
53+
offset: Felt::from(self.offset as u64),
54+
length: Felt::from(self.limit as u64),
55+
};
56+
let mut call_data = CallData::default();
57+
req.encode(&mut call_data)?;
58+
Ok(call_data.0)
59+
}
60+
61+
fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
62+
if response.is_empty() {
63+
return Ok(vec![]);
64+
}
65+
66+
// Convert bytes to Felts
67+
let chunks = response.chunks_exact(32);
68+
let felts: Vec<Felt> = chunks
69+
.map(|chunk| {
70+
let chunk_array: [u8; 32] = chunk
71+
.try_into()
72+
.map_err(|e| eyre::eyre!("Failed to convert chunk to array: {}", e))?;
73+
Ok(Felt::from_bytes_be(&chunk_array))
74+
})
75+
.collect::<eyre::Result<Vec<Felt>>>()?;
76+
77+
let response = ContextStorageEntriesResponse::decode_iter(&mut felts.iter())?;
78+
79+
Ok(response.entries.into_iter().map(Into::into).collect())
80+
}
81+
}
82+
83+
impl Method<Icp> for ContextStorageEntriesRequest {
84+
const METHOD: &'static str = "context_storage_entries";
85+
86+
type Returns = Vec<ContextStorageEntry>;
87+
88+
fn encode(self) -> eyre::Result<Vec<u8>> {
89+
// Encode offset and limit using Candid
90+
Encode!(&self.offset, &self.limit)
91+
.map_err(|e| eyre::eyre!("Failed to encode request: {}", e))
92+
}
93+
94+
fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
95+
// Decode the response as Vec of tuples
96+
let entries: Vec<(Vec<u8>, Vec<u8>)> = Decode!(&response, Vec<(Vec<u8>, Vec<u8>)>)
97+
.map_err(|e| eyre::eyre!("Failed to decode response: {}", e))?;
98+
99+
// Convert to ContextStorageEntry
100+
Ok(entries
101+
.into_iter()
102+
.map(|(key, value)| ContextStorageEntry { key, value })
103+
.collect())
104+
}
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use candid::{Decode, Encode};
2+
use serde::Serialize;
3+
use starknet::core::codec::Encode as StarknetEncode;
4+
use starknet_crypto::Felt;
5+
6+
use crate::client::env::proxy::starknet::{CallData, ContextVariableKey};
7+
use crate::client::env::Method;
8+
use crate::client::protocol::icp::Icp;
9+
use crate::client::protocol::near::Near;
10+
use crate::client::protocol::starknet::Starknet;
11+
use crate::icp::repr::ICRepr;
12+
13+
#[derive(Clone, Debug, Serialize)]
14+
pub(super) struct ContextVariableRequest {
15+
pub(super) key: Vec<u8>,
16+
}
17+
18+
impl Method<Near> for ContextVariableRequest {
19+
const METHOD: &'static str = "get_context_value";
20+
21+
type Returns = Vec<u8>;
22+
23+
fn encode(self) -> eyre::Result<Vec<u8>> {
24+
serde_json::to_vec(&self).map_err(Into::into)
25+
}
26+
27+
fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
28+
serde_json::from_slice(&response).map_err(Into::into)
29+
}
30+
}
31+
32+
impl Method<Starknet> for ContextVariableRequest {
33+
const METHOD: &'static str = "get_context_value";
34+
35+
type Returns = Vec<u8>;
36+
37+
fn encode(self) -> eyre::Result<Vec<u8>> {
38+
let mut call_data = CallData::default();
39+
let key: ContextVariableKey = self.key.into();
40+
key.encode(&mut call_data)?;
41+
42+
Ok(call_data.0)
43+
}
44+
45+
fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
46+
if response.is_empty() {
47+
return Ok(vec![]);
48+
}
49+
50+
let chunks = response.chunks_exact(32);
51+
let felts: Vec<Felt> = chunks
52+
.map(|chunk| {
53+
let chunk_array: [u8; 32] = chunk
54+
.try_into()
55+
.map_err(|e| eyre::eyre!("Failed to convert chunk to array: {}", e))?;
56+
Ok(Felt::from_bytes_be(&chunk_array))
57+
})
58+
.collect::<eyre::Result<Vec<Felt>>>()?;
59+
60+
if felts.is_empty() {
61+
return Ok(vec![]);
62+
}
63+
64+
// First felt is the discriminant (0 for None, 1 for Some)
65+
match felts[0] {
66+
f if f == Felt::ZERO => {
67+
println!(
68+
"First few bytes after discriminant: {:?}",
69+
&response[32..40]
70+
);
71+
72+
// Skip first 64 bytes (discriminant + length) and filter nulls
73+
Ok(response[64..]
74+
.iter()
75+
.filter(|&&b| b != 0)
76+
.copied()
77+
.collect())
78+
}
79+
v => Err(eyre::eyre!("Invalid option discriminant: {}", v)),
80+
}
81+
}
82+
}
83+
84+
impl Method<Icp> for ContextVariableRequest {
85+
const METHOD: &'static str = "get_context_value";
86+
87+
type Returns = Vec<u8>;
88+
89+
fn encode(self) -> eyre::Result<Vec<u8>> {
90+
// Convert the key to ICRepr
91+
let payload = ICRepr::new(self.key);
92+
// Use candid's Encode macro to serialize the data
93+
Encode!(&payload).map_err(Into::into)
94+
}
95+
96+
fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
97+
// Use candid's Decode macro to deserialize the response
98+
// The response will be an Option<Vec<u8>>
99+
let decoded = Decode!(&response, Vec<u8>)?;
100+
Ok(decoded)
101+
}
102+
}

0 commit comments

Comments
 (0)