Add storage mining pool to genesis and implement automatic reward redeeming (#4683)
* Add storage mining pool to genesis and implement automatic reward collection * Address review comments
This commit is contained in:
parent
ee68b9800e
commit
119467df59
|
@ -6,6 +6,7 @@
|
||||||
use crate::rpc_client::RpcClient;
|
use crate::rpc_client::RpcClient;
|
||||||
use bincode::{serialize_into, serialized_size};
|
use bincode::{serialize_into, serialized_size};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use solana_sdk::account::Account;
|
||||||
use solana_sdk::client::{AsyncClient, Client, SyncClient};
|
use solana_sdk::client::{AsyncClient, Client, SyncClient};
|
||||||
use solana_sdk::fee_calculator::FeeCalculator;
|
use solana_sdk::fee_calculator::FeeCalculator;
|
||||||
use solana_sdk::hash::Hash;
|
use solana_sdk::hash::Hash;
|
||||||
|
@ -306,11 +307,31 @@ impl SyncClient for ThinClient {
|
||||||
Ok(self.rpc_client().get_account_data(pubkey).ok())
|
Ok(self.rpc_client().get_account_data(pubkey).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_account(&self, pubkey: &Pubkey) -> TransportResult<Option<Account>> {
|
||||||
|
Ok(self.rpc_client().get_account(pubkey).ok())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> {
|
fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> {
|
||||||
let balance = self.rpc_client().get_balance(pubkey)?;
|
let balance = self.rpc_client().get_balance(pubkey)?;
|
||||||
Ok(balance)
|
Ok(balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
|
||||||
|
let index = self.optimizer.experiment();
|
||||||
|
let now = Instant::now();
|
||||||
|
let recent_blockhash = self.rpc_clients[index].get_recent_blockhash();
|
||||||
|
match recent_blockhash {
|
||||||
|
Ok(recent_blockhash) => {
|
||||||
|
self.optimizer.report(index, duration_as_ms(&now.elapsed()));
|
||||||
|
Ok(recent_blockhash)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
self.optimizer.report(index, std::u64::MAX);
|
||||||
|
Err(e)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_signature_status(
|
fn get_signature_status(
|
||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
|
@ -337,22 +358,6 @@ impl SyncClient for ThinClient {
|
||||||
Ok(slot)
|
Ok(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
|
|
||||||
let index = self.optimizer.experiment();
|
|
||||||
let now = Instant::now();
|
|
||||||
let recent_blockhash = self.rpc_clients[index].get_recent_blockhash();
|
|
||||||
match recent_blockhash {
|
|
||||||
Ok(recent_blockhash) => {
|
|
||||||
self.optimizer.report(index, duration_as_ms(&now.elapsed()));
|
|
||||||
Ok(recent_blockhash)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
self.optimizer.report(index, std::u64::MAX);
|
|
||||||
Err(e)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_transaction_count(&self) -> TransportResult<u64> {
|
fn get_transaction_count(&self) -> TransportResult<u64> {
|
||||||
let index = self.optimizer.experiment();
|
let index = self.optimizer.experiment();
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
|
@ -17,13 +17,16 @@ use solana_client::rpc_client::RpcClient;
|
||||||
use solana_client::rpc_request::RpcRequest;
|
use solana_client::rpc_request::RpcRequest;
|
||||||
use solana_client::thin_client::ThinClient;
|
use solana_client::thin_client::ThinClient;
|
||||||
use solana_ed25519_dalek as ed25519_dalek;
|
use solana_ed25519_dalek as ed25519_dalek;
|
||||||
|
use solana_sdk::account_utils::State;
|
||||||
use solana_sdk::client::{AsyncClient, SyncClient};
|
use solana_sdk::client::{AsyncClient, SyncClient};
|
||||||
use solana_sdk::hash::{Hash, Hasher};
|
use solana_sdk::hash::{Hash, Hasher};
|
||||||
use solana_sdk::message::Message;
|
use solana_sdk::message::Message;
|
||||||
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
||||||
use solana_sdk::timing::timestamp;
|
use solana_sdk::timing::timestamp;
|
||||||
use solana_sdk::transaction::Transaction;
|
use solana_sdk::transaction::Transaction;
|
||||||
use solana_sdk::transport::TransportError;
|
use solana_sdk::transport::TransportError;
|
||||||
|
use solana_storage_api::storage_contract::StorageContract;
|
||||||
use solana_storage_api::{get_segment_from_slot, storage_instruction, SLOTS_PER_SEGMENT};
|
use solana_storage_api::{get_segment_from_slot, storage_instruction, SLOTS_PER_SEGMENT};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, BufReader, ErrorKind, Read, Seek, SeekFrom};
|
use std::io::{self, BufReader, ErrorKind, Read, Seek, SeekFrom};
|
||||||
|
@ -298,7 +301,7 @@ impl Replicator {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self, mining_pool_pubkey: Option<Pubkey>) {
|
||||||
info!("waiting for ledger download");
|
info!("waiting for ledger download");
|
||||||
self.thread_handles.pop().unwrap().join().unwrap();
|
self.thread_handles.pop().unwrap().join().unwrap();
|
||||||
self.encrypt_ledger()
|
self.encrypt_ledger()
|
||||||
|
@ -325,6 +328,40 @@ impl Replicator {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.blockhash = storage_blockhash;
|
self.blockhash = storage_blockhash;
|
||||||
|
if let Some(mining_pool_pubkey) = mining_pool_pubkey {
|
||||||
|
self.redeem_rewards(&mining_pool_pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn redeem_rewards(&self, mining_pool_pubkey: &Pubkey) {
|
||||||
|
let nodes = self.cluster_info.read().unwrap().tvu_peers();
|
||||||
|
let client = crate::gossip_service::get_client(&nodes);
|
||||||
|
|
||||||
|
if let Ok(Some(account)) = client.get_account(&self.storage_keypair.pubkey()) {
|
||||||
|
if let Ok(StorageContract::ReplicatorStorage {
|
||||||
|
reward_validations, ..
|
||||||
|
}) = account.state()
|
||||||
|
{
|
||||||
|
if !reward_validations.is_empty() {
|
||||||
|
let ix = storage_instruction::claim_reward(
|
||||||
|
&self.keypair.pubkey(),
|
||||||
|
&self.storage_keypair.pubkey(),
|
||||||
|
mining_pool_pubkey,
|
||||||
|
);
|
||||||
|
let message = Message::new_with_payer(vec![ix], Some(&self.keypair.pubkey()));
|
||||||
|
if let Err(e) = client.send_message(&[&self.keypair], message) {
|
||||||
|
error!("unable to redeem reward, tx failed: {:?}", e);
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"collected mining rewards: Account balance {:?}",
|
||||||
|
client.get_balance(&self.keypair.pubkey())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("Redeem mining reward: No account data found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,22 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
.required(true)
|
.required(true)
|
||||||
.help("Path to file containing the bootstrap leader's storage keypair"),
|
.help("Path to file containing the bootstrap leader's storage keypair"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("storage_mining_pool_keypair_file")
|
||||||
|
.long("storage-mining-pool-keypair")
|
||||||
|
.value_name("KEYPAIR")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("Path to file containing the storage mining pool storage keypair"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("storage_mining_pool_lamports")
|
||||||
|
.long("storage-mining-pool-lamports")
|
||||||
|
.value_name("LAMPORTS")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("Number of lamports to assign to the storage mining pool"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("bootstrap_leader_lamports")
|
Arg::with_name("bootstrap_leader_lamports")
|
||||||
.long("bootstrap-leader-lamports")
|
.long("bootstrap-leader-lamports")
|
||||||
|
@ -251,17 +267,22 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
let bootstrap_stake_keypair_file = matches.value_of("bootstrap_stake_keypair_file").unwrap();
|
let bootstrap_stake_keypair_file = matches.value_of("bootstrap_stake_keypair_file").unwrap();
|
||||||
let bootstrap_storage_keypair_file =
|
let bootstrap_storage_keypair_file =
|
||||||
matches.value_of("bootstrap_storage_keypair_file").unwrap();
|
matches.value_of("bootstrap_storage_keypair_file").unwrap();
|
||||||
|
let storage_mining_pool_keypair = matches
|
||||||
|
.value_of("storage_mining_pool_keypair_file")
|
||||||
|
.unwrap();
|
||||||
let mint_keypair_file = matches.value_of("mint_keypair_file").unwrap();
|
let mint_keypair_file = matches.value_of("mint_keypair_file").unwrap();
|
||||||
let ledger_path = matches.value_of("ledger_path").unwrap();
|
let ledger_path = matches.value_of("ledger_path").unwrap();
|
||||||
let lamports = value_t_or_exit!(matches, "lamports", u64);
|
let lamports = value_t_or_exit!(matches, "lamports", u64);
|
||||||
let bootstrap_leader_lamports = value_t_or_exit!(matches, "bootstrap_leader_lamports", u64);
|
let bootstrap_leader_lamports = value_t_or_exit!(matches, "bootstrap_leader_lamports", u64);
|
||||||
let bootstrap_leader_stake_lamports =
|
let bootstrap_leader_stake_lamports =
|
||||||
value_t_or_exit!(matches, "bootstrap_leader_stake_lamports", u64);
|
value_t_or_exit!(matches, "bootstrap_leader_stake_lamports", u64);
|
||||||
|
let storage_pool_lamports = value_t_or_exit!(matches, "storage_mining_pool_lamports", u64);
|
||||||
|
|
||||||
let bootstrap_leader_keypair = read_keypair(bootstrap_leader_keypair_file)?;
|
let bootstrap_leader_keypair = read_keypair(bootstrap_leader_keypair_file)?;
|
||||||
let bootstrap_vote_keypair = read_keypair(bootstrap_vote_keypair_file)?;
|
let bootstrap_vote_keypair = read_keypair(bootstrap_vote_keypair_file)?;
|
||||||
let bootstrap_stake_keypair = read_keypair(bootstrap_stake_keypair_file)?;
|
let bootstrap_stake_keypair = read_keypair(bootstrap_stake_keypair_file)?;
|
||||||
let bootstrap_storage_keypair = read_keypair(bootstrap_storage_keypair_file)?;
|
let bootstrap_storage_keypair = read_keypair(bootstrap_storage_keypair_file)?;
|
||||||
|
let storage_mining_keypair = read_keypair(storage_mining_pool_keypair)?;
|
||||||
let mint_keypair = read_keypair(mint_keypair_file)?;
|
let mint_keypair = read_keypair(mint_keypair_file)?;
|
||||||
|
|
||||||
let (vote_account, vote_state) = vote_state::create_bootstrap_leader_account(
|
let (vote_account, vote_state) = vote_state::create_bootstrap_leader_account(
|
||||||
|
@ -301,6 +322,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
storage_mining_keypair.pubkey(),
|
||||||
|
storage_contract::create_mining_pool_account(storage_pool_lamports),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
&[
|
&[
|
||||||
solana_bpf_loader_program!(),
|
solana_bpf_loader_program!(),
|
||||||
|
|
|
@ -273,6 +273,8 @@ if [[ $node_type = replicator ]]; then
|
||||||
storage_keypair_path="$SOLANA_CONFIG_DIR"/replicator-storage-keypair$label.json
|
storage_keypair_path="$SOLANA_CONFIG_DIR"/replicator-storage-keypair$label.json
|
||||||
ledger_config_dir=$SOLANA_CONFIG_DIR/replicator-ledger$label
|
ledger_config_dir=$SOLANA_CONFIG_DIR/replicator-ledger$label
|
||||||
configured_flag=$SOLANA_CONFIG_DIR/replicator$label.configured
|
configured_flag=$SOLANA_CONFIG_DIR/replicator$label.configured
|
||||||
|
storage_mining_pool_keypair_path="$SOLANA_CONFIG_DIR"/storage-mining-pool-keypair.json
|
||||||
|
storage_mining_pool_pubkey=$($solana_keygen pubkey "$storage_mining_pool_keypair_path")
|
||||||
|
|
||||||
mkdir -p "$SOLANA_CONFIG_DIR"
|
mkdir -p "$SOLANA_CONFIG_DIR"
|
||||||
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
|
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
|
||||||
|
@ -293,6 +295,7 @@ EOF
|
||||||
default_arg --identity "$identity_keypair_path"
|
default_arg --identity "$identity_keypair_path"
|
||||||
default_arg --storage-keypair "$storage_keypair_path"
|
default_arg --storage-keypair "$storage_keypair_path"
|
||||||
default_arg --ledger "$ledger_config_dir"
|
default_arg --ledger "$ledger_config_dir"
|
||||||
|
default_arg --mining-pool "$storage_mining_pool_pubkey"
|
||||||
|
|
||||||
rsync_entrypoint_url=$(rsync_url "$entrypoint")
|
rsync_entrypoint_url=$(rsync_url "$entrypoint")
|
||||||
elif [[ $node_type = bootstrap_leader ]]; then
|
elif [[ $node_type = bootstrap_leader ]]; then
|
||||||
|
|
|
@ -13,16 +13,19 @@ $solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-keypair.json
|
||||||
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-vote-keypair.json
|
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-vote-keypair.json
|
||||||
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-stake-keypair.json
|
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-stake-keypair.json
|
||||||
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-storage-keypair.json
|
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/bootstrap-leader-storage-keypair.json
|
||||||
|
$solana_keygen new -o "$SOLANA_CONFIG_DIR"/storage-mining-pool-keypair.json
|
||||||
|
|
||||||
args=("$@")
|
args=("$@")
|
||||||
default_arg --bootstrap-leader-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-keypair.json
|
default_arg --bootstrap-leader-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-keypair.json
|
||||||
default_arg --bootstrap-vote-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-vote-keypair.json
|
default_arg --bootstrap-vote-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-vote-keypair.json
|
||||||
default_arg --bootstrap-stake-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-stake-keypair.json
|
default_arg --bootstrap-stake-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-stake-keypair.json
|
||||||
default_arg --bootstrap-storage-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-storage-keypair.json
|
default_arg --bootstrap-storage-keypair "$SOLANA_CONFIG_DIR"/bootstrap-leader-storage-keypair.json
|
||||||
|
default_arg --storage-mining-pool-keypair "$SOLANA_CONFIG_DIR"/storage-mining-pool-keypair.json
|
||||||
default_arg --ledger "$SOLANA_RSYNC_CONFIG_DIR"/ledger
|
default_arg --ledger "$SOLANA_RSYNC_CONFIG_DIR"/ledger
|
||||||
default_arg --mint "$SOLANA_CONFIG_DIR"/mint-keypair.json
|
default_arg --mint "$SOLANA_CONFIG_DIR"/mint-keypair.json
|
||||||
default_arg --lamports 100000000000000
|
default_arg --lamports 100000000000000
|
||||||
default_arg --bootstrap-leader-lamports 424242
|
default_arg --bootstrap-leader-lamports 424242
|
||||||
|
default_arg --storage-mining-pool-lamports 100000000
|
||||||
default_arg --target-lamports-per-signature 42
|
default_arg --target-lamports-per-signature 42
|
||||||
default_arg --target-signatures-per-slot 42
|
default_arg --target-signatures-per-slot 42
|
||||||
default_arg --hashes-per-tick auto
|
default_arg --hashes-per-tick auto
|
||||||
|
|
|
@ -11,8 +11,8 @@ use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::Signature;
|
use solana_sdk::signature::Signature;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub const VALIDATOR_REWARD: u64 = 25;
|
pub const VALIDATOR_REWARD: u64 = 200;
|
||||||
pub const REPLICATOR_REWARD: u64 = 25;
|
pub const REPLICATOR_REWARD: u64 = 200;
|
||||||
// Todo Tune this for actual use cases when replicators are feature complete
|
// Todo Tune this for actual use cases when replicators are feature complete
|
||||||
pub const STORAGE_ACCOUNT_SPACE: u64 = 1024 * 8;
|
pub const STORAGE_ACCOUNT_SPACE: u64 = 1024 * 8;
|
||||||
pub const MAX_PROOFS_PER_SEGMENT: usize = 80;
|
pub const MAX_PROOFS_PER_SEGMENT: usize = 80;
|
||||||
|
@ -99,6 +99,17 @@ pub fn create_validator_storage_account(owner: Pubkey, lamports: u64) -> Account
|
||||||
storage_account
|
storage_account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utility function, used by genesis
|
||||||
|
pub fn create_mining_pool_account(lamports: u64) -> Account {
|
||||||
|
let mut storage_account = Account::new(lamports, STORAGE_ACCOUNT_SPACE as usize, &crate::id());
|
||||||
|
|
||||||
|
storage_account
|
||||||
|
.set_state(&StorageContract::MiningPool)
|
||||||
|
.expect("set_state");
|
||||||
|
|
||||||
|
storage_account
|
||||||
|
}
|
||||||
|
|
||||||
pub struct StorageAccount<'a> {
|
pub struct StorageAccount<'a> {
|
||||||
pub(crate) id: Pubkey,
|
pub(crate) id: Pubkey,
|
||||||
account: &'a mut Account,
|
account: &'a mut Account,
|
||||||
|
|
|
@ -2,11 +2,20 @@ use clap::{crate_description, crate_name, crate_version, App, Arg};
|
||||||
use solana::cluster_info::{Node, FULLNODE_PORT_RANGE};
|
use solana::cluster_info::{Node, FULLNODE_PORT_RANGE};
|
||||||
use solana::contact_info::ContactInfo;
|
use solana::contact_info::ContactInfo;
|
||||||
use solana::replicator::Replicator;
|
use solana::replicator::Replicator;
|
||||||
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
|
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
// Return an error if a pubkey cannot be parsed.
|
||||||
|
fn is_pubkey(string: String) -> Result<(), String> {
|
||||||
|
match string.parse::<Pubkey>() {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(format!("{:?}", err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
|
@ -21,6 +30,14 @@ fn main() {
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("File containing an identity (keypair)"),
|
.help("File containing an identity (keypair)"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("storage_mining_pool_pubkey")
|
||||||
|
.long("mining-pool")
|
||||||
|
.value_name("PUBKEY_BASE58_STR")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("The public key of the storage mining pool"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("entrypoint")
|
Arg::with_name("entrypoint")
|
||||||
.short("n")
|
.short("n")
|
||||||
|
@ -69,6 +86,10 @@ fn main() {
|
||||||
Keypair::new()
|
Keypair::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let storage_mining_pool_pubkey = matches
|
||||||
|
.value_of("storage_mining_pool_pubkey")
|
||||||
|
.map(|value| value.parse::<Pubkey>().unwrap());
|
||||||
|
|
||||||
let entrypoint_addr = matches
|
let entrypoint_addr = matches
|
||||||
.value_of("entrypoint")
|
.value_of("entrypoint")
|
||||||
.map(|entrypoint| {
|
.map(|entrypoint| {
|
||||||
|
@ -101,6 +122,6 @@ fn main() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
replicator.run();
|
replicator.run(storage_mining_pool_pubkey);
|
||||||
replicator.close();
|
replicator.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::bank::Bank;
|
use crate::bank::Bank;
|
||||||
|
use solana_sdk::account::Account;
|
||||||
use solana_sdk::client::{AsyncClient, Client, SyncClient};
|
use solana_sdk::client::{AsyncClient, Client, SyncClient};
|
||||||
use solana_sdk::fee_calculator::FeeCalculator;
|
use solana_sdk::fee_calculator::FeeCalculator;
|
||||||
use solana_sdk::hash::Hash;
|
use solana_sdk::hash::Hash;
|
||||||
|
@ -95,6 +96,10 @@ impl SyncClient for BankClient {
|
||||||
Ok(self.bank.get_account(pubkey).map(|account| account.data))
|
Ok(self.bank.get_account(pubkey).map(|account| account.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_account(&self, pubkey: &Pubkey) -> Result<Option<Account>> {
|
||||||
|
Ok(self.bank.get_account(pubkey))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
|
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
|
||||||
Ok(self.bank.get_balance(pubkey))
|
Ok(self.bank.get_balance(pubkey))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//! Asynchronous implementations are expected to create transactions, sign them, and send
|
//! Asynchronous implementations are expected to create transactions, sign them, and send
|
||||||
//! them but without waiting to see if the server accepted it.
|
//! them but without waiting to see if the server accepted it.
|
||||||
|
|
||||||
|
use crate::account::Account;
|
||||||
use crate::fee_calculator::FeeCalculator;
|
use crate::fee_calculator::FeeCalculator;
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
use crate::instruction::Instruction;
|
use crate::instruction::Instruction;
|
||||||
|
@ -37,6 +38,9 @@ pub trait SyncClient {
|
||||||
/// Get an account or None if not found.
|
/// Get an account or None if not found.
|
||||||
fn get_account_data(&self, pubkey: &Pubkey) -> Result<Option<Vec<u8>>>;
|
fn get_account_data(&self, pubkey: &Pubkey) -> Result<Option<Vec<u8>>>;
|
||||||
|
|
||||||
|
/// Get an account or None if not found.
|
||||||
|
fn get_account(&self, pubkey: &Pubkey) -> Result<Option<Account>>;
|
||||||
|
|
||||||
/// Get account balance or 0 if not found.
|
/// Get account balance or 0 if not found.
|
||||||
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64>;
|
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue