merge `blob` and `values`

This commit is contained in:
Ryan Heywood 2024-12-20 17:22:49 -05:00
parent f09fb4dd59
commit b6e798a9ad
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
4 changed files with 32 additions and 31 deletions

View File

@ -157,11 +157,13 @@ pub struct TransferToken {
#[derive(Serialize, Deserialize, Debug)]
pub struct Sign {
blockhash: String,
transaction: solana_sdk::transaction::Transaction,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Broadcast {
cluster: Option<Cluster>,
transaction: solana_sdk::transaction::Transaction,
}
#[derive(Serialize, Deserialize, Debug)]
@ -170,9 +172,6 @@ pub struct Request {
// and adds in its own derivation constructs that cause type conflicts.
derived_keys: Option<Vec<[u8; 32]>>,
// NOTE: This is an opaque type that can be deserialized inside an Operation
blob: Option<serde_json::Value>,
#[serde(flatten)]
operation: Operation,
}
@ -624,13 +623,7 @@ impl Module for Solana {
"derivation_accounts": [0u32 | 1 << 31],
}))
}
Operation::Sign(Sign { blockhash }) => {
let transaction = request
.blob
.and_then(|b| b.get("transaction").cloned())
.expect("was given transaction");
let mut transaction: solana_sdk::transaction::Transaction =
serde_json::from_value(transaction).expect("valid message blob");
Operation::Sign(Sign { blockhash, mut transaction }) => {
let keys = request
.derived_keys
.unwrap_or_default()
@ -648,16 +641,10 @@ impl Module for Solana {
}
}))
}
Operation::Broadcast(Broadcast { cluster }) => {
Operation::Broadcast(Broadcast { cluster, transaction }) => {
let cluster = cluster.unwrap_or(Cluster::MainnetBeta);
let cluster_url = format!("https://api.{cluster}.solana.com");
let transaction = request
.blob
.and_then(|b| b.get("transaction").cloned())
.expect("was given transaction");
let transaction: solana_sdk::transaction::Transaction =
serde_json::from_value(transaction).expect("valid message blob");
transaction.verify().expect("invalid signatures");
let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url);
let _simulated_response = client.simulate_transaction(&transaction).unwrap();

View File

@ -2,6 +2,7 @@ use clap::command;
use icepick_module::help::*;
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
io::{IsTerminal, Write},
process::{Command, Stdio},
};
@ -168,6 +169,7 @@ pub fn do_cli_thing() {
if !stdin.is_terminal() {
cli_input = serde_json::from_reader(stdin).ok();
}
// TODO: should we rename "blob"?
let blob = cli_input.as_ref().and_then(|json| json.get("blob"));
let derivation_accounts = cli_input
@ -182,14 +184,20 @@ pub fn do_cli_thing() {
.find(|(name, ..)| *name == module)
.and_then(|(.., operations)| operations.iter().find(|o| o.name == subcommand))
{
let mut args = std::collections::HashMap::<String, Option<&String>>::with_capacity(
operation.arguments.len(),
);
// all values to be passed to the command
let mut args =
HashMap::<String, serde_json::Value>::with_capacity(operation.arguments.len());
// add the values from piped input, if any
if let Some(serde_json::Value::Object(blob)) = blob {
args.extend(blob.iter().map(|(k, v)| (k.clone(), v.clone())));
}
// add the values from CLI arguments
for arg in &operation.arguments {
args.insert(
arg.name.clone(),
matches.get_one::<String>(&arg.name.replace('_', "-")),
);
if let Some(value) = matches.get_one::<String>(&arg.name.replace('_', "-")) {
args.insert(arg.name.clone(), serde_json::Value::String(value.clone()));
}
}
let (algo, path) = config
@ -235,7 +243,6 @@ pub fn do_cli_thing() {
"operation": subcommand,
"values": args,
"derived_keys": derived_keys,
"blob": blob,
});
let bin = commands
.iter()

View File

@ -82,22 +82,23 @@ impl Workflow {
map
}
pub fn simulate_workflow(&self, mut data: HashSet<String>, operations: &[InvocableOperation]) {
fn simulate_workflow(&self, mut data: HashSet<String>, operations: &[InvocableOperation]) {
// simulate the steps by using a HashSet to traverse the inputs and outputs and ensure
// there's no inconsistencies
for (i, step) in self.steps.iter().enumerate() {
// NOTE: overflow possible but unlikely
let step_index = i + 1;
let step_type = &step.r#type;
// Find the relevant Operation
let Some(invocable) = operations.iter().find(|op| op.name == step.r#type) else {
panic!("Could not find operation: {}", step.r#type);
let Some(invocable) = operations.iter().find(|op| op.name == *step_type) else {
panic!("Could not find operation: {step_type}");
};
// Check if we have the keys we want to pass into the module.
for in_memory_name in step.inputs.values() {
if !data.contains(in_memory_name) && !step.values.contains_key(in_memory_name) {
panic!("Failed simulation: step #{step_index}: missing value {in_memory_name}");
panic!("Failed simulation: step #{step_index} ({step_type}): missing value {in_memory_name}");
}
}
@ -109,7 +110,7 @@ impl Workflow {
.iter()
.any(|arg| *module_input_name == arg.name)
{
eprintln!("Simulation: step #{step_index}: input value {module_input_name} will be passed through as JSON input");
eprintln!("Simulation: step #{step_index} ({step_type}): input value {module_input_name} will be passed through as JSON input");
}
}

View File

@ -59,13 +59,19 @@ from_address = "from_address"
[module.workflow.step.outputs]
transaction = "unsigned_transaction"
# Get a blockhash
[[module.workflow.step]]
type = "sol-get-blockhash"
outputs = { blockhash = "blockhash" }
# Sign the transaction
[[module.workflow.step]]
type = "sol-sign"
[module.workflow.step.inputs]
transaction = "unsigned_transaction"
# blockhash = "blockhash"
blockhash = "blockhash"
[module.workflow.step.outputs]
transaction = "signed_transaction"