Skip to content

Commit

Permalink
Nuke the client module (#246)
Browse files Browse the repository at this point in the history
* Remove the client module

* Remove all uses of clockwork_client in cli

* Readd localnet startup script

* Migrate to ToAccountMetas
  • Loading branch information
nickgarfield authored May 2, 2023
1 parent d37ce1b commit 02e3333
Show file tree
Hide file tree
Showing 72 changed files with 607 additions and 1,585 deletions.
25 changes: 5 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[workspace]
members = [
"cli",
"client",
"cron",
"plugin",
"programs/*",
Expand Down
4 changes: 3 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ build = "build.rs"

[dependencies]
anchor-lang = "0.27.0"
anchor-spl = { features = ["mint", "token"], version = "0.27.0" }
anyhow = "1.0.61"
bincode = "1.3.3"
bzip2 = "0.4"
clap = { version = "3.1.2", features = ["derive"] }
clockwork-client = { path = "../client", version = "=2.0.15" }
clockwork-cron = { path = "../cron", version = "=2.0.15" }
clockwork-network-program = { path = "../programs/network", version = "=2.0.15" }
clockwork-relayer-api = { path = "../relayer/api", version = "=2.0.15" }
clockwork-plugin-utils= { path = "../plugin/utils", version = "=2.0.15" }
clockwork-thread-program = { path = "../programs/thread", version = "=2.0.15" }
clockwork-utils = { path = "../utils", version = "=2.0.15" }
clockwork-webhook-program = { path = "../programs/webhook", version = "=2.0.15" }
chrono = { version = "0.4.19", default-features = false, features = ["alloc"] }
Expand Down
26 changes: 6 additions & 20 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
use {
crate::parser::ProgramInfo,
clap::{
crate_version,
Arg,
ArgGroup,
Command,
},
clockwork_client::{
thread::state::{
SerializableInstruction,
Trigger,
},
webhook::state::HttpMethod,
},
solana_sdk::{
pubkey::Pubkey,
signature::Keypair,
},
};
use clap::{crate_version, Arg, ArgGroup, Command};
use clockwork_thread_program::state::{SerializableInstruction, Trigger};
use clockwork_webhook_program::state::HttpMethod;
use solana_sdk::{pubkey::Pubkey, signature::Keypair};

use crate::parser::ProgramInfo;

#[derive(Debug, PartialEq)]
pub enum CliCommand {
Expand Down
158 changes: 158 additions & 0 deletions cli/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use anchor_lang::{prelude::Clock, AccountDeserialize};
use clockwork_utils::ProgramLogsDeserializable;
use solana_client::{
client_error, rpc_client::RpcClient,
rpc_response::RpcSimulateTransactionResult,
};
use solana_sdk::{
commitment_config::CommitmentConfig,
hash::Hash,
instruction::Instruction,
program_error::ProgramError,
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
signers::Signers,
transaction::Transaction,
};
use std::{
fmt::Debug,
ops::{Deref, DerefMut},
str::FromStr,
};
use thiserror::Error;


#[derive(Debug, Error)]
pub enum ClientError {
#[error(transparent)]
Client(#[from] client_error::ClientError),

#[error(transparent)]
Program(#[from] ProgramError),

#[error("Failed to deserialize account data")]
DeserializationError,
}

pub type ClientResult<T> = Result<T, ClientError>;

pub struct Client {
pub client: RpcClient,
pub payer: Keypair,
}

impl Client {
pub fn new(payer: Keypair, url: String) -> Self {
let client = RpcClient::new_with_commitment::<String>(url, CommitmentConfig::processed());
Self { client, payer }
}

pub fn get<T: AccountDeserialize>(&self, pubkey: &Pubkey) -> ClientResult<T> {
let data = self.client.get_account_data(pubkey)?;
T::try_deserialize(&mut data.as_slice()).map_err(|_| ClientError::DeserializationError)
}

pub fn get_clock(&self) -> ClientResult<Clock> {
let clock_pubkey = Pubkey::from_str("SysvarC1ock11111111111111111111111111111111").unwrap();
let clock_data = self.client.get_account_data(&clock_pubkey)?;
bincode::deserialize::<Clock>(&clock_data).map_err(|_| ClientError::DeserializationError)
}

pub fn get_return_data<T: ProgramLogsDeserializable>(
&self,
ix: Instruction,
) -> ClientResult<T> {
// let result = self.simulate_transaction(&[ix.clone()], &[self.payer()])?;

// After we can upgrade our Solana SDK version to 1.14.0 we can just use the below code:
// let data = result.logs;
// Ok(T::try_from_slice(logs, &data)
// .map_err(|_| ClientError::DeserializationError)?)
//
// But for the time being since RpcSimulateTransactionResult.data does not exist yet,
// We can only parse the logs ourselves to find the return_data
let logs = self.get_instruction_logs(ix.clone())?;
T::try_from_program_logs(logs, &ix.program_id)
.map_err(|_| ClientError::DeserializationError)
}

pub fn get_instruction_logs(&self, ix: Instruction) -> ClientResult<Vec<String>> {
let result = self.simulate_transaction(&[ix], &[self.payer()])?;
let logs = result.logs.ok_or(ClientError::DeserializationError)?;
Ok(logs)
}

pub fn payer(&self) -> &Keypair {
&self.payer
}

pub fn payer_pubkey(&self) -> Pubkey {
self.payer.pubkey()
}

pub fn latest_blockhash(&self) -> ClientResult<Hash> {
Ok(self.client.get_latest_blockhash()?)
}

pub fn airdrop(&self, to_pubkey: &Pubkey, lamports: u64) -> ClientResult<Signature> {
let blockhash = self.client.get_latest_blockhash()?;
let signature = self.request_airdrop_with_blockhash(to_pubkey, lamports, &blockhash)?;
self.confirm_transaction_with_spinner(&signature, &blockhash, self.commitment())?;
Ok(signature)
}

pub fn send_and_confirm<T: Signers>(
&self,
ixs: &[Instruction],
signers: &T,
) -> ClientResult<Signature> {
let tx = self.transaction(ixs, signers)?;
Ok(self.send_and_confirm_transaction(&tx)?)
}

pub fn simulate_transaction<T: Signers>(
&self,
ixs: &[Instruction],
signers: &T,
) -> ClientResult<RpcSimulateTransactionResult> {
let tx = self.transaction(ixs, signers)?;
let result = self.client.simulate_transaction(&tx)?;
if result.value.err.is_some() {
Err(ClientError::DeserializationError)
} else {
Ok(result.value)
}
}

fn transaction<T: Signers>(
&self,
ixs: &[Instruction],
signers: &T,
) -> ClientResult<Transaction> {
let mut tx = Transaction::new_with_payer(ixs, Some(&self.payer_pubkey()));
tx.sign(signers, self.latest_blockhash()?);
Ok(tx)
}
}


impl Debug for Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RPC client payer {}", self.payer_pubkey())
}
}

impl Deref for Client {
type Target = RpcClient;

fn deref(&self) -> &Self::Target {
&self.client
}
}

impl DerefMut for Client {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.client
}
}

1 change: 1 addition & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod cli;
mod client;
mod config;
mod deps;
mod errors;
Expand Down
44 changes: 12 additions & 32 deletions cli/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,17 @@
use {
crate::{
cli::CliCommand,
errors::CliError,
},
clap::ArgMatches,
clockwork_client::{
thread::state::{
SerializableAccount,
SerializableInstruction,
Trigger,
},
webhook::state::HttpMethod,
},
serde::{
Deserialize as JsonDeserialize,
Serialize as JsonSerialize,
},
solana_sdk::{
pubkey::Pubkey,
signature::{
read_keypair_file,
Keypair,
},
signer::Signer,
},
std::{
convert::TryFrom,
fs,
path::PathBuf,
str::FromStr,
},
use std::{convert::TryFrom, fs, path::PathBuf, str::FromStr};

use clap::ArgMatches;
use clockwork_thread_program::state::{SerializableAccount, SerializableInstruction, Trigger};
use clockwork_webhook_program::state::HttpMethod;
use serde::{Deserialize as JsonDeserialize, Serialize as JsonSerialize};
use solana_sdk::{
pubkey::Pubkey,
signature::{read_keypair_file, Keypair},
signer::Signer,
};

use crate::{cli::CliCommand, errors::CliError};

impl TryFrom<&ArgMatches> for CliCommand {
type Error = CliError;

Expand Down
22 changes: 15 additions & 7 deletions cli/src/processor/config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use {
crate::errors::CliError,
clockwork_client::{
network::state::{Config, ConfigSettings},
Client,
use anchor_lang::{
solana_program::{
instruction::Instruction, pubkey::Pubkey,
},
solana_sdk::pubkey::Pubkey,
InstructionData, ToAccountMetas
};
use clockwork_network_program::state::{Config, ConfigSettings};

use crate::{client::Client, errors::CliError};

pub fn get(client: &Client) -> Result<(), CliError> {
let config = client
Expand Down Expand Up @@ -35,7 +36,14 @@ pub fn set(
};

// Submit tx
let ix = clockwork_client::network::instruction::config_update(client.payer_pubkey(), settings);
let ix = Instruction {
program_id: clockwork_network_program::ID,
accounts: clockwork_network_program::accounts::ConfigUpdate {
admin: client.payer_pubkey(),
config: Config::pubkey(),
}.to_account_metas(Some(false)),
data: clockwork_network_program::instruction::ConfigUpdate { settings }.data(),
};
client.send_and_confirm(&[ix], &[client.payer()]).unwrap();
get(client)?;
Ok(())
Expand Down
12 changes: 5 additions & 7 deletions cli/src/processor/crontab.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use {
crate::errors::CliError,
chrono::{DateTime, NaiveDateTime, Utc},
clockwork_client::Client,
clockwork_cron::Schedule,
std::str::FromStr,
};
use chrono::{DateTime, NaiveDateTime, Utc};
use clockwork_cron::Schedule;
use std::str::FromStr;

use crate::{client::Client, errors::CliError};

pub fn get(client: &Client, schedule: String) -> Result<(), CliError> {
let clock = client.get_clock().unwrap();
Expand Down
Loading

1 comment on commit 02e3333

@vercel
Copy link

@vercel vercel bot commented on 02e3333 May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.