Skip to content

Commit

Permalink
Merge branch 'master' into feat--add-near-calls-nonce
Browse files Browse the repository at this point in the history
  • Loading branch information
frdomovic authored Dec 19, 2024
2 parents c140917 + 55e713b commit e599196
Show file tree
Hide file tree
Showing 11 changed files with 602 additions and 22 deletions.
17 changes: 14 additions & 3 deletions .github/workflows/cross-platform-install-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,24 @@ jobs:
echo "BRANCH_NAME=${{ github.ref_name }}" >> $GITHUB_ENV
fi
# Run the installation script
# Run the merod script
- name: Test installation script
run: |
curl -s https://raw.githubusercontent.com/calimero-network/core/${{ env.BRANCH_NAME }}/scripts/install.sh | bash
curl -s https://raw.githubusercontent.com/calimero-network/core/${{ env.BRANCH_NAME }}/scripts/install-merod.sh | bash
# Validate the binary installation
- name: Validate installation
- name: Validate merod installation
run: |
which merod
merod --version
# Run the meroctl script
- name: Test installation script
run: |
curl -s https://raw.githubusercontent.com/calimero-network/core/${{ env.BRANCH_NAME }}/scripts/install-meroctl.sh | bash
# Validate the binary installation
- name: Validate meroctl installation
run: |
which meroctl
meroctl --version
22 changes: 21 additions & 1 deletion crates/context/config/src/client/env/proxy/query.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use active_proposals::ActiveProposalRequest;
use context_storage_entries::ContextStorageEntriesRequest;
use context_variable::ContextVariableRequest;
use proposal::ProposalRequest;
use proposal_approvals::ProposalApprovalsRequest;
use proposal_approvers::ProposalApproversRequest;
Expand All @@ -8,10 +10,12 @@ use crate::client::env::utils;
use crate::client::transport::Transport;
use crate::client::{CallClient, ClientError, Operation};
use crate::repr::Repr;
use crate::types::ContextIdentity;
use crate::types::{ContextIdentity, ContextStorageEntry};
use crate::{Proposal, ProposalId, ProposalWithApprovals};

mod active_proposals;
mod context_storage_entries;
mod context_variable;
mod proposal;
mod proposal_approvals;
mod proposal_approvers;
Expand Down Expand Up @@ -73,4 +77,20 @@ impl<'a, T: Transport> ContextProxyQuery<'a, T> {

utils::send(&self.client, Operation::Read(params)).await
}

pub async fn get_context_value(&self, key: Vec<u8>) -> Result<Vec<u8>, ClientError<T>> {
let params = ContextVariableRequest { key };

utils::send(&self.client, Operation::Read(params)).await
}

pub async fn get_context_storage_entries(
&self,
offset: usize,
limit: usize,
) -> Result<Vec<ContextStorageEntry>, ClientError<T>> {
let params = ContextStorageEntriesRequest { offset, limit };

utils::send(&self.client, Operation::Read(params)).await
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use candid::{Decode, Encode};
use serde::Serialize;
use starknet::core::codec::{Decode as StarknetDecode, Encode as StarknetEncode};
use starknet_crypto::Felt;

use crate::client::env::proxy::starknet::{
CallData, ContextStorageEntriesResponse, StarknetContextStorageEntriesRequest,
};
use crate::client::env::Method;
use crate::client::protocol::icp::Icp;
use crate::client::protocol::near::Near;
use crate::client::protocol::starknet::Starknet;
use crate::types::ContextStorageEntry;

#[derive(Clone, Debug, Serialize)]
pub(super) struct ContextStorageEntriesRequest {
pub(super) offset: usize,
pub(super) limit: usize,
}

impl Method<Near> for ContextStorageEntriesRequest {
const METHOD: &'static str = "context_storage_entries";

type Returns = Vec<ContextStorageEntry>;

fn encode(self) -> eyre::Result<Vec<u8>> {
serde_json::to_vec(&self).map_err(Into::into)
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
// Decode the response as Vec of tuples with boxed slices
let entries: Vec<(Box<[u8]>, Box<[u8]>)> = serde_json::from_slice(&response)
.map_err(|e| eyre::eyre!("Failed to decode response: {}", e))?;

// Convert to ContextStorageEntry
Ok(entries
.into_iter()
.map(|(key, value)| ContextStorageEntry {
key: key.into(),
value: value.into(),
})
.collect())
}
}

impl Method<Starknet> for ContextStorageEntriesRequest {
const METHOD: &'static str = "context_storage_entries";

type Returns = Vec<ContextStorageEntry>;

fn encode(self) -> eyre::Result<Vec<u8>> {
let req = StarknetContextStorageEntriesRequest {
offset: Felt::from(self.offset as u64),
length: Felt::from(self.limit as u64),
};
let mut call_data = CallData::default();
req.encode(&mut call_data)?;
Ok(call_data.0)
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
if response.is_empty() {
return Ok(vec![]);
}

// Convert bytes to Felts
let chunks = response.chunks_exact(32);
let felts: Vec<Felt> = chunks
.map(|chunk| {
let chunk_array: [u8; 32] = chunk
.try_into()
.map_err(|e| eyre::eyre!("Failed to convert chunk to array: {}", e))?;
Ok(Felt::from_bytes_be(&chunk_array))
})
.collect::<eyre::Result<Vec<Felt>>>()?;

let response = ContextStorageEntriesResponse::decode_iter(&mut felts.iter())?;

Ok(response.entries.into_iter().map(Into::into).collect())
}
}

impl Method<Icp> for ContextStorageEntriesRequest {
const METHOD: &'static str = "context_storage_entries";

type Returns = Vec<ContextStorageEntry>;

fn encode(self) -> eyre::Result<Vec<u8>> {
// Encode offset and limit using Candid
Encode!(&self.offset, &self.limit)
.map_err(|e| eyre::eyre!("Failed to encode request: {}", e))
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
// Decode the response as Vec of tuples
let entries: Vec<(Vec<u8>, Vec<u8>)> = Decode!(&response, Vec<(Vec<u8>, Vec<u8>)>)
.map_err(|e| eyre::eyre!("Failed to decode response: {}", e))?;

// Convert to ContextStorageEntry
Ok(entries
.into_iter()
.map(|(key, value)| ContextStorageEntry { key, value })
.collect())
}
}
102 changes: 102 additions & 0 deletions crates/context/config/src/client/env/proxy/query/context_variable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use candid::{Decode, Encode};
use serde::Serialize;
use starknet::core::codec::Encode as StarknetEncode;
use starknet_crypto::Felt;

use crate::client::env::proxy::starknet::{CallData, ContextVariableKey};
use crate::client::env::Method;
use crate::client::protocol::icp::Icp;
use crate::client::protocol::near::Near;
use crate::client::protocol::starknet::Starknet;
use crate::icp::repr::ICRepr;

#[derive(Clone, Debug, Serialize)]
pub(super) struct ContextVariableRequest {
pub(super) key: Vec<u8>,
}

impl Method<Near> for ContextVariableRequest {
const METHOD: &'static str = "get_context_value";

type Returns = Vec<u8>;

fn encode(self) -> eyre::Result<Vec<u8>> {
serde_json::to_vec(&self).map_err(Into::into)
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
serde_json::from_slice(&response).map_err(Into::into)
}
}

impl Method<Starknet> for ContextVariableRequest {
const METHOD: &'static str = "get_context_value";

type Returns = Vec<u8>;

fn encode(self) -> eyre::Result<Vec<u8>> {
let mut call_data = CallData::default();
let key: ContextVariableKey = self.key.into();
key.encode(&mut call_data)?;

Ok(call_data.0)
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
if response.is_empty() {
return Ok(vec![]);
}

let chunks = response.chunks_exact(32);
let felts: Vec<Felt> = chunks
.map(|chunk| {
let chunk_array: [u8; 32] = chunk
.try_into()
.map_err(|e| eyre::eyre!("Failed to convert chunk to array: {}", e))?;
Ok(Felt::from_bytes_be(&chunk_array))
})
.collect::<eyre::Result<Vec<Felt>>>()?;

if felts.is_empty() {
return Ok(vec![]);
}

// First felt is the discriminant (0 for None, 1 for Some)
match felts[0] {
f if f == Felt::ZERO => {
println!(
"First few bytes after discriminant: {:?}",
&response[32..40]
);

// Skip first 64 bytes (discriminant + length) and filter nulls
Ok(response[64..]
.iter()
.filter(|&&b| b != 0)
.copied()
.collect())
}
v => Err(eyre::eyre!("Invalid option discriminant: {}", v)),
}
}
}

impl Method<Icp> for ContextVariableRequest {
const METHOD: &'static str = "get_context_value";

type Returns = Vec<u8>;

fn encode(self) -> eyre::Result<Vec<u8>> {
// Convert the key to ICRepr
let payload = ICRepr::new(self.key);
// Use candid's Encode macro to serialize the data
Encode!(&payload).map_err(Into::into)
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
// Use candid's Decode macro to deserialize the response
// The response will be an Option<Vec<u8>>
let decoded = Decode!(&response, Vec<u8>)?;
Ok(decoded)
}
}
Loading

0 comments on commit e599196

Please sign in to comment.