add --cluster option to specify which cluster to send requests to

This commit is contained in:
Ryan Heywood 2024-11-29 00:18:45 -05:00
parent 14f0be8921
commit 6703a5b3ce
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
1 changed files with 41 additions and 13 deletions

View File

@ -14,7 +14,27 @@ pub enum Error {}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct GetBlockhash {} pub enum Cluster {
Devnet,
Testnet,
Mainnet,
}
impl std::fmt::Display for Cluster {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Cluster::Devnet => f.write_str("devnet"),
Cluster::Testnet => f.write_str("testnet"),
Cluster::Mainnet => f.write_str("mainnet"),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct GetBlockhash {
cluster: Option<Cluster>,
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -45,7 +65,9 @@ pub struct Sign {}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct Broadcast {} pub struct Broadcast {
cluster: Option<Cluster>,
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -92,6 +114,11 @@ impl Module for Solana {
type Request = Request; type Request = Request;
fn describe_operations() -> Vec<icepick_module::help::Operation> { fn describe_operations() -> Vec<icepick_module::help::Operation> {
let cluster = Argument {
name: "cluster".to_string(),
description: "The cluster to interact with (mainnet, testnet, devnet)".to_string(),
r#type: ArgumentType::Optional,
};
let account = Argument { let account = Argument {
name: "from-account".to_string(), name: "from-account".to_string(),
description: "The derivation account used for the transaction.".to_string(), description: "The derivation account used for the transaction.".to_string(),
@ -130,7 +157,7 @@ impl Module for Solana {
icepick_module::help::Operation { icepick_module::help::Operation {
name: "get-blockhash".to_string(), name: "get-blockhash".to_string(),
description: "Get the latest blockhash".to_string(), description: "Get the latest blockhash".to_string(),
arguments: vec![], arguments: vec![cluster.clone()],
}, },
icepick_module::help::Operation { icepick_module::help::Operation {
name: "generate-wallet".to_string(), name: "generate-wallet".to_string(),
@ -195,16 +222,17 @@ impl Module for Solana {
icepick_module::help::Operation { icepick_module::help::Operation {
name: "broadcast".to_string(), name: "broadcast".to_string(),
description: "Broadcast a signed transaction".to_string(), description: "Broadcast a signed transaction".to_string(),
arguments: vec![], arguments: vec![cluster.clone()],
}, },
] ]
} }
fn handle_request(request: Self::Request) -> Result<serde_json::Value, Self::Error> { fn handle_request(request: Self::Request) -> Result<serde_json::Value, Self::Error> {
match request.operation { match request.operation {
Operation::GetBlockhash(_) => { Operation::GetBlockhash(GetBlockhash { cluster }) => {
let devnet = "https://api.devnet.solana.com"; let cluster = cluster.unwrap_or(Cluster::Mainnet);
let client = solana_rpc_client::rpc_client::RpcClient::new(devnet); let cluster_url = format!("https://api.{cluster}.solana.com");
let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url);
let response = client.get_latest_blockhash().unwrap(); let response = client.get_latest_blockhash().unwrap();
Ok(serde_json::json!({ Ok(serde_json::json!({
"blob": response.to_string(), "blob": response.to_string(),
@ -305,18 +333,18 @@ impl Module for Solana {
"blob": transaction, "blob": transaction,
})) }))
} }
Operation::Broadcast(_) => { Operation::Broadcast(Broadcast { cluster }) => {
let cluster = cluster.unwrap_or(Cluster::Mainnet);
let cluster_url = format!("https://api.{cluster}.solana.com");
let blob = request.blob.expect("passed in instruction blob"); let blob = request.blob.expect("passed in instruction blob");
let transaction: solana_sdk::transaction::Transaction = let transaction: solana_sdk::transaction::Transaction =
serde_json::from_value(blob).expect("valid message blob"); serde_json::from_value(blob).expect("valid message blob");
transaction.verify().expect("invalid signatures"); transaction.verify().expect("invalid signatures");
// TODO: make this a CLI option let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url);
let devnet = "https://api.devnet.solana.com";
let client = solana_rpc_client::rpc_client::RpcClient::new(devnet);
let _simulated_response = client.simulate_transaction(&transaction).unwrap(); let _simulated_response = client.simulate_transaction(&transaction).unwrap();
let response = client.send_and_confirm_transaction(&transaction); let response = client.send_and_confirm_transaction(&transaction);
Ok( Ok(match response {
match response {
Ok(s) => { Ok(s) => {
serde_json::json!({ serde_json::json!({
"blob": { "blob": {