merge `blob` and `values`
This commit is contained in:
parent
f09fb4dd59
commit
b6e798a9ad
|
@ -157,11 +157,13 @@ pub struct TransferToken {
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Sign {
|
pub struct Sign {
|
||||||
blockhash: String,
|
blockhash: String,
|
||||||
|
transaction: solana_sdk::transaction::Transaction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Broadcast {
|
pub struct Broadcast {
|
||||||
cluster: Option<Cluster>,
|
cluster: Option<Cluster>,
|
||||||
|
transaction: solana_sdk::transaction::Transaction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
@ -170,9 +172,6 @@ pub struct Request {
|
||||||
// and adds in its own derivation constructs that cause type conflicts.
|
// and adds in its own derivation constructs that cause type conflicts.
|
||||||
derived_keys: Option<Vec<[u8; 32]>>,
|
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)]
|
#[serde(flatten)]
|
||||||
operation: Operation,
|
operation: Operation,
|
||||||
}
|
}
|
||||||
|
@ -624,13 +623,7 @@ impl Module for Solana {
|
||||||
"derivation_accounts": [0u32 | 1 << 31],
|
"derivation_accounts": [0u32 | 1 << 31],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Operation::Sign(Sign { blockhash }) => {
|
Operation::Sign(Sign { blockhash, mut transaction }) => {
|
||||||
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");
|
|
||||||
let keys = request
|
let keys = request
|
||||||
.derived_keys
|
.derived_keys
|
||||||
.unwrap_or_default()
|
.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 = cluster.unwrap_or(Cluster::MainnetBeta);
|
||||||
let cluster_url = format!("https://api.{cluster}.solana.com");
|
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");
|
transaction.verify().expect("invalid signatures");
|
||||||
let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url);
|
let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url);
|
||||||
let _simulated_response = client.simulate_transaction(&transaction).unwrap();
|
let _simulated_response = client.simulate_transaction(&transaction).unwrap();
|
||||||
|
|
|
@ -2,6 +2,7 @@ use clap::command;
|
||||||
use icepick_module::help::*;
|
use icepick_module::help::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
io::{IsTerminal, Write},
|
io::{IsTerminal, Write},
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
};
|
};
|
||||||
|
@ -168,6 +169,7 @@ pub fn do_cli_thing() {
|
||||||
if !stdin.is_terminal() {
|
if !stdin.is_terminal() {
|
||||||
cli_input = serde_json::from_reader(stdin).ok();
|
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 blob = cli_input.as_ref().and_then(|json| json.get("blob"));
|
||||||
|
|
||||||
let derivation_accounts = cli_input
|
let derivation_accounts = cli_input
|
||||||
|
@ -182,14 +184,20 @@ pub fn do_cli_thing() {
|
||||||
.find(|(name, ..)| *name == module)
|
.find(|(name, ..)| *name == module)
|
||||||
.and_then(|(.., operations)| operations.iter().find(|o| o.name == subcommand))
|
.and_then(|(.., operations)| operations.iter().find(|o| o.name == subcommand))
|
||||||
{
|
{
|
||||||
let mut args = std::collections::HashMap::<String, Option<&String>>::with_capacity(
|
// all values to be passed to the command
|
||||||
operation.arguments.len(),
|
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 {
|
for arg in &operation.arguments {
|
||||||
args.insert(
|
if let Some(value) = matches.get_one::<String>(&arg.name.replace('_', "-")) {
|
||||||
arg.name.clone(),
|
args.insert(arg.name.clone(), serde_json::Value::String(value.clone()));
|
||||||
matches.get_one::<String>(&arg.name.replace('_', "-")),
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (algo, path) = config
|
let (algo, path) = config
|
||||||
|
@ -235,7 +243,6 @@ pub fn do_cli_thing() {
|
||||||
"operation": subcommand,
|
"operation": subcommand,
|
||||||
"values": args,
|
"values": args,
|
||||||
"derived_keys": derived_keys,
|
"derived_keys": derived_keys,
|
||||||
"blob": blob,
|
|
||||||
});
|
});
|
||||||
let bin = commands
|
let bin = commands
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -82,22 +82,23 @@ impl Workflow {
|
||||||
map
|
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
|
// simulate the steps by using a HashSet to traverse the inputs and outputs and ensure
|
||||||
// there's no inconsistencies
|
// there's no inconsistencies
|
||||||
for (i, step) in self.steps.iter().enumerate() {
|
for (i, step) in self.steps.iter().enumerate() {
|
||||||
// NOTE: overflow possible but unlikely
|
// NOTE: overflow possible but unlikely
|
||||||
let step_index = i + 1;
|
let step_index = i + 1;
|
||||||
|
let step_type = &step.r#type;
|
||||||
|
|
||||||
// Find the relevant Operation
|
// Find the relevant Operation
|
||||||
let Some(invocable) = operations.iter().find(|op| op.name == step.r#type) else {
|
let Some(invocable) = operations.iter().find(|op| op.name == *step_type) else {
|
||||||
panic!("Could not find operation: {}", step.r#type);
|
panic!("Could not find operation: {step_type}");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if we have the keys we want to pass into the module.
|
// Check if we have the keys we want to pass into the module.
|
||||||
for in_memory_name in step.inputs.values() {
|
for in_memory_name in step.inputs.values() {
|
||||||
if !data.contains(in_memory_name) && !step.values.contains_key(in_memory_name) {
|
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()
|
.iter()
|
||||||
.any(|arg| *module_input_name == arg.name)
|
.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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,13 +59,19 @@ from_address = "from_address"
|
||||||
[module.workflow.step.outputs]
|
[module.workflow.step.outputs]
|
||||||
transaction = "unsigned_transaction"
|
transaction = "unsigned_transaction"
|
||||||
|
|
||||||
|
# Get a blockhash
|
||||||
|
[[module.workflow.step]]
|
||||||
|
type = "sol-get-blockhash"
|
||||||
|
|
||||||
|
outputs = { blockhash = "blockhash" }
|
||||||
|
|
||||||
# Sign the transaction
|
# Sign the transaction
|
||||||
[[module.workflow.step]]
|
[[module.workflow.step]]
|
||||||
type = "sol-sign"
|
type = "sol-sign"
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
[module.workflow.step.inputs]
|
||||||
transaction = "unsigned_transaction"
|
transaction = "unsigned_transaction"
|
||||||
# blockhash = "blockhash"
|
blockhash = "blockhash"
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
[module.workflow.step.outputs]
|
||||||
transaction = "signed_transaction"
|
transaction = "signed_transaction"
|
||||||
|
|
Loading…
Reference in New Issue