Implementing openbook_v2 place orders in rust

This commit is contained in:
Godmode Galactus 2023-05-13 16:56:30 +02:00
parent 8890a462d5
commit 4e16fdff22
No known key found for this signature in database
GPG Key ID: A04142C71ABB0DEA
26 changed files with 4940 additions and 1046 deletions

1405
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,11 @@ rand_chacha = "0.3.1"
async-trait = "0.1.68"
solana-sdk = "1.15.2"
solana-program = "1.15.2"
solana-rpc-client = "1.15.2"
derive_more = "0.99.17"
pretty_env_logger = "0.4.0"
tracing-subscriber = "0.3.17"
spl-token = "3.5.0"
solana-client = "1.15.2"

View File

@ -1,6 +1,11 @@
import { AnchorProvider, Provider } from "@project-serum/anchor";
import { AnchorProvider, BN, Program, Provider, web3 } from "@project-serum/anchor";
import { SuccessfulTxSimulationResponse } from "@project-serum/anchor/dist/cjs/utils/rpc";
import { Connection, PublicKey, Transaction, Signer, SendOptions, ConfirmOptions, Commitment, Keypair } from "@solana/web3.js";
import { Command } from "./output_file";
import { IDL, OpenbookV2 } from "./openbook-v2/openbook_v2";
import { U64_MAX_BN } from "@blockworks-foundation/mango-v4";
import { assert } from "console";
import { buffer } from "stream/consumers";
export class TestProvider extends AnchorProvider {
keypair: Keypair;

View File

@ -8,7 +8,7 @@ import { getKeypairFromFile } from './common_utils';
import { deploy_programs } from './deploy_programs';
import { User, createUser, mintUser } from './general/create_users';
import { configure_accounts } from './general/accounts';
import { OutputFile } from './output_file';
import { Command, OutputFile } from './output_file';
import { MintUtils } from './general/mint_utils';
import { OpenbookConfigurator } from './openbook-v2/configure_openbook';
@ -142,9 +142,11 @@ async function configure(
let programOutputData = programs.map(x => {
let kp = getKeypairFromFile(x.programKeyPath);
let emptyCommands : Command[] = [];
return {
name: x.name,
program_id: kp.publicKey
program_id: kp.publicKey,
commands: emptyCommands,
}
})
@ -167,18 +169,19 @@ async function configure(
let openbookProgramId = programOutputData[index].program_id;
let openbookConfigurator = new OpenbookConfigurator(connection, authority, mintUtils, openbookProgramId);
let markets = await openbookConfigurator.configureOpenbookV2(mints);
programOutputData[index].commands = await openbookConfigurator.getCommands();
console.log("Finished configuring openbook")
console.log("Creating users");
let users = await Promise.all(Array.from(Array(nbPayers).keys()).map(_ => createUser(connection, authority, balancePerPayer)));
let tokenAccounts = await Promise.all(users.map(
/// user is richer than bill gates, but not as rich as certain world leaders
user => mintUser(connection, authority, mints, mintUtils, user.publicKey, 100_000_000_000)
async(user) => await mintUser(connection, authority, mints, mintUtils, user.publicKey, 100_000_000_000_000_000)
))
let userOpenOrders = await Promise.all(users.map(
/// user is crazy betting all his money in crypto market
user => openbookConfigurator.configureMarketForUser(user, markets, 100_000_000_000)
async(user) => await openbookConfigurator.configureMarketForUser(user, markets)
))
let userData: User [] = users.map((user, i) => {
@ -191,6 +194,14 @@ async function configure(
console.log("Users created");
console.log("Filling up orderbook");
await Promise.all( userData.map( async(user, i) => {
for (const market of markets) {
await openbookConfigurator.fillOrderBook(user, users[i], market, 32);
}
}) )
console.log("Orderbook filled");
console.log("Creating accounts")
let accounts = await configure_accounts(connection, authority, numberOfAccountsToBeCreated, programIds);

View File

@ -3,11 +3,13 @@ import * as web3 from "@solana/web3.js";
import { exec } from "child_process";
import * as fs from "fs"
import { promisify } from "util";
import { getKeypairFromFile } from "./common_utils";
export interface ProgramData {
name: string,
programPath: string,
programKeyPath: string,
idl: string,
}
export async function deploy_programs(url: String, payer: string, programs: ProgramData[]) {
@ -23,5 +25,24 @@ export async function deploy_programs(url: String, payer: string, programs: Prog
if (stderr.length > 0) {
console.log(stderr);
}
if (program.idl.length > 0) {
let programId = getKeypairFromFile(program.programKeyPath);
console.log("deploying idl file for program " + programId.publicKey);
let initCmd = "anchor idl init --filepath " + program.idl + " --provider.wallet " + payer + " --provider.cluster " + url + " " + programId.publicKey;
const {stdout, stderr} = await execPromise(initCmd);
if (stderr.length > 0) {
let updateCommand = "anchor idl update --filepath " + program.idl + " --provider.wallet " + payer + " --provider.cluster " + url + " " + programId.publicKey;
const {stdout, stderr} = await execPromise(updateCommand);
if (stdout.length > 0) {
console.log(stdout);
}
if(stderr.length > 0) {
console.log("could not deploy idl for " + programId.publicKey);
}
}
}
}
}

View File

@ -4,7 +4,12 @@ import { Market, createMarket } from "./create_markets";
import { MintUtils } from "../general/mint_utils";
import { OpenbookV2 } from "./openbook_v2";
import IDL from '../programs/openbook_v2.json'
import { BN, Program, web3 } from "@project-serum/anchor";
import { BN, Program, web3, IdlTypes } from "@project-serum/anchor";
import { User } from "../general/create_users";
import { U64_MAX_BN } from "@blockworks-foundation/mango-v4";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { Command } from "../output_file";
import assert from "assert";
export interface OpenOrders {
market: PublicKey,
@ -16,32 +21,33 @@ export class OpenbookConfigurator {
anchorProvider: TestProvider;
mintUtils: MintUtils;
openbookProgramId: PublicKey;
program: Program<OpenbookV2>;
constructor(connection: Connection, authority: Keypair, mintUtils: MintUtils, openbookProgramId: PublicKey) {
this.anchorProvider = new TestProvider(connection, authority);
this.mintUtils = mintUtils;
this.openbookProgramId = openbookProgramId;
this.program = new Program<OpenbookV2>(
IDL as OpenbookV2,
this.openbookProgramId,
this.anchorProvider,
);
}
public async configureOpenbookV2(mints: PublicKey[]): Promise<Market[]> {
let quoteMint = mints[0];
let admin = Keypair.generate();
return await Promise.all(mints.slice(1).map((mint, index) => createMarket(this.anchorProvider, this.mintUtils, admin, this.openbookProgramId, mint, quoteMint, index)))
return await Promise.all(mints.slice(1).map((mint, index) => createMarket(this.program, this.anchorProvider, this.mintUtils, admin, this.openbookProgramId, mint, quoteMint, index)))
}
public async configureMarketForUser(user: Keypair, markets: Market[], depositAmount: number) : Promise<OpenOrders[]> {
let program = new Program<OpenbookV2>(
IDL as OpenbookV2,
this.openbookProgramId,
this.anchorProvider,
);
public async configureMarketForUser(user: Keypair, markets: Market[],) : Promise<OpenOrders[]> {
const openOrders = await Promise.all(
markets.map(async(market) => {
let accountIndex = new BN(0);
let [openOrders, _tmp] = PublicKey.findProgramAddressSync([Buffer.from("OpenOrders"), user.publicKey.toBuffer(), market.market_pk.toBuffer(), accountIndex.toBuffer("le", 4)], this.openbookProgramId)
await program.methods.initOpenOrders(
await this.program.methods.initOpenOrders(
0,
64
).accounts({
@ -62,4 +68,112 @@ export class OpenbookConfigurator {
}
})
}
public async fillOrderBook(user: User, userKp: Keypair, market: Market, nbOrders: number) {
for( let i=0; i<nbOrders; ++i) {
let side = {bid:{}} ;
let placeOrder = {limit:{}};
await this.program.methods.placeOrder(
side,
new BN(1000-1-i),
new BN(10000),
new BN(1000000),
new BN(i),
placeOrder,
false,
U64_MAX_BN,
255,
).accounts({
asks: market.asks,
baseVault: market.base_vault,
bids: market.bids,
eventQueue: market.event_queue,
market: market.market_pk,
openOrdersAccount: user.open_orders[market.market_index].open_orders,
oracle: market.oracle,
owner: userKp.publicKey,
payer: user.token_data[0].token_account,
quoteVault: market.quote_vault,
systemProgram: web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
}).signers([userKp]).rpc();
}
for( let i=0; i<nbOrders; ++i) {
let side = {ask:{}} ;
let placeOrder = {limit:{}};
await this.program.methods.placeOrder(
side,
new BN(1000+1+i),
new BN(10000),
new BN(1000000),
new BN(i),
placeOrder,
false,
U64_MAX_BN,
255,
).accounts({
asks: market.asks,
baseVault: market.base_vault,
bids: market.bids,
eventQueue: market.event_queue,
market: market.market_pk,
openOrdersAccount: user.open_orders[market.market_index].open_orders,
oracle: market.oracle,
owner: userKp.publicKey,
payer: user.token_data[market.market_index+1].token_account,
quoteVault: market.quote_vault,
systemProgram: web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
}).signers([userKp]).rpc();
}
}
/// this is a special method.
/// It is pain to create an anchor instruction in rust
/// so this method will create the instruction in typescript and serialize into bytes and store it into command type
public async getCommands() : Promise<Command[]> {
let side = {bid:{}} ;
let placeOrder = {limit:{}};
let placeOrderIx = await this.program.methods.placeOrder(
side,
new BN(0),
new BN(0),
new BN(0),
new BN(0),
placeOrder,
false,
U64_MAX_BN,
255,
).accounts({
asks: PublicKey.default,
baseVault: PublicKey.default,
bids: PublicKey.default,
eventQueue: PublicKey.default,
market: PublicKey.default,
openOrdersAccount: PublicKey.default,
oracle: PublicKey.default,
owner: PublicKey.default,
payer: PublicKey.default,
quoteVault: PublicKey.default,
systemProgram: web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
}).instruction();
let argument_sizes = [8, 1, 8, 8, 8, 8, 1, 1, 8, 1];
assert(argument_sizes.reduce( (sum, current) => sum + current, 0 ) === placeOrderIx.data.length);
let placeOrderCommand : Command = {
name: "placeOrder",
instruction: Array.from(placeOrderIx.data),
argument_sizes,
};
return [placeOrderCommand]
}
}

View File

@ -22,12 +22,7 @@ export interface Market {
market_index: number,
}
export async function createMarket(anchorProvider: TestProvider, mintUtils: MintUtils, adminKp: Keypair, openbookProgramId: PublicKey, baseMint: PublicKey, quoteMint: PublicKey, index: number): Promise<Market> {
let program = new Program<OpenbookV2>(
IDL as OpenbookV2,
openbookProgramId,
anchorProvider,
);
export async function createMarket(program:Program<OpenbookV2>, anchorProvider: TestProvider, mintUtils: MintUtils, adminKp: Keypair, openbookProgramId: PublicKey, baseMint: PublicKey, quoteMint: PublicKey, index: number): Promise<Market> {
let [oracleId, _tmp] = PublicKey.findProgramAddressSync([Buffer.from("StubOracle"), baseMint.toBytes()], openbookProgramId)
const admin:PublicKey = adminKp.publicKey;

View File

@ -1552,22 +1552,6 @@ export type OpenbookV2 = {
"type": {
"kind": "struct",
"fields": [
{
"name": "basePositionLots",
"docs": [
"Currenlty not being used"
],
"type": "i64"
},
{
"name": "quotePositionNative",
"docs": [
"Currenlty not being used"
],
"type": {
"defined": "I80F48"
}
},
{
"name": "quoteRunningNative",
"docs": [
@ -1589,20 +1573,6 @@ export type OpenbookV2 = {
],
"type": "i64"
},
{
"name": "takerBaseLots",
"docs": [
"Amount of base lots on the EventQueue waiting to be processed"
],
"type": "i64"
},
{
"name": "takerQuoteLots",
"docs": [
"Amount of quote lots on the EventQueue waiting to be processed"
],
"type": "i64"
},
{
"name": "baseFreeNative",
"type": {
@ -4511,22 +4481,6 @@ export const IDL: OpenbookV2 = {
"type": {
"kind": "struct",
"fields": [
{
"name": "basePositionLots",
"docs": [
"Currenlty not being used"
],
"type": "i64"
},
{
"name": "quotePositionNative",
"docs": [
"Currenlty not being used"
],
"type": {
"defined": "I80F48"
}
},
{
"name": "quoteRunningNative",
"docs": [
@ -4548,20 +4502,6 @@ export const IDL: OpenbookV2 = {
],
"type": "i64"
},
{
"name": "takerBaseLots",
"docs": [
"Amount of base lots on the EventQueue waiting to be processed"
],
"type": "i64"
},
{
"name": "takerQuoteLots",
"docs": [
"Amount of quote lots on the EventQueue waiting to be processed"
],
"type": "i64"
},
{
"name": "baseFreeNative",
"type": {

View File

@ -2,9 +2,16 @@ import { PublicKey } from "@solana/web3.js";
import { Market } from "./openbook-v2/create_markets";
import { User } from "./general/create_users";
export interface Command {
name: String,
instruction: number[],
argument_sizes: number[],
}
export interface ProgramOutputData {
name: String,
program_id: PublicKey,
commands: Command [],
}
export interface OutputFile {

View File

@ -2,11 +2,13 @@
{
"name": "pyth_mock",
"programPath": "programs/pyth_mock.so",
"programKeyPath": "programs/pyth_mock.json"
"programKeyPath": "programs/pyth_mock.json",
"idl": ""
},
{
"name": "openbook_v2",
"programPath": "programs/openbook_v2.so",
"programKeyPath": "programs/openbook_v2-keypair.json"
"programKeyPath": "programs/openbook_v2-keypair.json",
"idl": "programs/openbook_v2.json"
}
]

View File

@ -1552,22 +1552,6 @@
"type": {
"kind": "struct",
"fields": [
{
"name": "basePositionLots",
"docs": [
"Currenlty not being used"
],
"type": "i64"
},
{
"name": "quotePositionNative",
"docs": [
"Currenlty not being used"
],
"type": {
"defined": "I80F48"
}
},
{
"name": "quoteRunningNative",
"docs": [
@ -1589,20 +1573,6 @@
],
"type": "i64"
},
{
"name": "takerBaseLots",
"docs": [
"Amount of base lots on the EventQueue waiting to be processed"
],
"type": "i64"
},
{
"name": "takerQuoteLots",
"docs": [
"Amount of quote lots on the EventQueue waiting to be processed"
],
"type": "i64"
},
{
"name": "baseFreeNative",
"type": {

Binary file not shown.

2682
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,8 @@
"@project-serum/anchor": "^0.26.0",
"@solana/spl-token": "^0.3.7",
"@solana/web3.js": "^1.75.0",
"cmd-ts": "^0.12.1"
"cmd-ts": "^0.12.1",
"loadash": "^1.0.0",
"lodash": "^4.17.21"
}
}

View File

@ -45,7 +45,11 @@ impl Bencher {
})
});
let avg_metric = futures::future::try_join_all(futs).await?.into_iter().sum::<Metric>() / args.threads;
let avg_metric = futures::future::try_join_all(futs)
.await?
.into_iter()
.sum::<Metric>()
/ args.threads;
Ok(avg_metric)
}

View File

@ -1,13 +1,19 @@
use std::{sync::Arc, time::Duration};
use clap::{command, Parser};
use futures::StreamExt;
use log::Log;
use solana_client::{nonblocking::pubsub_client::PubsubClient, rpc_config::RpcTransactionLogsConfig};
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
use tokio::sync::RwLock;
use solana_sdk::{hash::Hash, commitment_config::{CommitmentConfig, CommitmentLevel}};
use crate::{
solana_runtime::{
accounts_fetching::AccountsFetchingTests, get_block::GetBlockTest, get_slot::GetSlotTest,
send_and_get_status_memo::SendAndConfrimTesting,
},
openbook::simulate_place_orders::SimulateOpenbookV2PlaceOrder,
test_registry::TestRegistry,
};
@ -29,21 +35,60 @@ pub struct Args {
#[arg(long)]
pub get_block: bool,
#[arg(long)]
pub simulate_openbook_v2: bool,
#[arg(short = 'a', long)]
pub test_all: bool,
#[arg(short = 'r', long, default_value_t = String::from("http://127.0.0.1:8899"))]
pub rpc_addr: String,
#[arg(short = 'w', long, default_value_t = String::from("ws://127.0.0.1:8900"))]
pub rpc_ws_addr: String,
#[arg(short = 'd', long, default_value_t = 60)]
pub duration_in_seconds: u64,
#[arg(short = 't', long, default_value_t = 4)]
pub threads: u64,
#[arg(short = 'p', long)]
pub print_logs: bool,
}
impl Args {
pub fn generate_test_registry(&self) -> TestRegistry {
pub fn generate_test_registry(&self, block_hash: Arc<RwLock<Hash>>) -> TestRegistry {
if self.print_logs {
let rpc_ws_addr = self.rpc_ws_addr.clone();
tokio::spawn(async move {
let pubsub_client = PubsubClient::new(&rpc_ws_addr).await.unwrap();
let res = pubsub_client.logs_subscribe(solana_client::rpc_config::RpcTransactionLogsFilter::All, RpcTransactionLogsConfig{
commitment: None
}).await;
match res {
Ok(( mut stream, _)) => {
loop {
let log = stream.next().await;
match log {
Some(log) => {
for log_s in log.value.logs {
println!("{}", log_s);
}
},
None => {
}
}
}
},
Err(e) => {
println!("error subscribing to the logs {}",e);
}
}
});
}
let mut test_registry = TestRegistry::default();
if self.accounts_fetching || self.test_all {
@ -51,7 +96,7 @@ impl Args {
}
if self.send_and_confirm_transaction || self.test_all {
test_registry.register(Box::new(SendAndConfrimTesting));
test_registry.register(Box::new(SendAndConfrimTesting{block_hash: block_hash.clone()}));
}
if self.get_slot || self.test_all {
@ -62,6 +107,10 @@ impl Args {
test_registry.register(Box::new(GetBlockTest));
}
if self.simulate_openbook_v2 || self.test_all {
test_registry.register(Box::new(SimulateOpenbookV2PlaceOrder{block_hash} ));
}
test_registry
}

View File

@ -1,45 +1,78 @@
use serde::{Deserialize, Serialize};
use solana_sdk::signature::Keypair;
use solana_sdk::{signature::Keypair, signer::Signer};
#[derive(Serialize, Deserialize, Clone)]
pub struct Command {
pub name: String,
pub instruction: Vec<u8>,
pub argument_sizes: Vec<u8>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct ProgramData {
pub name: String,
pub program_id: String,
pub commands: Vec<Command>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct User {
secret: Vec<u8>,
token_data: Vec<TokenAccountData>,
open_orders: Vec<OpenOrders>,
pub secret: Vec<u8>,
pub token_data: Vec<TokenAccountData>,
pub open_orders: Vec<OpenOrders>,
}
impl User {
pub fn get_keypair(&self) -> Keypair {
Keypair::from_bytes(&self.secret).unwrap()
}
}
impl Signer for User {
fn try_pubkey(&self) -> Result<solana_sdk::pubkey::Pubkey, solana_sdk::signer::SignerError> {
let kp = self.get_keypair();
Ok(kp.pubkey())
}
fn try_sign_message(
&self,
message: &[u8],
) -> Result<solana_sdk::signature::Signature, solana_sdk::signer::SignerError> {
let kp = self.get_keypair();
Ok(kp.sign_message(message))
}
fn is_interactive(&self) -> bool {
true
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct TokenAccountData {
mint: String,
token_account: String,
pub mint: String,
pub token_account: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct OpenOrders {
market: String,
open_orders: String,
pub market: String,
pub open_orders: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Market {
name: String,
admin : Vec<u8>,
market_pk: String,
oracle: String,
asks: String,
bids: String,
event_queue: String,
base_vault: String,
quote_vault: String,
base_mint: String,
quote_mint: String,
market_index: u32,
pub name: String,
pub admin: Vec<u8>,
pub market_pk: String,
pub oracle: String,
pub asks: String,
pub bids: String,
pub event_queue: String,
pub base_vault: String,
pub quote_vault: String,
pub base_mint: String,
pub quote_mint: String,
pub market_index: usize,
}
#[derive(Serialize, Deserialize, Clone)]

View File

@ -2,13 +2,18 @@ pub mod bencher;
mod cli;
mod config;
mod metrics;
mod openbook;
mod solana_runtime;
mod test_registry;
use std::{sync::Arc, time::Duration};
use anyhow::{bail, Context};
use clap::Parser;
use cli::Args;
use config::Config;
use tokio::sync::RwLock;
use solana_sdk::hash::Hash;
#[tokio::main(flavor = "multi_thread", worker_threads = 16)]
async fn main() -> anyhow::Result<()> {
@ -28,9 +33,31 @@ async fn main() -> anyhow::Result<()> {
bail!("No payers");
}
args.generate_test_registry()
let rpc_client = args.get_rpc_client();
let current_hash = rpc_client.get_latest_blockhash().await.unwrap();
let block_hash: Arc<RwLock<Hash>> = Arc::new(RwLock::new(current_hash));
// block hash updater task
{
let block_hash = block_hash.clone();
let rpc_client = args.get_rpc_client();
tokio::spawn(async move {
loop {
let bh = rpc_client.get_latest_blockhash().await;
match bh {
Ok(bh) => {
let mut lock = block_hash.write().await;
*lock = bh;
}
Err(e) => println!("blockhash update error {}", e),
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
});
}
args.generate_test_registry(block_hash)
.start_testing(args, config_json)
.await;
Ok(())
}
}

View File

@ -90,7 +90,10 @@ impl TestingTask for AccountsFetchingTests {
for i in 0..accounts_to_fetch.len() {
if hash_set_known.contains(&accounts_to_fetch[i]) {
if res[i].is_none() {
println!("unable to fetch known account {}", accounts_to_fetch[i]);
println!(
"unable to fetch known account {}",
accounts_to_fetch[i]
);
}
} else if res[i].is_some() {
println!("fetched unknown account should not be possible");
@ -120,7 +123,7 @@ impl TestingTask for AccountsFetchingTests {
Ok(())
}
fn get_name(&self) -> &'static str {
"Accounts Fetching"
fn get_name(&self) -> String {
"Accounts Fetching".to_string()
}
}

View File

@ -21,8 +21,8 @@ impl TestingTask for GetBlockTest {
Ok(())
}
fn get_name(&self) -> &'static str {
"GetBlockTest"
fn get_name(&self) -> String {
"GetBlockTest".to_string()
}
}
@ -39,7 +39,7 @@ impl BenchFn for GetBlockBench {
}
async fn bench_fn(&mut self, rpc_client: Arc<RpcClient>) -> anyhow::Result<()> {
// self.slot += 1;
// self.slot += 1;
rpc_client.get_block(self.slot).await?;
Ok(())
}

View File

@ -16,8 +16,8 @@ impl TestingTask for GetSlotTest {
Ok(())
}
fn get_name(&self) -> &'static str {
"GetSlotTest"
fn get_name(&self) -> String {
"GetSlotTest".to_string()
}
}

View File

@ -1,4 +1,4 @@
pub mod accounts_fetching;
pub mod send_and_get_status_memo;
pub mod get_slot;
pub mod get_block;
pub mod get_slot;
pub mod send_and_get_status_memo;

View File

@ -26,7 +26,9 @@ struct Metric {
pub number_of_unconfirmed_txs: usize,
}
pub struct SendAndConfrimTesting;
pub struct SendAndConfrimTesting {
pub block_hash: Arc<RwLock<Hash>>
}
fn create_memo_tx(msg: &[u8], payer: &Keypair, blockhash: Hash) -> Transaction {
let memo = Pubkey::from_str(MEMO_PROGRAM_ID).unwrap();
@ -117,26 +119,6 @@ impl TestingTask for SendAndConfrimTesting {
) -> anyhow::Result<()> {
println!("started sending and confirming memo transactions");
let rpc_client = Arc::new(RpcClient::new(args.rpc_addr.clone()));
let block_hash: Arc<RwLock<Hash>> = Arc::new(RwLock::new(Hash::default()));
// block hash updater task
{
let block_hash = block_hash.clone();
let rpc_client = rpc_client.clone();
tokio::spawn(async move {
loop {
let bh = rpc_client.get_latest_blockhash().await;
match bh {
Ok(bh) => {
let mut lock = block_hash.write().await;
*lock = bh;
}
Err(e) => println!("blockhash update error {}", e),
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
});
}
let mut run_interval_ms = tokio::time::interval(Duration::from_secs(1));
let nb_runs = args.duration_in_seconds;
@ -146,6 +128,7 @@ impl TestingTask for SendAndConfrimTesting {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
let payer = payers.choose(&mut rng).unwrap();
let payer = Keypair::from_bytes(payer.to_bytes().as_slice()).unwrap();
let block_hash = self.block_hash.clone();
tasks.push(tokio::spawn(send_and_confirm_transactions(
rpc_client.clone(),
NB_MEMO_TRANSACTIONS_SENT_PER_SECOND,
@ -173,7 +156,7 @@ impl TestingTask for SendAndConfrimTesting {
Ok(())
}
fn get_name(&self) -> &'static str {
"Send and confirm memo transaction"
fn get_name(&self) -> String {
"Send and confirm memo transaction".to_string()
}
}

View File

@ -1,11 +1,10 @@
use async_trait::async_trait;
use crate::{cli::Args, config::Config};
#[async_trait]
pub trait TestingTask: Send + Sync {
async fn test(&self, args: Args, config: Config) -> anyhow::Result<()>;
fn get_name(&self) -> &'static str;
fn get_name(&self) -> String;
}
#[derive(Default)]
@ -19,6 +18,7 @@ impl TestRegistry {
}
pub async fn start_testing(self, args: Args, config: Config) {
let tasks = self.tests.into_iter().map(|test| {
let args = args.clone();
let config = config.clone();

@ -1 +1 @@
Subproject commit b7754174bf8c8cbcbda25372fbd0f8dc8b429317
Subproject commit 921d52c58064c3f197600b90929cedb845314a22

1381
yarn.lock

File diff suppressed because it is too large Load Diff