Merge pull request #123 from vacp2p/schouhy/wallet-fetch-programs

Add wallet command to check program ids match the ones used by the node
This commit is contained in:
Sergio Chouhy 2025-10-20 17:44:40 -03:00 committed by GitHub
commit 348156043a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 98 additions and 7 deletions

View File

@ -1,8 +1,11 @@
use std::collections::HashMap;
use crate::parse_request;
use super::errors::RpcParseError;
use super::parser::RpcRequest;
use super::parser::parse_params;
use nssa_core::program::ProgramId;
use serde::{Deserialize, Serialize};
use serde_json::Value;
@ -58,6 +61,9 @@ pub struct GetProofForCommitmentRequest {
pub commitment: nssa_core::Commitment,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetProgramIdsRequest {}
parse_request!(HelloRequest);
parse_request!(RegisterAccountRequest);
parse_request!(SendTxRequest);
@ -70,6 +76,7 @@ parse_request!(GetTransactionByHashRequest);
parse_request!(GetAccountsNoncesRequest);
parse_request!(GetProofForCommitmentRequest);
parse_request!(GetAccountRequest);
parse_request!(GetProgramIdsRequest);
#[derive(Serialize, Deserialize, Debug)]
pub struct HelloResponse {
@ -126,3 +133,8 @@ pub struct GetAccountResponse {
pub struct GetProofForCommitmentResponse {
pub membership_proof: Option<nssa_core::MembershipProof>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetProgramIdsResponse {
pub program_ids: HashMap<String, ProgramId>,
}

View File

@ -1,16 +1,19 @@
use std::collections::HashMap;
use super::rpc_primitives::requests::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse,
GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest,
};
use anyhow::Result;
use json::{SendTxRequest, SendTxResponse, SequencerRpcRequest, SequencerRpcResponse};
use nssa_core::program::ProgramId;
use reqwest::Client;
use serde_json::Value;
use crate::rpc_primitives::requests::{
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest,
GetTransactionByHashResponse,
GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest,
GetProofForCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse,
};
use crate::sequencer_client::json::AccountInitialData;
use crate::transaction::{EncodedTransaction, NSSATransaction};
@ -237,4 +240,24 @@ impl SequencerClient {
Ok(resp_deser)
}
// Get Ids of the programs used by the node
pub async fn get_program_ids(
&self,
) -> Result<HashMap<String, ProgramId>, SequencerClientError> {
let acc_req = GetProgramIdsRequest {};
let req = serde_json::to_value(acc_req).unwrap();
let resp = self
.call_method_with_payload("get_program_ids", req)
.await
.unwrap();
let resp_deser = serde_json::from_value::<GetProgramIdsResponse>(resp)
.unwrap()
.program_ids;
Ok(resp_deser)
}
}

View File

@ -12,6 +12,7 @@ pub use nssa_core::address::Address;
pub use privacy_preserving_transaction::{
PrivacyPreservingTransaction, circuit::execute_and_prove,
};
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
pub use public_transaction::PublicTransaction;
pub use signature::PrivateKey;
pub use signature::PublicKey;

View File

@ -1,6 +1,8 @@
use std::collections::HashMap;
use actix_web::Error as HttpError;
use base64::{Engine, engine::general_purpose};
use nssa;
use nssa::{self, program::Program};
use sequencer_core::config::AccountInitialData;
use serde_json::Value;
@ -14,9 +16,9 @@ use common::{
requests::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest,
GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
GetInitialTestnetAccountsRequest, GetProofForCommitmentRequest,
GetProofForCommitmentResponse, GetTransactionByHashRequest,
GetTransactionByHashResponse,
GetInitialTestnetAccountsRequest, GetProgramIdsRequest, GetProgramIdsResponse,
GetProofForCommitmentRequest, GetProofForCommitmentResponse,
GetTransactionByHashRequest, GetTransactionByHashResponse,
},
},
transaction::EncodedTransaction,
@ -40,6 +42,7 @@ pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash";
pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces";
pub const GET_ACCOUNT: &str = "get_account";
pub const GET_PROOF_FOR_COMMITMENT: &str = "get_proof_for_commitment";
pub const GET_PROGRAM_IDS: &str = "get_program_ids";
pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER";
@ -267,6 +270,24 @@ impl JsonHandler {
respond(helperstruct)
}
async fn process_get_program_ids(&self, request: Request) -> Result<Value, RpcErr> {
let _get_proof_req = GetProgramIdsRequest::parse(Some(request.params))?;
let mut program_ids = HashMap::new();
program_ids.insert(
"authenticated_transfer".to_string(),
Program::authenticated_transfer_program().id(),
);
program_ids.insert("token".to_string(), Program::token().id());
program_ids.insert("pinata".to_string(), Program::pinata().id());
program_ids.insert(
"privacy_preserving_circuit".to_string(),
nssa::PRIVACY_PRESERVING_CIRCUIT_ID,
);
let helperstruct = GetProgramIdsResponse { program_ids };
respond(helperstruct)
}
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
match request.method.as_ref() {
HELLO => self.process_temp_hello(request).await,
@ -280,6 +301,7 @@ impl JsonHandler {
GET_ACCOUNT => self.process_get_account(request).await,
GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await,
GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await,
GET_PROGRAM_IDS => self.process_get_program_ids(request).await,
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
}
}

View File

@ -11,7 +11,7 @@ use anyhow::Result;
use chain_storage::WalletChainStore;
use config::WalletConfig;
use log::info;
use nssa::{Account, Address};
use nssa::{Account, Address, program::Program};
use clap::{Parser, Subcommand};
use nssa_core::{Commitment, MembershipProof};
@ -400,6 +400,9 @@ pub enum Command {
#[arg(long)]
solution: u128,
},
// Check the wallet can connect to the node and builtin local programs
// match the remote versions
CheckHealth {},
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize
ClaimPinataPrivateReceiverOwned {
@ -792,6 +795,36 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
SubcommandReturnValue::Empty
}
Command::CheckHealth {} => {
let remote_program_ids = wallet_core
.sequencer_client
.get_program_ids()
.await
.expect("Error fetching program ids");
let Some(authenticated_transfer_id) = remote_program_ids.get("authenticated_transfer")
else {
panic!("Missing authenticated transfer ID from remote");
};
if authenticated_transfer_id != &Program::authenticated_transfer_program().id() {
panic!("Local ID for authenticated transfer program is different from remote");
}
let Some(token_id) = remote_program_ids.get("token") else {
panic!("Missing token program ID from remote");
};
if token_id != &Program::token().id() {
panic!("Local ID for token program is different from remote");
}
let Some(circuit_id) = remote_program_ids.get("privacy_preserving_circuit") else {
panic!("Missing privacy preserving circuit ID from remote");
};
if circuit_id != &nssa::PRIVACY_PRESERVING_CIRCUIT_ID {
panic!("Local ID for privacy preserving circuit is different from remote");
}
println!("✅All looks good!");
SubcommandReturnValue::Empty
}
Command::ClaimPinataPrivateReceiverOwned {
pinata_addr,
winner_addr,