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 bincode::{serialize_into, serialized_size};
|
||||
use log::*;
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::client::{AsyncClient, Client, SyncClient};
|
||||
use solana_sdk::fee_calculator::FeeCalculator;
|
||||
use solana_sdk::hash::Hash;
|
||||
|
@ -306,11 +307,31 @@ impl SyncClient for ThinClient {
|
|||
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> {
|
||||
let balance = self.rpc_client().get_balance(pubkey)?;
|
||||
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(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
|
@ -337,22 +358,6 @@ impl SyncClient for ThinClient {
|
|||
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> {
|
||||
let index = self.optimizer.experiment();
|
||||
let now = Instant::now();
|
||||
|
|
|
@ -17,13 +17,16 @@ use solana_client::rpc_client::RpcClient;
|
|||
use solana_client::rpc_request::RpcRequest;
|
||||
use solana_client::thin_client::ThinClient;
|
||||
use solana_ed25519_dalek as ed25519_dalek;
|
||||
use solana_sdk::account_utils::State;
|
||||
use solana_sdk::client::{AsyncClient, SyncClient};
|
||||
use solana_sdk::hash::{Hash, Hasher};
|
||||
use solana_sdk::message::Message;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
||||
use solana_sdk::timing::timestamp;
|
||||
use solana_sdk::transaction::Transaction;
|
||||
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 std::fs::File;
|
||||
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");
|
||||
self.thread_handles.pop().unwrap().join().unwrap();
|
||||
self.encrypt_ledger()
|
||||
|
@ -325,6 +328,40 @@ impl Replicator {
|
|||
}
|
||||
};
|
||||
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)
|
||||
.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::with_name("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_storage_keypair_file =
|
||||
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 ledger_path = matches.value_of("ledger_path").unwrap();
|
||||
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_stake_lamports =
|
||||
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_vote_keypair = read_keypair(bootstrap_vote_keypair_file)?;
|
||||
let bootstrap_stake_keypair = read_keypair(bootstrap_stake_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 (vote_account, vote_state) = vote_state::create_bootstrap_leader_account(
|
||||
|
@ -301,6 +322,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
1,
|
||||
),
|
||||
),
|
||||
(
|
||||
storage_mining_keypair.pubkey(),
|
||||
storage_contract::create_mining_pool_account(storage_pool_lamports),
|
||||
),
|
||||
],
|
||||
&[
|
||||
solana_bpf_loader_program!(),
|
||||
|
|
|
@ -273,6 +273,8 @@ if [[ $node_type = replicator ]]; then
|
|||
storage_keypair_path="$SOLANA_CONFIG_DIR"/replicator-storage-keypair$label.json
|
||||
ledger_config_dir=$SOLANA_CONFIG_DIR/replicator-ledger$label
|
||||
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"
|
||||
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
|
||||
|
@ -293,6 +295,7 @@ EOF
|
|||
default_arg --identity "$identity_keypair_path"
|
||||
default_arg --storage-keypair "$storage_keypair_path"
|
||||
default_arg --ledger "$ledger_config_dir"
|
||||
default_arg --mining-pool "$storage_mining_pool_pubkey"
|
||||
|
||||
rsync_entrypoint_url=$(rsync_url "$entrypoint")
|
||||
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-stake-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=("$@")
|
||||
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-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 --storage-mining-pool-keypair "$SOLANA_CONFIG_DIR"/storage-mining-pool-keypair.json
|
||||
default_arg --ledger "$SOLANA_RSYNC_CONFIG_DIR"/ledger
|
||||
default_arg --mint "$SOLANA_CONFIG_DIR"/mint-keypair.json
|
||||
default_arg --lamports 100000000000000
|
||||
default_arg --bootstrap-leader-lamports 424242
|
||||
default_arg --storage-mining-pool-lamports 100000000
|
||||
default_arg --target-lamports-per-signature 42
|
||||
default_arg --target-signatures-per-slot 42
|
||||
default_arg --hashes-per-tick auto
|
||||
|
|
|
@ -11,8 +11,8 @@ use solana_sdk::pubkey::Pubkey;
|
|||
use solana_sdk::signature::Signature;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub const VALIDATOR_REWARD: u64 = 25;
|
||||
pub const REPLICATOR_REWARD: u64 = 25;
|
||||
pub const VALIDATOR_REWARD: u64 = 200;
|
||||
pub const REPLICATOR_REWARD: u64 = 200;
|
||||
// Todo Tune this for actual use cases when replicators are feature complete
|
||||
pub const STORAGE_ACCOUNT_SPACE: u64 = 1024 * 8;
|
||||
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
|
||||
}
|
||||
|
||||
// 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(crate) id: Pubkey,
|
||||
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::contact_info::ContactInfo;
|
||||
use solana::replicator::Replicator;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
|
||||
use std::net::SocketAddr;
|
||||
use std::process::exit;
|
||||
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() {
|
||||
solana_logger::setup();
|
||||
|
||||
|
@ -21,6 +30,14 @@ fn main() {
|
|||
.takes_value(true)
|
||||
.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::with_name("entrypoint")
|
||||
.short("n")
|
||||
|
@ -69,6 +86,10 @@ fn main() {
|
|||
Keypair::new()
|
||||
};
|
||||
|
||||
let storage_mining_pool_pubkey = matches
|
||||
.value_of("storage_mining_pool_pubkey")
|
||||
.map(|value| value.parse::<Pubkey>().unwrap());
|
||||
|
||||
let entrypoint_addr = matches
|
||||
.value_of("entrypoint")
|
||||
.map(|entrypoint| {
|
||||
|
@ -101,6 +122,6 @@ fn main() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
replicator.run();
|
||||
replicator.run(storage_mining_pool_pubkey);
|
||||
replicator.close();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::bank::Bank;
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::client::{AsyncClient, Client, SyncClient};
|
||||
use solana_sdk::fee_calculator::FeeCalculator;
|
||||
use solana_sdk::hash::Hash;
|
||||
|
@ -95,6 +96,10 @@ impl SyncClient for BankClient {
|
|||
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> {
|
||||
Ok(self.bank.get_balance(pubkey))
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//! Asynchronous implementations are expected to create transactions, sign them, and send
|
||||
//! them but without waiting to see if the server accepted it.
|
||||
|
||||
use crate::account::Account;
|
||||
use crate::fee_calculator::FeeCalculator;
|
||||
use crate::hash::Hash;
|
||||
use crate::instruction::Instruction;
|
||||
|
@ -37,6 +38,9 @@ pub trait SyncClient {
|
|||
/// Get an account or None if not found.
|
||||
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.
|
||||
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue