Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Events #89

Merged
merged 2 commits into from
Mar 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobs:
- pushd examples/interface && anchor test && popd
- pushd examples/lockup && anchor test && popd
- pushd examples/misc && anchor test && popd
- pushd examples/events && anchor test && popd
- pushd examples/cashiers-check && anchor test && popd
- <<: *examples
name: Runs the examples 2
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ incremented for features.

* cli: Specify test files to run ([#118](https://github.com/project-serum/anchor/pull/118)).
* lang: Allow overriding the `#[state]` account's size ([#121](https://github.com/project-serum/anchor/pull/121)).
* lang, client, ts: Add event emission and subscriptions ([#89](https://github.com/project-serum/anchor/pull/89)).

## Breaking Changes

* client: Replace url str with `Cluster` struct when constructing clients ([#89](https://github.com/project-serum/anchor/pull/89)).

## [0.3.0] - 2021-03-12

Expand Down
29 changes: 17 additions & 12 deletions Cargo.lock

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

6 changes: 4 additions & 2 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ description = "Rust client for Anchor programs"

[dependencies]
anchor-lang = { path = "../lang", version = "0.3.0" }
solana-client = "1.5.8"
solana-sdk = "1.5.8"
anyhow = "1.0.32"
regex = "1.4.5"
solana-client = "=1.5.15"
solana-sdk = "=1.5.15"
thiserror = "1.0.20"
3 changes: 2 additions & 1 deletion client/example/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ edition = "2018"
[workspace]

[dependencies]
anchor-client = { git = "https://github.com/project-serum/anchor" }
anchor-client = { path = "../" }
basic-2 = { path = "../../examples/tutorial/basic-2/programs/basic-2", features = ["no-entrypoint"] }
composite = { path = "../../examples/composite/programs/composite", features = ["no-entrypoint"] }
events = { path = "../../examples/events/programs/events", features = ["no-entrypoint"] }
shellexpand = "2.1.0"
anyhow = "1.0.32"
rand = "0.7.3"
Expand Down
8 changes: 6 additions & 2 deletions client/example/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ main() {
anchor deploy
local basic_2_pid=$(cat target/idl/basic_2.json | jq -r .metadata.address)
popd

pushd ../../examples/events
anchor build
anchor deploy
local events_pid=$(cat target/idl/events.json | jq -r .metadata.address)
popd
#
# Run Test.
#
cargo run -- --composite-pid $composite_pid --basic-2-pid $basic_2_pid
cargo run -- --composite-pid $composite_pid --basic-2-pid $basic_2_pid --events-pid $events_pid
}

cleanup() {
Expand Down
45 changes: 43 additions & 2 deletions client/example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,30 @@ use anchor_client::solana_sdk::signature::read_keypair_file;
use anchor_client::solana_sdk::signature::{Keypair, Signer};
use anchor_client::solana_sdk::system_instruction;
use anchor_client::solana_sdk::sysvar;
use anchor_client::Client;
use anchor_client::{Client, Cluster, EventContext};
use anyhow::Result;
// The `accounts` and `instructions` modules are generated by the framework.
use basic_2::accounts as basic_2_accounts;
use basic_2::instruction as basic_2_instruction;
use basic_2::Counter;
use events::instruction as events_instruction;
use events::MyEvent;
// The `accounts` and `instructions` modules are generated by the framework.
use clap::Clap;
use composite::accounts::{Bar, CompositeUpdate, Foo, Initialize};
use composite::instruction as composite_instruction;
use composite::{DummyA, DummyB};
use rand::rngs::OsRng;
use std::time::Duration;

#[derive(Clap)]
pub struct Opts {
#[clap(long)]
composite_pid: Pubkey,
#[clap(long)]
basic_2_pid: Pubkey,
#[clap(long)]
events_pid: Pubkey,
}

// This example assumes a local validator is running with the programs
Expand All @@ -33,14 +38,18 @@ fn main() -> Result<()> {
// Wallet and cluster params.
let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json"))
.expect("Example requires a keypair file");
let url = "http://localhost:8899";
let url = Cluster::Custom(
"http://localhost:8899".to_string(),
"ws://127.0.0.1:8900".to_string(),
);

// Client.
let client = Client::new_with_options(url, payer, CommitmentConfig::processed());

// Run tests.
composite(&client, opts.composite_pid)?;
basic_2(&client, opts.basic_2_pid)?;
events(&client, opts.events_pid)?;

// Success.
Ok(())
Expand Down Expand Up @@ -155,3 +164,35 @@ fn basic_2(client: &Client, pid: Pubkey) -> Result<()> {

Ok(())
}

fn events(client: &Client, pid: Pubkey) -> Result<()> {
let program = client.program(pid);

let (sender, receiver) = std::sync::mpsc::channel();
let handle = program.on(move |_ctx: &EventContext, event: MyEvent| {
sender.send(event).unwrap();
})?;

std::thread::sleep(Duration::from_millis(1000));

program
.request()
.args(events_instruction::Initialize {})
.send()?;

let event = receiver.recv().unwrap();
assert_eq!(event.data, 5);
assert_eq!(event.label, "hello".to_string());

// TODO: remove once https://github.com/solana-labs/solana/issues/16102
// is addressed. Until then, drop the subscription handle in another
// thread so that we deadlock in the other thread as to not block
// this thread.
std::thread::spawn(move || {
drop(handle);
});

println!("Success!");

Ok(())
}
102 changes: 102 additions & 0 deletions client/src/cluster.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use anyhow::Result;
use std::str::FromStr;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Cluster {
Testnet,
Mainnet,
VipMainnet,
Devnet,
Localnet,
Debug,
Custom(String, String),
}

impl Default for Cluster {
fn default() -> Self {
Cluster::Localnet
}
}

impl FromStr for Cluster {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Cluster> {
match s.to_lowercase().as_str() {
"t" | "testnet" => Ok(Cluster::Testnet),
"m" | "mainnet" => Ok(Cluster::Mainnet),
"v" | "vipmainnet" => Ok(Cluster::VipMainnet),
"d" | "devnet" => Ok(Cluster::Devnet),
"l" | "localnet" => Ok(Cluster::Localnet),
"g" | "debug" => Ok(Cluster::Debug),
_ => Err(anyhow::Error::msg(
"Cluster must be one of [localnet, testnet, mainnet, devnet] or be an http or https url\n",
)),
}
}
}

impl std::fmt::Display for Cluster {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let clust_str = match self {
Cluster::Testnet => "testnet",
Cluster::Mainnet => "mainnet",
Cluster::VipMainnet => "vipmainnet",
Cluster::Devnet => "devnet",
Cluster::Localnet => "localnet",
Cluster::Debug => "debug",
Cluster::Custom(url, _ws_url) => url,
};
write!(f, "{}", clust_str)
}
}

impl Cluster {
pub fn url(&self) -> &str {
match self {
Cluster::Devnet => "https://devnet.solana.com",
Cluster::Testnet => "https://testnet.solana.com",
Cluster::Mainnet => "https://api.mainnet-beta.solana.com",
Cluster::VipMainnet => "https://vip-api.mainnet-beta.solana.com",
Cluster::Localnet => "http://127.0.0.1:8899",
Cluster::Debug => "http://34.90.18.145:8899",
Cluster::Custom(url, _ws_url) => url,
}
}
pub fn ws_url(&self) -> &str {
match self {
Cluster::Devnet => "wss://devnet.solana.com",
Cluster::Testnet => "wss://testnet.solana.com",
Cluster::Mainnet => "wss://api.mainnet-beta.solana.com",
Cluster::VipMainnet => "wss://vip-api.mainnet-beta.solana.com",
Cluster::Localnet => "ws://127.0.0.1:9000",
Cluster::Debug => "ws://34.90.18.145:9000",
Cluster::Custom(_url, ws_url) => ws_url,
}
}
}

#[cfg(test)]
mod tests {
use super::*;

fn test_cluster(name: &str, cluster: Cluster) {
assert_eq!(Cluster::from_str(name).unwrap(), cluster);
}

#[test]
fn test_cluster_parse() {
test_cluster("testnet", Cluster::Testnet);
test_cluster("mainnet", Cluster::Mainnet);
test_cluster("vipmainnet", Cluster::VipMainnet);
test_cluster("devnet", Cluster::Devnet);
test_cluster("localnet", Cluster::Localnet);
test_cluster("debug", Cluster::Debug);
}

#[test]
#[should_panic]
fn test_cluster_bad_parse() {
let bad_url = "httq://my_custom_url.test.net";
Cluster::from_str(bad_url).unwrap();
}
}
Loading