Add storage mining pool (#4364)
* Add storage mining pool * Set gossip port * Add create-storage-mining-pool-account wallet command * Add claim-storage-reward wallet command * Create storage account upfront * Add storage program to genesis * Use STORAGE_ACCOUNT_SPACE * Fix tests * Add wallet commands to create validator/replicator storage accounts * Add create_validator_storage_account() * Storage stage no longer implicitly creates a storage account
This commit is contained in:
parent
6b35e16676
commit
b37d2fde3d
|
@ -80,6 +80,11 @@ dependencies = [
|
|||
"predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_matches"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.11"
|
||||
|
@ -2636,6 +2641,8 @@ dependencies = [
|
|||
"solana-sdk 0.15.0",
|
||||
"solana-stake-api 0.15.0",
|
||||
"solana-stake-program 0.15.0",
|
||||
"solana-storage-api 0.15.0",
|
||||
"solana-storage-program 0.15.0",
|
||||
"solana-vote-api 0.15.0",
|
||||
"solana-vote-program 0.15.0",
|
||||
]
|
||||
|
@ -2692,6 +2699,7 @@ dependencies = [
|
|||
name = "solana-storage-api"
|
||||
version = "0.15.0"
|
||||
dependencies = [
|
||||
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2804,6 +2812,7 @@ dependencies = [
|
|||
"solana-netutil 0.15.0",
|
||||
"solana-sdk 0.15.0",
|
||||
"solana-stake-api 0.15.0",
|
||||
"solana-storage-api 0.15.0",
|
||||
"solana-vote-api 0.15.0",
|
||||
"solana-vote-signer 0.15.0",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3424,6 +3433,7 @@ dependencies = [
|
|||
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
|
||||
"checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
|
||||
"checksum assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e"
|
||||
"checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb37ca32a3d9d88f18d08bac8d28368b8ee1f14f8b08eb62999c51720035b55"
|
||||
"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
|
||||
|
|
|
@ -142,12 +142,19 @@ pub fn kill_entry_and_spend_and_verify_rest(
|
|||
assert!(cluster_nodes.len() >= nodes);
|
||||
let client = create_client(entry_point_info.client_facing_addr(), FULLNODE_PORT_RANGE);
|
||||
let first_two_epoch_slots = MINIMUM_SLOT_LENGTH * 3;
|
||||
|
||||
for ingress_node in &cluster_nodes {
|
||||
client
|
||||
.poll_get_balance(&ingress_node.id)
|
||||
.unwrap_or_else(|err| panic!("Node {} has no balance: {}", ingress_node.id, err));
|
||||
}
|
||||
|
||||
info!("sleeping for 2 leader fortnights");
|
||||
sleep(Duration::from_millis(
|
||||
slot_millis * first_two_epoch_slots as u64,
|
||||
));
|
||||
info!("done sleeping for first 2 warmup epochs");
|
||||
info!("killing entry point");
|
||||
info!("killing entry point: {}", entry_point_info.id);
|
||||
assert!(client.fullnode_exit().unwrap());
|
||||
info!("sleeping for some time");
|
||||
sleep(Duration::from_millis(
|
||||
|
@ -160,10 +167,10 @@ pub fn kill_entry_and_spend_and_verify_rest(
|
|||
}
|
||||
|
||||
let client = create_client(ingress_node.client_facing_addr(), FULLNODE_PORT_RANGE);
|
||||
let bal = client
|
||||
let balance = client
|
||||
.poll_get_balance(&funding_keypair.pubkey())
|
||||
.expect("balance in source");
|
||||
assert!(bal > 0);
|
||||
assert_ne!(balance, 0);
|
||||
|
||||
let mut result = Ok(());
|
||||
let mut retries = 0;
|
||||
|
|
|
@ -387,6 +387,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn validator_exit() {
|
||||
solana_logger::setup();
|
||||
let leader_keypair = Keypair::new();
|
||||
let leader_node = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use solana_client::thin_client::create_client;
|
|||
use solana_client::thin_client::ThinClient;
|
||||
use solana_sdk::client::SyncClient;
|
||||
use solana_sdk::genesis_block::GenesisBlock;
|
||||
use solana_sdk::message::Message;
|
||||
use solana_sdk::poh_config::PohConfig;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
|
@ -19,6 +20,7 @@ use solana_sdk::timing::DEFAULT_SLOTS_PER_EPOCH;
|
|||
use solana_sdk::timing::DEFAULT_TICKS_PER_SLOT;
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use solana_stake_api::stake_instruction;
|
||||
use solana_storage_api::storage_instruction;
|
||||
use solana_vote_api::vote_instruction;
|
||||
use solana_vote_api::vote_state::VoteState;
|
||||
use std::collections::HashMap;
|
||||
|
@ -120,6 +122,7 @@ impl LocalCluster {
|
|||
mut genesis_block,
|
||||
mint_keypair,
|
||||
voting_keypair,
|
||||
storage_keypair,
|
||||
} = create_genesis_block_with_leader(
|
||||
config.cluster_lamports,
|
||||
&leader_pubkey,
|
||||
|
@ -135,7 +138,7 @@ impl LocalCluster {
|
|||
let (genesis_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_block);
|
||||
let leader_ledger_path = tmp_copy_blocktree!(&genesis_ledger_path);
|
||||
let leader_contact_info = leader_node.info.clone();
|
||||
let leader_storage_keypair = Arc::new(Keypair::new());
|
||||
let leader_storage_keypair = Arc::new(storage_keypair);
|
||||
let leader_voting_keypair = Arc::new(voting_keypair);
|
||||
let leader_server = Fullnode::new(
|
||||
leader_node,
|
||||
|
@ -238,12 +241,12 @@ impl LocalCluster {
|
|||
// setup as a listener
|
||||
info!("listener {} ", validator_pubkey,);
|
||||
} else {
|
||||
// Send each validator some lamports to vote
|
||||
// Give the validator some lamports to setup vote and storage accounts
|
||||
let validator_balance = Self::transfer_with_client(
|
||||
&client,
|
||||
&self.funding_keypair,
|
||||
&validator_pubkey,
|
||||
stake * 2 + 1,
|
||||
stake * 2 + 2,
|
||||
);
|
||||
info!(
|
||||
"validator {} balance {}",
|
||||
|
@ -257,6 +260,9 @@ impl LocalCluster {
|
|||
stake,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Self::setup_storage_account(&client, &storage_keypair, &validator_keypair, false)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let voting_keypair = Arc::new(voting_keypair);
|
||||
|
@ -298,21 +304,24 @@ impl LocalCluster {
|
|||
|
||||
fn add_replicator(&mut self) {
|
||||
let replicator_keypair = Arc::new(Keypair::new());
|
||||
let replicator_id = replicator_keypair.pubkey();
|
||||
let replicator_pubkey = replicator_keypair.pubkey();
|
||||
let storage_keypair = Arc::new(Keypair::new());
|
||||
let storage_id = storage_keypair.pubkey();
|
||||
let storage_pubkey = storage_keypair.pubkey();
|
||||
let client = create_client(
|
||||
self.entry_point_info.client_facing_addr(),
|
||||
FULLNODE_PORT_RANGE,
|
||||
);
|
||||
|
||||
// Give the replicator some lamports to setup its storage accounts
|
||||
Self::transfer_with_client(
|
||||
&client,
|
||||
&self.funding_keypair,
|
||||
&replicator_keypair.pubkey(),
|
||||
1,
|
||||
42,
|
||||
);
|
||||
let replicator_node = Node::new_localhost_replicator(&replicator_id);
|
||||
let replicator_node = Node::new_localhost_replicator(&replicator_pubkey);
|
||||
|
||||
Self::setup_storage_account(&client, &storage_keypair, &replicator_keypair, true).unwrap();
|
||||
|
||||
let (replicator_ledger_path, _blockhash) = create_new_tmp_ledger!(&self.genesis_block);
|
||||
let replicator = Replicator::new(
|
||||
|
@ -322,12 +331,12 @@ impl LocalCluster {
|
|||
replicator_keypair,
|
||||
storage_keypair,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|err| panic!("Replicator::new() failed: {:?}", err));
|
||||
|
||||
self.replicators.push(replicator);
|
||||
self.replicator_infos.insert(
|
||||
replicator_id,
|
||||
ReplicatorInfo::new(storage_id, replicator_ledger_path),
|
||||
replicator_pubkey,
|
||||
ReplicatorInfo::new(storage_pubkey, replicator_ledger_path),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -464,6 +473,36 @@ impl LocalCluster {
|
|||
"expected successful vote account registration",
|
||||
))
|
||||
}
|
||||
|
||||
fn setup_storage_account(
|
||||
client: &ThinClient,
|
||||
storage_keypair: &Keypair,
|
||||
from_keypair: &Arc<Keypair>,
|
||||
replicator: bool,
|
||||
) -> Result<()> {
|
||||
let message = Message::new_with_payer(
|
||||
if replicator {
|
||||
storage_instruction::create_replicator_storage_account(
|
||||
&from_keypair.pubkey(),
|
||||
&storage_keypair.pubkey(),
|
||||
1,
|
||||
)
|
||||
} else {
|
||||
storage_instruction::create_validator_storage_account(
|
||||
&from_keypair.pubkey(),
|
||||
&storage_keypair.pubkey(),
|
||||
1,
|
||||
)
|
||||
},
|
||||
Some(&from_keypair.pubkey()),
|
||||
);
|
||||
let signer_keys = vec![from_keypair.as_ref()];
|
||||
let blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
let mut transaction = Transaction::new(&signer_keys, message, blockhash);
|
||||
client
|
||||
.retry_transfer(&from_keypair, &mut transaction, 5)
|
||||
.map(|_signature| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl Cluster for LocalCluster {
|
||||
|
@ -529,7 +568,7 @@ mod test {
|
|||
let num_replicators = 1;
|
||||
let config = ClusterConfig {
|
||||
fullnode_config,
|
||||
num_replicators: 1,
|
||||
num_replicators,
|
||||
node_stakes: vec![3; NUM_NODES],
|
||||
cluster_lamports: 100,
|
||||
ticks_per_slot: 8,
|
||||
|
|
|
@ -290,8 +290,8 @@ impl Replicator {
|
|||
.expect("ledger encrypt not successful");
|
||||
loop {
|
||||
self.create_sampling_offsets();
|
||||
if self.sample_file_to_create_mining_hash().is_err() {
|
||||
info!("Error sampling file, exiting...");
|
||||
if let Err(err) = self.sample_file_to_create_mining_hash() {
|
||||
warn!("Error sampling file, exiting: {:?}", err);
|
||||
break;
|
||||
}
|
||||
self.submit_mining_proof();
|
||||
|
@ -365,7 +365,10 @@ impl Replicator {
|
|||
self.num_chacha_blocks = num_encrypted_bytes / CHACHA_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
info!("Done encrypting the ledger");
|
||||
info!(
|
||||
"Done encrypting the ledger: {:?}",
|
||||
self.ledger_data_file_encrypted
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -406,29 +409,30 @@ impl Replicator {
|
|||
if client.poll_get_balance(&keypair.pubkey())? == 0 {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"No account has been setup",
|
||||
"keypair account has no balance",
|
||||
))?
|
||||
}
|
||||
|
||||
// check if the account exists
|
||||
let bal = client.poll_get_balance(&storage_keypair.pubkey());
|
||||
if bal.is_err() || bal.unwrap() == 0 {
|
||||
// check if the storage account exists
|
||||
let balance = client.poll_get_balance(&storage_keypair.pubkey());
|
||||
if balance.is_err() || balance.unwrap() == 0 {
|
||||
let (blockhash, _fee_calculator) = client.get_recent_blockhash().expect("blockhash");
|
||||
|
||||
let ix = vec![storage_instruction::create_account(
|
||||
let ix = storage_instruction::create_replicator_storage_account(
|
||||
&keypair.pubkey(),
|
||||
&storage_keypair.pubkey(),
|
||||
1,
|
||||
)];
|
||||
);
|
||||
let tx = Transaction::new_signed_instructions(&[keypair], ix, blockhash);
|
||||
let signature = client.async_send_transaction(tx)?;
|
||||
client
|
||||
.poll_for_signature(&signature)
|
||||
.map_err(|err| match err {
|
||||
TransportError::IoError(e) => e,
|
||||
TransportError::TransactionError(_) => {
|
||||
io::Error::new(ErrorKind::Other, "signature not found")
|
||||
}
|
||||
TransportError::TransactionError(_) => io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"setup_mining_account: signature not found",
|
||||
),
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -504,10 +508,11 @@ impl Replicator {
|
|||
.expect("rpc request")
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
info!("max slot: {}", storage_slot);
|
||||
info!("storage slot: {}", storage_slot);
|
||||
if get_segment_from_slot(storage_slot) != 0 {
|
||||
return Ok((storage_blockhash, storage_slot));
|
||||
}
|
||||
info!("waiting for segment...");
|
||||
sleep(Duration::from_secs(5));
|
||||
}
|
||||
Err(Error::new(
|
||||
|
|
|
@ -192,6 +192,15 @@ impl StorageStage {
|
|||
.name("solana-storage-create-accounts".to_string())
|
||||
.spawn(move || {
|
||||
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
|
||||
{
|
||||
let working_bank = bank_forks.read().unwrap().working_bank();
|
||||
let storage_account = working_bank.get_account(&storage_keypair.pubkey());
|
||||
if storage_account.is_none() {
|
||||
warn!("Storage account not found: {}", storage_keypair.pubkey());
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match instruction_receiver.recv_timeout(Duration::from_secs(1)) {
|
||||
Ok(instruction) => {
|
||||
|
@ -238,22 +247,29 @@ impl StorageStage {
|
|||
) -> io::Result<()> {
|
||||
let working_bank = bank_forks.read().unwrap().working_bank();
|
||||
let blockhash = working_bank.confirmed_last_blockhash();
|
||||
let mut instructions = vec![];
|
||||
let signer_keys = vec![keypair.as_ref(), storage_keypair.as_ref()];
|
||||
let keypair_balance = working_bank.get_balance(&keypair.pubkey());
|
||||
|
||||
if keypair_balance == 0 {
|
||||
warn!("keypair account balance empty: {}", keypair.pubkey(),);
|
||||
} else {
|
||||
debug!(
|
||||
"keypair account balance: {}: {}",
|
||||
keypair.pubkey(),
|
||||
keypair_balance
|
||||
);
|
||||
}
|
||||
if working_bank
|
||||
.get_account(&storage_keypair.pubkey())
|
||||
.is_none()
|
||||
{
|
||||
let create_instruction = storage_instruction::create_account(
|
||||
&keypair.pubkey(),
|
||||
&storage_keypair.pubkey(),
|
||||
1,
|
||||
warn!(
|
||||
"storage account does not exist: {}",
|
||||
storage_keypair.pubkey()
|
||||
);
|
||||
instructions.push(create_instruction);
|
||||
info!("storage account requested");
|
||||
}
|
||||
instructions.push(instruction);
|
||||
let message = Message::new_with_payer(instructions, Some(&signer_keys[0].pubkey()));
|
||||
|
||||
let signer_keys = vec![keypair.as_ref(), storage_keypair.as_ref()];
|
||||
let message = Message::new_with_payer(vec![instruction], Some(&signer_keys[0].pubkey()));
|
||||
let transaction = Transaction::new(&signer_keys, message, blockhash);
|
||||
|
||||
transactions_socket.send_to(
|
||||
|
|
|
@ -25,7 +25,7 @@ use solana_sdk::signature::{read_keypair, KeypairUtil};
|
|||
use solana_sdk::system_program;
|
||||
use solana_sdk::timing;
|
||||
use solana_stake_api::stake_state;
|
||||
use solana_storage_api::storage_contract::STORAGE_ACCOUNT_SPACE;
|
||||
use solana_storage_api::storage_contract;
|
||||
use solana_vote_api::vote_state;
|
||||
use std::error;
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -216,7 +216,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
// storage account
|
||||
(
|
||||
bootstrap_storage_keypair.pubkey(),
|
||||
Account::new(1, STORAGE_ACCOUNT_SPACE as usize, &solana_storage_api::id()),
|
||||
storage_contract::create_validator_storage_account(1),
|
||||
),
|
||||
],
|
||||
&[
|
||||
|
|
|
@ -73,12 +73,13 @@ rsync_url() { # adds the 'rsync://` prefix to URLs that need it
|
|||
echo "rsync://$url"
|
||||
}
|
||||
|
||||
setup_vote_and_stake_accounts() {
|
||||
setup_validator_accounts() {
|
||||
declare entrypoint_ip=$1
|
||||
declare node_keypair_path=$2
|
||||
declare vote_keypair_path=$3
|
||||
declare stake_keypair_path=$4
|
||||
declare stake=$5
|
||||
declare storage_keypair_path=$5
|
||||
declare stake=$6
|
||||
|
||||
declare node_pubkey
|
||||
node_pubkey=$($solana_keygen pubkey "$node_keypair_path")
|
||||
|
@ -89,6 +90,9 @@ setup_vote_and_stake_accounts() {
|
|||
declare stake_pubkey
|
||||
stake_pubkey=$($solana_keygen pubkey "$stake_keypair_path")
|
||||
|
||||
declare storage_pubkey
|
||||
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
|
||||
|
||||
if [[ -f "$node_keypair_path".configured ]]; then
|
||||
echo "Vote and stake accounts have already been configured"
|
||||
else
|
||||
|
@ -97,27 +101,30 @@ setup_vote_and_stake_accounts() {
|
|||
|
||||
# Fund the vote account from the node, with the node as the node_pubkey
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
create-vote-account "$vote_pubkey" "$node_pubkey" "$stake" || return $?
|
||||
create-vote-account "$vote_pubkey" "$node_pubkey" "$stake" || return $?
|
||||
|
||||
# Fund the stake account from the node, with the node as the node_pubkey
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
create-stake-account "$stake_pubkey" "$stake" || return $?
|
||||
create-stake-account "$stake_pubkey" "$stake" || return $?
|
||||
|
||||
# Delegate the stake. The transaction fee is paid by the node but the
|
||||
# transaction must be signed by the stake_keypair
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
delegate-stake "$stake_keypair_path" "$vote_pubkey" || return $?
|
||||
delegate-stake "$stake_keypair_path" "$vote_pubkey" || return $?
|
||||
|
||||
# Setup validator storage account
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
create-validator-storage-account "$storage_pubkey" || return $?
|
||||
|
||||
touch "$node_keypair_path".configured
|
||||
fi
|
||||
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
show-vote-account "$vote_pubkey"
|
||||
|
||||
show-vote-account "$vote_pubkey"
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
show-stake-account "$stake_pubkey"
|
||||
|
||||
show-stake-account "$stake_pubkey"
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
show-storage-account "$storage_pubkey"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
@ -132,14 +139,28 @@ ledger_not_setup() {
|
|||
setup_replicator_account() {
|
||||
declare entrypoint_ip=$1
|
||||
declare node_keypair_path=$2
|
||||
declare stake=$3
|
||||
declare storage_keypair_path=$2
|
||||
declare stake=$4
|
||||
|
||||
declare storage_pubkey
|
||||
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
|
||||
|
||||
if [[ -f "$node_keypair_path".configured ]]; then
|
||||
echo "Replicator account has already been configured"
|
||||
else
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" airdrop "$stake" || return $?
|
||||
|
||||
# Setup replicator storage account
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
create-replicator-storage-account "$storage_keypair_path" || return $?
|
||||
|
||||
touch "$node_keypair_path".configured
|
||||
fi
|
||||
|
||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||
show-storage-account "$storage_pubkey"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
args=()
|
||||
|
@ -228,7 +249,6 @@ if [[ $node_type = bootstrap_leader ]]; then
|
|||
accounts_config_dir="$SOLANA_CONFIG_DIR"/bootstrap-leader-accounts
|
||||
fullnode_storage_keypair_path=$SOLANA_CONFIG_DIR/bootstrap-leader-storage-keypair.json
|
||||
|
||||
|
||||
default_arg --rpc-port 8899
|
||||
default_arg --rpc-drone-address 127.0.0.1:9900
|
||||
default_arg --gossip-port 8001
|
||||
|
@ -300,11 +320,13 @@ else
|
|||
|
||||
fullnode_pubkey=$($solana_keygen pubkey "$fullnode_keypair_path")
|
||||
fullnode_vote_pubkey=$($solana_keygen pubkey "$fullnode_vote_keypair_path")
|
||||
fullnode_storage_pubkey=$($solana_keygen pubkey "$fullnode_storage_keypair_path")
|
||||
|
||||
cat <<EOF
|
||||
======================[ Fullnode configuration ]======================
|
||||
node pubkey: $fullnode_pubkey
|
||||
vote pubkey: $fullnode_vote_pubkey
|
||||
storage pubkey: $fullnode_storage_pubkey
|
||||
ledger: $ledger_config_dir
|
||||
accounts: $accounts_config_dir
|
||||
======================================================================
|
||||
|
@ -362,9 +384,17 @@ while true; do
|
|||
trap '[[ -n $pid ]] && kill "$pid" >/dev/null 2>&1 && wait "$pid"' INT TERM ERR
|
||||
|
||||
if [[ $node_type = validator ]] && ((stake)); then
|
||||
setup_vote_and_stake_accounts "${entrypoint_address%:*}" "$fullnode_keypair_path" "$fullnode_vote_keypair_path" "$fullnode_stake_keypair_path" "$stake"
|
||||
setup_validator_accounts "${entrypoint_address%:*}" \
|
||||
"$fullnode_keypair_path" \
|
||||
"$fullnode_vote_keypair_path" \
|
||||
"$fullnode_stake_keypair_path" \
|
||||
"$fullnode_storage_keypair_path" \
|
||||
"$stake"
|
||||
elif [[ $node_type = replicator ]] && ((stake)); then
|
||||
setup_replicator_account "${entrypoint_address%:*}" "$replicator_keypair_path" "$stake"
|
||||
setup_replicator_account "${entrypoint_address%:*}" \
|
||||
"$replicator_keypair_path" \
|
||||
"$replicator_storage_keypair_path" \
|
||||
"$stake"
|
||||
fi
|
||||
|
||||
echo "$PS4$program ${args[*]}"
|
||||
|
|
|
@ -15,6 +15,7 @@ serde = "1.0.91"
|
|||
serde_derive = "1.0.91"
|
||||
solana-logger = { path = "../../logger", version = "0.15.0" }
|
||||
solana-sdk = { path = "../../sdk", version = "0.15.0" }
|
||||
assert_matches = "1.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../../runtime", version = "0.15.0" }
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::get_segment_from_slot;
|
|||
use log::*;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::account::KeyedAccount;
|
||||
use solana_sdk::account_utils::State;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::instruction::InstructionError;
|
||||
|
@ -42,8 +43,7 @@ pub struct CheckedProof {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum StorageContract {
|
||||
//don't move this
|
||||
Default,
|
||||
Uninitialized, // Must be first (aka, 0)
|
||||
|
||||
ValidatorStorage {
|
||||
slot: u64,
|
||||
|
@ -58,6 +58,24 @@ pub enum StorageContract {
|
|||
/// Multiple validators can validate the same set of proofs so it needs a Vec
|
||||
reward_validations: HashMap<usize, HashMap<Hash, Vec<CheckedProof>>>,
|
||||
},
|
||||
|
||||
MiningPool,
|
||||
}
|
||||
|
||||
// utility function, used by Bank, tests, genesis
|
||||
pub fn create_validator_storage_account(lamports: u64) -> Account {
|
||||
let mut storage_account = Account::new(lamports, STORAGE_ACCOUNT_SPACE as usize, &crate::id());
|
||||
|
||||
storage_account
|
||||
.set_state(&StorageContract::ValidatorStorage {
|
||||
slot: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: HashMap::new(),
|
||||
reward_validations: HashMap::new(),
|
||||
})
|
||||
.expect("set_state");
|
||||
|
||||
storage_account
|
||||
}
|
||||
|
||||
pub struct StorageAccount<'a> {
|
||||
|
@ -69,6 +87,44 @@ impl<'a> StorageAccount<'a> {
|
|||
Self { account }
|
||||
}
|
||||
|
||||
pub fn initialize_mining_pool(&mut self) -> Result<(), InstructionError> {
|
||||
let storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Uninitialized = storage_contract {
|
||||
*storage_contract = StorageContract::MiningPool;
|
||||
self.account.set_state(storage_contract)
|
||||
} else {
|
||||
Err(InstructionError::AccountAlreadyInitialized)?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_replicator_storage(&mut self) -> Result<(), InstructionError> {
|
||||
let storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Uninitialized = storage_contract {
|
||||
*storage_contract = StorageContract::ReplicatorStorage {
|
||||
proofs: HashMap::new(),
|
||||
reward_validations: HashMap::new(),
|
||||
};
|
||||
self.account.set_state(storage_contract)
|
||||
} else {
|
||||
Err(InstructionError::AccountAlreadyInitialized)?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_validator_storage(&mut self) -> Result<(), InstructionError> {
|
||||
let storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Uninitialized = storage_contract {
|
||||
*storage_contract = StorageContract::ValidatorStorage {
|
||||
slot: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: HashMap::new(),
|
||||
reward_validations: HashMap::new(),
|
||||
};
|
||||
self.account.set_state(storage_contract)
|
||||
} else {
|
||||
Err(InstructionError::AccountAlreadyInitialized)?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit_mining_proof(
|
||||
&mut self,
|
||||
id: Pubkey,
|
||||
|
@ -78,13 +134,6 @@ impl<'a> StorageAccount<'a> {
|
|||
current_slot: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Default = storage_contract {
|
||||
*storage_contract = StorageContract::ReplicatorStorage {
|
||||
proofs: HashMap::new(),
|
||||
reward_validations: HashMap::new(),
|
||||
};
|
||||
};
|
||||
|
||||
if let StorageContract::ReplicatorStorage { proofs, .. } = &mut storage_contract {
|
||||
let segment_index = get_segment_from_slot(slot);
|
||||
let current_segment = get_segment_from_slot(current_slot);
|
||||
|
@ -120,15 +169,6 @@ impl<'a> StorageAccount<'a> {
|
|||
current_slot: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Default = storage_contract {
|
||||
*storage_contract = StorageContract::ValidatorStorage {
|
||||
slot: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: HashMap::new(),
|
||||
reward_validations: HashMap::new(),
|
||||
};
|
||||
};
|
||||
|
||||
if let StorageContract::ValidatorStorage {
|
||||
slot: state_slot,
|
||||
hash: state_hash,
|
||||
|
@ -165,15 +205,6 @@ impl<'a> StorageAccount<'a> {
|
|||
replicator_accounts: &mut [StorageAccount],
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Default = storage_contract {
|
||||
*storage_contract = StorageContract::ValidatorStorage {
|
||||
slot: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: HashMap::new(),
|
||||
reward_validations: HashMap::new(),
|
||||
};
|
||||
};
|
||||
|
||||
if let StorageContract::ValidatorStorage {
|
||||
slot: state_slot,
|
||||
lockout_validations,
|
||||
|
@ -241,13 +272,11 @@ impl<'a> StorageAccount<'a> {
|
|||
|
||||
pub fn claim_storage_reward(
|
||||
&mut self,
|
||||
mining_pool: &mut KeyedAccount,
|
||||
slot: u64,
|
||||
current_slot: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::Default = storage_contract {
|
||||
Err(InstructionError::InvalidArgument)?
|
||||
};
|
||||
|
||||
if let StorageContract::ValidatorStorage {
|
||||
reward_validations,
|
||||
|
@ -266,14 +295,15 @@ impl<'a> StorageAccount<'a> {
|
|||
);
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
let _num_validations = count_valid_proofs(
|
||||
let num_validations = count_valid_proofs(
|
||||
&reward_validations
|
||||
.remove(&claim_segment)
|
||||
.map(|mut proofs| proofs.drain().map(|(_, proof)| proof).collect::<Vec<_>>())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
// TODO can't just create lamports out of thin air
|
||||
// self.account.lamports += TOTAL_VALIDATOR_REWARDS * num_validations;
|
||||
let reward = TOTAL_VALIDATOR_REWARDS * num_validations;
|
||||
mining_pool.account.lamports -= reward;
|
||||
self.account.lamports += reward;
|
||||
self.account.set_state(storage_contract)
|
||||
} else if let StorageContract::ReplicatorStorage {
|
||||
proofs,
|
||||
|
@ -288,7 +318,7 @@ impl<'a> StorageAccount<'a> {
|
|||
|| !reward_validations.contains_key(&claim_segment)
|
||||
|| !proofs.contains_key(&claim_segment)
|
||||
{
|
||||
debug!(
|
||||
info!(
|
||||
"current {:?}, claim {:?}, have rewards for {:?} segments",
|
||||
claim_index,
|
||||
claim_segment,
|
||||
|
@ -317,10 +347,15 @@ impl<'a> StorageAccount<'a> {
|
|||
})
|
||||
.unwrap_or_default();
|
||||
let _num_validations = count_valid_proofs(&checked_proofs);
|
||||
// TODO can't just create lamports out of thin air
|
||||
// self.account.lamports += num_validations
|
||||
// * TOTAL_REPLICATOR_REWARDS
|
||||
// * (num_validations / reward_validations[claim_segment].len() as u64);
|
||||
|
||||
// TODO enable when rewards are working
|
||||
/*
|
||||
let reward = num_validations
|
||||
* TOTAL_REPLICATOR_REWARDS
|
||||
* (num_validations / reward_validations[&claim_segment].len() as u64);
|
||||
mining_pool.account.lamports -= reward;
|
||||
self.account.lamports += reward;
|
||||
*/
|
||||
self.account.set_state(storage_contract)
|
||||
} else {
|
||||
Err(InstructionError::InvalidArgument)?
|
||||
|
@ -399,7 +434,7 @@ mod tests {
|
|||
fn test_account_data() {
|
||||
solana_logger::setup();
|
||||
let mut account = Account::default();
|
||||
account.data.resize(4 * 1024, 0);
|
||||
account.data.resize(STORAGE_ACCOUNT_SPACE as usize, 0);
|
||||
let storage_account = StorageAccount::new(&mut account);
|
||||
// pretend it's a validator op code
|
||||
let mut contract = storage_account.account.state().unwrap();
|
||||
|
@ -454,9 +489,12 @@ mod tests {
|
|||
// account has no space
|
||||
process_validation(&mut account, segment_index, &proof, &checked_proof).unwrap_err();
|
||||
|
||||
account.account.data.resize(4 * 1024, 0);
|
||||
account
|
||||
.account
|
||||
.data
|
||||
.resize(STORAGE_ACCOUNT_SPACE as usize, 0);
|
||||
let storage_contract = &mut account.account.state().unwrap();
|
||||
if let StorageContract::Default = storage_contract {
|
||||
if let StorageContract::Uninitialized = storage_contract {
|
||||
let mut proof_map = HashMap::new();
|
||||
proof_map.insert(proof.sha_state, proof.clone());
|
||||
let mut proofs = HashMap::new();
|
||||
|
|
|
@ -9,6 +9,14 @@ use solana_sdk::system_instruction;
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum StorageInstruction {
|
||||
/// Initialize the account as a mining pool, validator or replicator
|
||||
///
|
||||
/// Expects 1 Account:
|
||||
/// 0 - Account to be initialized
|
||||
InitializeMiningPool,
|
||||
InitializeValidatorStorage,
|
||||
InitializeReplicatorStorage,
|
||||
|
||||
SubmitMiningProof {
|
||||
sha_state: Hash,
|
||||
slot: u64,
|
||||
|
@ -18,6 +26,11 @@ pub enum StorageInstruction {
|
|||
hash: Hash,
|
||||
slot: u64,
|
||||
},
|
||||
/// Redeem storage reward credits
|
||||
///
|
||||
/// Expects 1 Account:
|
||||
/// 0 - Storage account with credits to redeem
|
||||
/// 1 - MiningPool account to redeem credits from
|
||||
ClaimStorageReward {
|
||||
slot: u64,
|
||||
},
|
||||
|
@ -27,12 +40,71 @@ pub enum StorageInstruction {
|
|||
},
|
||||
}
|
||||
|
||||
pub fn create_account(from: &Pubkey, to: &Pubkey, lamports: u64) -> Instruction {
|
||||
system_instruction::create_account(&from, to, lamports, STORAGE_ACCOUNT_SPACE, &id())
|
||||
pub fn create_validator_storage_account(
|
||||
from_pubkey: &Pubkey,
|
||||
storage_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> Vec<Instruction> {
|
||||
vec![
|
||||
system_instruction::create_account(
|
||||
from_pubkey,
|
||||
storage_pubkey,
|
||||
lamports,
|
||||
STORAGE_ACCOUNT_SPACE,
|
||||
&id(),
|
||||
),
|
||||
Instruction::new(
|
||||
id(),
|
||||
&StorageInstruction::InitializeValidatorStorage,
|
||||
vec![AccountMeta::new(*storage_pubkey, false)],
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn create_replicator_storage_account(
|
||||
from_pubkey: &Pubkey,
|
||||
storage_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> Vec<Instruction> {
|
||||
vec![
|
||||
system_instruction::create_account(
|
||||
from_pubkey,
|
||||
storage_pubkey,
|
||||
lamports,
|
||||
STORAGE_ACCOUNT_SPACE,
|
||||
&id(),
|
||||
),
|
||||
Instruction::new(
|
||||
id(),
|
||||
&StorageInstruction::InitializeReplicatorStorage,
|
||||
vec![AccountMeta::new(*storage_pubkey, false)],
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn create_mining_pool_account(
|
||||
from_pubkey: &Pubkey,
|
||||
storage_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> Vec<Instruction> {
|
||||
vec![
|
||||
system_instruction::create_account(
|
||||
from_pubkey,
|
||||
storage_pubkey,
|
||||
lamports,
|
||||
STORAGE_ACCOUNT_SPACE,
|
||||
&id(),
|
||||
),
|
||||
Instruction::new(
|
||||
id(),
|
||||
&StorageInstruction::InitializeMiningPool,
|
||||
vec![AccountMeta::new(*storage_pubkey, false)],
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn mining_proof(
|
||||
from_pubkey: &Pubkey,
|
||||
storage_pubkey: &Pubkey,
|
||||
sha_state: Hash,
|
||||
slot: u64,
|
||||
signature: Signature,
|
||||
|
@ -42,12 +114,12 @@ pub fn mining_proof(
|
|||
slot,
|
||||
signature,
|
||||
};
|
||||
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
||||
let account_metas = vec![AccountMeta::new(*storage_pubkey, true)];
|
||||
Instruction::new(id(), &storage_instruction, account_metas)
|
||||
}
|
||||
|
||||
pub fn advertise_recent_blockhash(
|
||||
from_pubkey: &Pubkey,
|
||||
storage_pubkey: &Pubkey,
|
||||
storage_hash: Hash,
|
||||
slot: u64,
|
||||
) -> Instruction {
|
||||
|
@ -55,12 +127,16 @@ pub fn advertise_recent_blockhash(
|
|||
hash: storage_hash,
|
||||
slot,
|
||||
};
|
||||
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
||||
let account_metas = vec![AccountMeta::new(*storage_pubkey, true)];
|
||||
Instruction::new(id(), &storage_instruction, account_metas)
|
||||
}
|
||||
|
||||
pub fn proof_validation(from_pubkey: &Pubkey, slot: u64, proofs: Vec<CheckedProof>) -> Instruction {
|
||||
let mut account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
||||
pub fn proof_validation(
|
||||
storage_pubkey: &Pubkey,
|
||||
slot: u64,
|
||||
proofs: Vec<CheckedProof>,
|
||||
) -> Instruction {
|
||||
let mut account_metas = vec![AccountMeta::new(*storage_pubkey, true)];
|
||||
proofs.iter().for_each(|checked_proof| {
|
||||
account_metas.push(AccountMeta::new(checked_proof.proof.id, false))
|
||||
});
|
||||
|
@ -68,8 +144,15 @@ pub fn proof_validation(from_pubkey: &Pubkey, slot: u64, proofs: Vec<CheckedProo
|
|||
Instruction::new(id(), &storage_instruction, account_metas)
|
||||
}
|
||||
|
||||
pub fn reward_claim(from_pubkey: &Pubkey, slot: u64) -> Instruction {
|
||||
pub fn claim_reward(
|
||||
storage_pubkey: &Pubkey,
|
||||
mining_pool_pubkey: &Pubkey,
|
||||
slot: u64,
|
||||
) -> Instruction {
|
||||
let storage_instruction = StorageInstruction::ClaimStorageReward { slot };
|
||||
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*storage_pubkey, false),
|
||||
AccountMeta::new(*mining_pool_pubkey, false),
|
||||
];
|
||||
Instruction::new(id(), &storage_instruction, account_metas)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
//! storage program
|
||||
//! Receive mining proofs from miners, validate the answers
|
||||
//! and give reward for good proofs.
|
||||
|
||||
use crate::storage_contract::StorageAccount;
|
||||
use crate::storage_instruction::StorageInstruction;
|
||||
use log::*;
|
||||
use solana_sdk::account::KeyedAccount;
|
||||
use solana_sdk::instruction::InstructionError;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
@ -18,30 +16,37 @@ pub fn process_instruction(
|
|||
) -> Result<(), InstructionError> {
|
||||
solana_logger::setup();
|
||||
|
||||
let num_keyed_accounts = keyed_accounts.len();
|
||||
let (me, rest) = keyed_accounts.split_at_mut(1);
|
||||
|
||||
// accounts_keys[0] must be signed
|
||||
let storage_account_pubkey = me[0].signer_key();
|
||||
if storage_account_pubkey.is_none() {
|
||||
info!("account[0] is unsigned");
|
||||
Err(InstructionError::MissingRequiredSignature)?;
|
||||
}
|
||||
let storage_account_pubkey = *storage_account_pubkey.unwrap();
|
||||
|
||||
let me_unsigned = me[0].signer_key().is_none();
|
||||
let storage_account_pubkey = *me[0].unsigned_key();
|
||||
let mut storage_account = StorageAccount::new(&mut me[0].account);
|
||||
let mut rest: Vec<_> = rest
|
||||
.iter_mut()
|
||||
.map(|keyed_account| StorageAccount::new(&mut keyed_account.account))
|
||||
.collect();
|
||||
|
||||
match bincode::deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
||||
StorageInstruction::InitializeMiningPool => {
|
||||
if !rest.is_empty() {
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
storage_account.initialize_mining_pool()
|
||||
}
|
||||
StorageInstruction::InitializeReplicatorStorage => {
|
||||
if !rest.is_empty() {
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
storage_account.initialize_replicator_storage()
|
||||
}
|
||||
StorageInstruction::InitializeValidatorStorage => {
|
||||
if !rest.is_empty() {
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
storage_account.initialize_validator_storage()
|
||||
}
|
||||
StorageInstruction::SubmitMiningProof {
|
||||
sha_state,
|
||||
slot,
|
||||
signature,
|
||||
} => {
|
||||
if num_keyed_accounts != 1 {
|
||||
if me_unsigned || !rest.is_empty() {
|
||||
// This instruction must be signed by `me`
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
storage_account.submit_mining_proof(
|
||||
|
@ -53,9 +58,8 @@ pub fn process_instruction(
|
|||
)
|
||||
}
|
||||
StorageInstruction::AdvertiseStorageRecentBlockhash { hash, slot } => {
|
||||
if num_keyed_accounts != 1 {
|
||||
// keyed_accounts[0] should be the main storage key
|
||||
// to access its data
|
||||
if me_unsigned || !rest.is_empty() {
|
||||
// This instruction must be signed by `me`
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
storage_account.advertise_storage_recent_blockhash(
|
||||
|
@ -65,18 +69,24 @@ pub fn process_instruction(
|
|||
)
|
||||
}
|
||||
StorageInstruction::ClaimStorageReward { slot } => {
|
||||
if num_keyed_accounts != 1 {
|
||||
// keyed_accounts[0] should be the main storage key
|
||||
// to access its data
|
||||
if rest.len() != 1 {
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
storage_account.claim_storage_reward(slot, tick_height / DEFAULT_TICKS_PER_SLOT)
|
||||
storage_account.claim_storage_reward(
|
||||
&mut rest[0],
|
||||
slot,
|
||||
tick_height / DEFAULT_TICKS_PER_SLOT,
|
||||
)
|
||||
}
|
||||
StorageInstruction::ProofValidation { slot, proofs } => {
|
||||
if num_keyed_accounts == 1 {
|
||||
// have to have at least 1 replicator to do any verification
|
||||
if me_unsigned || rest.is_empty() {
|
||||
// This instruction must be signed by `me`
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
let mut rest: Vec<_> = rest
|
||||
.iter_mut()
|
||||
.map(|keyed_account| StorageAccount::new(&mut keyed_account.account))
|
||||
.collect();
|
||||
storage_account.proof_validation(slot, proofs, &mut rest)
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +98,13 @@ mod tests {
|
|||
use crate::id;
|
||||
use crate::storage_contract::{
|
||||
CheckedProof, Proof, ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE,
|
||||
TOTAL_VALIDATOR_REWARDS,
|
||||
};
|
||||
use crate::storage_instruction;
|
||||
use crate::SLOTS_PER_SEGMENT;
|
||||
use assert_matches::assert_matches;
|
||||
use bincode::deserialize;
|
||||
use log::*;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_runtime::bank_client::BankClient;
|
||||
use solana_sdk::account::{create_keyed_accounts, Account};
|
||||
|
@ -99,6 +112,7 @@ mod tests {
|
|||
use solana_sdk::genesis_block::create_genesis_block;
|
||||
use solana_sdk::hash::{hash, Hash};
|
||||
use solana_sdk::instruction::Instruction;
|
||||
use solana_sdk::message::Message;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
||||
use std::sync::Arc;
|
||||
|
@ -127,10 +141,14 @@ mod tests {
|
|||
#[test]
|
||||
fn test_proof_bounds() {
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let account = Account {
|
||||
let mut account = Account {
|
||||
data: vec![0; STORAGE_ACCOUNT_SPACE as usize],
|
||||
..Account::default()
|
||||
};
|
||||
{
|
||||
let mut storage_account = StorageAccount::new(&mut account);
|
||||
storage_account.initialize_replicator_storage().unwrap();
|
||||
}
|
||||
|
||||
let ix = storage_instruction::mining_proof(
|
||||
&pubkey,
|
||||
|
@ -212,13 +230,20 @@ mod tests {
|
|||
let pubkey = Pubkey::new_rand();
|
||||
let mut accounts = [Account::default(), Account::default()];
|
||||
accounts[0].data.resize(STORAGE_ACCOUNT_SPACE as usize, 0);
|
||||
{
|
||||
let mut storage_account = StorageAccount::new(&mut accounts[0]);
|
||||
storage_account.initialize_replicator_storage().unwrap();
|
||||
}
|
||||
|
||||
let ix =
|
||||
storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default());
|
||||
// move tick height into segment 1
|
||||
let ticks_till_next_segment = TICKS_IN_SEGMENT + 1;
|
||||
|
||||
test_instruction(&ix, &mut accounts, ticks_till_next_segment).unwrap();
|
||||
assert_matches!(
|
||||
test_instruction(&ix, &mut accounts, ticks_till_next_segment),
|
||||
Ok(_)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -230,6 +255,8 @@ mod tests {
|
|||
let replicator = replicator_keypair.pubkey();
|
||||
let validator_keypair = Keypair::new();
|
||||
let validator = validator_keypair.pubkey();
|
||||
let mining_pool_keypair = Keypair::new();
|
||||
let mining_pool = mining_pool_keypair.pubkey();
|
||||
|
||||
let mut bank = Bank::new(&genesis_block);
|
||||
bank.add_instruction_processor(id(), process_instruction);
|
||||
|
@ -237,11 +264,26 @@ mod tests {
|
|||
let slot = 0;
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
let ix = storage_instruction::create_account(&mint_pubkey, &validator, 10);
|
||||
bank_client.send_instruction(&mint_keypair, ix).unwrap();
|
||||
let message = Message::new(storage_instruction::create_validator_storage_account(
|
||||
&mint_pubkey,
|
||||
&validator,
|
||||
10,
|
||||
));
|
||||
bank_client.send_message(&[&mint_keypair], message).unwrap();
|
||||
|
||||
let ix = storage_instruction::create_account(&mint_pubkey, &replicator, 10);
|
||||
bank_client.send_instruction(&mint_keypair, ix).unwrap();
|
||||
let message = Message::new(storage_instruction::create_replicator_storage_account(
|
||||
&mint_pubkey,
|
||||
&replicator,
|
||||
10,
|
||||
));
|
||||
bank_client.send_message(&[&mint_keypair], message).unwrap();
|
||||
|
||||
let message = Message::new(storage_instruction::create_mining_pool_account(
|
||||
&mint_pubkey,
|
||||
&mining_pool,
|
||||
100,
|
||||
));
|
||||
bank_client.send_message(&[&mint_keypair], message).unwrap();
|
||||
|
||||
// tick the bank up until it's moved into storage segment 2 because the next advertise is for segment 1
|
||||
let next_storage_segment_tick_height = TICKS_IN_SEGMENT * 2;
|
||||
|
@ -256,9 +298,7 @@ mod tests {
|
|||
SLOTS_PER_SEGMENT,
|
||||
);
|
||||
|
||||
bank_client
|
||||
.send_instruction(&validator_keypair, ix)
|
||||
.unwrap();
|
||||
assert_matches!(bank_client.send_instruction(&validator_keypair, ix), Ok(_));
|
||||
|
||||
let ix = storage_instruction::mining_proof(
|
||||
&replicator,
|
||||
|
@ -266,9 +306,8 @@ mod tests {
|
|||
slot,
|
||||
Signature::default(),
|
||||
);
|
||||
bank_client
|
||||
.send_instruction(&replicator_keypair, ix)
|
||||
.unwrap();
|
||||
|
||||
assert_matches!(bank_client.send_instruction(&replicator_keypair, ix), Ok(_));
|
||||
|
||||
let ix = storage_instruction::advertise_recent_blockhash(
|
||||
&validator,
|
||||
|
@ -281,10 +320,7 @@ mod tests {
|
|||
bank.register_tick(&bank.last_blockhash());
|
||||
}
|
||||
|
||||
bank_client
|
||||
.send_instruction(&validator_keypair, ix)
|
||||
.unwrap();
|
||||
|
||||
assert_matches!(bank_client.send_instruction(&validator_keypair, ix), Ok(_));
|
||||
let ix = storage_instruction::proof_validation(
|
||||
&validator,
|
||||
slot,
|
||||
|
@ -297,9 +333,8 @@ mod tests {
|
|||
status: ProofStatus::Valid,
|
||||
}],
|
||||
);
|
||||
bank_client
|
||||
.send_instruction(&validator_keypair, ix)
|
||||
.unwrap();
|
||||
|
||||
assert_matches!(bank_client.send_instruction(&validator_keypair, ix), Ok(_));
|
||||
|
||||
let ix = storage_instruction::advertise_recent_blockhash(
|
||||
&validator,
|
||||
|
@ -312,30 +347,50 @@ mod tests {
|
|||
bank.register_tick(&bank.last_blockhash());
|
||||
}
|
||||
|
||||
bank_client
|
||||
.send_instruction(&validator_keypair, ix)
|
||||
.unwrap();
|
||||
assert_matches!(bank_client.send_instruction(&validator_keypair, ix), Ok(_));
|
||||
|
||||
let ix = storage_instruction::reward_claim(&validator, slot);
|
||||
bank_client
|
||||
.send_instruction(&validator_keypair, ix)
|
||||
.unwrap();
|
||||
assert_eq!(bank_client.get_balance(&validator).unwrap(), 10,);
|
||||
|
||||
// TODO enable when rewards are working
|
||||
// assert_eq!(bank_client.get_balance(&validator).unwrap(), TOTAL_VALIDATOR_REWARDS);
|
||||
let message = Message::new_with_payer(
|
||||
vec![storage_instruction::claim_reward(
|
||||
&validator,
|
||||
&mining_pool,
|
||||
slot,
|
||||
)],
|
||||
Some(&validator),
|
||||
);
|
||||
assert_matches!(
|
||||
bank_client.send_message(&[&validator_keypair], message),
|
||||
Ok(_)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
bank_client.get_balance(&validator).unwrap(),
|
||||
10 + TOTAL_VALIDATOR_REWARDS
|
||||
);
|
||||
|
||||
// tick the bank into the next storage epoch so that rewards can be claimed
|
||||
for _ in 0..=TICKS_IN_SEGMENT {
|
||||
bank.register_tick(&bank.last_blockhash());
|
||||
}
|
||||
|
||||
let ix = storage_instruction::reward_claim(&replicator, slot);
|
||||
bank_client
|
||||
.send_instruction(&replicator_keypair, ix)
|
||||
.unwrap();
|
||||
assert_eq!(bank_client.get_balance(&replicator).unwrap(), 10);
|
||||
|
||||
let message = Message::new_with_payer(
|
||||
vec![storage_instruction::claim_reward(
|
||||
&replicator,
|
||||
&mining_pool,
|
||||
slot,
|
||||
)],
|
||||
Some(&replicator),
|
||||
);
|
||||
assert_matches!(
|
||||
bank_client.send_message(&[&replicator_keypair], message),
|
||||
Ok(_)
|
||||
);
|
||||
|
||||
// TODO enable when rewards are working
|
||||
// assert_eq!(bank_client.get_balance(&replicator).unwrap(), TOTAL_REPLICATOR_REWARDS);
|
||||
// assert_eq!(bank_client.get_balance(&replicator).unwrap(), 10 + TOTAL_REPLICATOR_REWARDS);
|
||||
}
|
||||
|
||||
fn get_storage_slot<C: SyncClient>(client: &C, account: &Pubkey) -> u64 {
|
||||
|
@ -399,13 +454,19 @@ mod tests {
|
|||
.transfer(10, &mint_keypair, &replicator_pubkey)
|
||||
.unwrap();
|
||||
|
||||
let ix = storage_instruction::create_account(&mint_pubkey, &replicator_pubkey, 1);
|
||||
let message = Message::new(storage_instruction::create_replicator_storage_account(
|
||||
&mint_pubkey,
|
||||
&replicator_pubkey,
|
||||
1,
|
||||
));
|
||||
bank_client.send_message(&[&mint_keypair], message).unwrap();
|
||||
|
||||
bank_client.send_instruction(&mint_keypair, ix).unwrap();
|
||||
|
||||
let ix = storage_instruction::create_account(&mint_pubkey, &validator_pubkey, 1);
|
||||
|
||||
bank_client.send_instruction(&mint_keypair, ix).unwrap();
|
||||
let message = Message::new(storage_instruction::create_validator_storage_account(
|
||||
&mint_pubkey,
|
||||
&validator_pubkey,
|
||||
1,
|
||||
));
|
||||
bank_client.send_message(&[&mint_keypair], message).unwrap();
|
||||
|
||||
let ix = storage_instruction::advertise_recent_blockhash(
|
||||
&validator_pubkey,
|
||||
|
|
1
run.sh
1
run.sh
|
@ -73,6 +73,7 @@ args=(
|
|||
--voting-keypair "$dataDir"/config/leader-vote-account-keypair.json
|
||||
--vote-account "$leaderVoteAccountPubkey"
|
||||
--ledger "$dataDir"/ledger/
|
||||
--gossip-port 8001
|
||||
--rpc-port 8899
|
||||
--rpc-drone-address 127.0.0.1:9900
|
||||
)
|
||||
|
|
|
@ -27,9 +27,11 @@ solana-logger = { path = "../logger", version = "0.15.0" }
|
|||
solana-metrics = { path = "../metrics", version = "0.15.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.15.0" }
|
||||
solana-stake-api = { path = "../programs/stake_api", version = "0.15.0" }
|
||||
solana-storage-api = { path = "../programs/storage_api", version = "0.15.0" }
|
||||
solana-vote-api = { path = "../programs/vote_api", version = "0.15.0" }
|
||||
solana-vote-program = { path = "../programs/vote_program", version = "0.15.0" }
|
||||
solana-stake-program = { path = "../programs/stake_program", version = "0.15.0" }
|
||||
solana-storage-program = { path = "../programs/storage_program", version = "0.15.0" }
|
||||
solana-noop-program = { path = "../programs/noop_program", version = "0.15.0" }
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -4,6 +4,7 @@ use solana_sdk::pubkey::Pubkey;
|
|||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_sdk::system_program;
|
||||
use solana_stake_api::stake_state;
|
||||
use solana_storage_api::storage_contract;
|
||||
use solana_vote_api::vote_state;
|
||||
|
||||
// The default stake placed with the bootstrap leader
|
||||
|
@ -13,6 +14,7 @@ pub struct GenesisBlockInfo {
|
|||
pub genesis_block: GenesisBlock,
|
||||
pub mint_keypair: Keypair,
|
||||
pub voting_keypair: Keypair,
|
||||
pub storage_keypair: Keypair,
|
||||
}
|
||||
|
||||
pub fn create_genesis_block_with_leader(
|
||||
|
@ -23,6 +25,7 @@ pub fn create_genesis_block_with_leader(
|
|||
let mint_keypair = Keypair::new();
|
||||
let voting_keypair = Keypair::new();
|
||||
let staking_keypair = Keypair::new();
|
||||
let storage_keypair = Keypair::new();
|
||||
|
||||
// TODO: de-duplicate the stake once passive staking
|
||||
// is fully implemented
|
||||
|
@ -41,11 +44,11 @@ pub fn create_genesis_block_with_leader(
|
|||
mint_keypair.pubkey(),
|
||||
Account::new(mint_lamports, 0, &system_program::id()),
|
||||
),
|
||||
// node needs an account to issue votes from, this will require
|
||||
// node needs an account to issue votes and storage proofs from, this will require
|
||||
// airdrops at some point to cover fees...
|
||||
(
|
||||
*bootstrap_leader_id,
|
||||
Account::new(1, 0, &system_program::id()),
|
||||
Account::new(42, 0, &system_program::id()),
|
||||
),
|
||||
// where votes go to
|
||||
(voting_keypair.pubkey(), vote_account),
|
||||
|
@ -58,13 +61,23 @@ pub fn create_genesis_block_with_leader(
|
|||
bootstrap_leader_stake_lamports,
|
||||
),
|
||||
),
|
||||
// storage account
|
||||
(
|
||||
storage_keypair.pubkey(),
|
||||
storage_contract::create_validator_storage_account(1),
|
||||
),
|
||||
],
|
||||
&[
|
||||
solana_vote_program!(),
|
||||
solana_stake_program!(),
|
||||
solana_storage_program!(), // TODO: storage program is only needed by core/, move this line into core/src/genesis_utils.rs
|
||||
],
|
||||
&[solana_vote_program!(), solana_stake_program!()],
|
||||
);
|
||||
|
||||
GenesisBlockInfo {
|
||||
genesis_block,
|
||||
mint_keypair,
|
||||
voting_keypair,
|
||||
storage_keypair,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,5 +25,8 @@ extern crate solana_vote_program;
|
|||
#[macro_use]
|
||||
extern crate solana_stake_program;
|
||||
|
||||
#[macro_use]
|
||||
extern crate solana_storage_program;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
|
|
@ -24,6 +24,7 @@ solana-logger = { path = "../logger", version = "0.15.0" }
|
|||
solana-netutil = { path = "../netutil", version = "0.15.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.15.0" }
|
||||
solana-stake-api = { path = "../programs/stake_api", version = "0.15.0" }
|
||||
solana-storage-api = { path = "../programs/storage_api", version = "0.15.0" }
|
||||
solana-vote-api = { path = "../programs/vote_api", version = "0.15.0" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "0.15.0" }
|
||||
url = "1.7.2"
|
||||
|
|
|
@ -27,6 +27,7 @@ use solana_sdk::system_instruction::SystemError;
|
|||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::transaction::{Transaction, TransactionError};
|
||||
use solana_stake_api::stake_instruction;
|
||||
use solana_storage_api::storage_instruction;
|
||||
use solana_vote_api::vote_instruction;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
@ -53,6 +54,11 @@ pub enum WalletCommand {
|
|||
DelegateStake(Keypair, Pubkey),
|
||||
RedeemVoteCredits(Pubkey, Pubkey, Pubkey),
|
||||
ShowStakeAccount(Pubkey),
|
||||
CreateStorageMiningPoolAccount(Pubkey, u64),
|
||||
CreateReplicatorStorageAccount(Pubkey),
|
||||
CreateValidatorStorageAccount(Pubkey),
|
||||
ClaimStorageReward(Pubkey, Pubkey, u64),
|
||||
ShowStorageAccount(Pubkey),
|
||||
Deploy(String),
|
||||
GetTransactionCount,
|
||||
// Pay(lamports, to, timestamp, timestamp_pubkey, witness(es), cancelable)
|
||||
|
@ -250,6 +256,42 @@ pub fn parse_command(
|
|||
let staking_account_id = pubkey_of(matches, "staking_account_id").unwrap();
|
||||
Ok(WalletCommand::ShowStakeAccount(staking_account_id))
|
||||
}
|
||||
("create-storage-mining-pool-account", Some(matches)) => {
|
||||
let storage_mining_pool_account_id =
|
||||
pubkey_of(matches, "storage_mining_pool_account_id").unwrap();
|
||||
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
||||
Ok(WalletCommand::CreateStorageMiningPoolAccount(
|
||||
storage_mining_pool_account_id,
|
||||
lamports,
|
||||
))
|
||||
}
|
||||
("create-replicator-storage-account", Some(matches)) => {
|
||||
let storage_account_id = pubkey_of(matches, "storage_account_id").unwrap();
|
||||
Ok(WalletCommand::CreateReplicatorStorageAccount(
|
||||
storage_account_id,
|
||||
))
|
||||
}
|
||||
("create-validator-storage-account", Some(matches)) => {
|
||||
let storage_account_id = pubkey_of(matches, "storage_account_id").unwrap();
|
||||
Ok(WalletCommand::CreateValidatorStorageAccount(
|
||||
storage_account_id,
|
||||
))
|
||||
}
|
||||
("claim-storage-reward", Some(matches)) => {
|
||||
let storage_mining_pool_account_id =
|
||||
pubkey_of(matches, "storage_mining_pool_account_id").unwrap();
|
||||
let storage_account_id = pubkey_of(matches, "storage_account_id").unwrap();
|
||||
let slot = matches.value_of("slot").unwrap().parse()?;
|
||||
Ok(WalletCommand::ClaimStorageReward(
|
||||
storage_mining_pool_account_id,
|
||||
storage_account_id,
|
||||
slot,
|
||||
))
|
||||
}
|
||||
("show-storage-account", Some(matches)) => {
|
||||
let storage_account_id = pubkey_of(matches, "storage_account_id").unwrap();
|
||||
Ok(WalletCommand::ShowStorageAccount(storage_account_id))
|
||||
}
|
||||
("deploy", Some(deploy_matches)) => Ok(WalletCommand::Deploy(
|
||||
deploy_matches
|
||||
.value_of("program_location")
|
||||
|
@ -585,6 +627,91 @@ fn process_show_stake_account(
|
|||
}
|
||||
}
|
||||
|
||||
fn process_create_storage_mining_pool_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
storage_account_id: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let ixs = storage_instruction::create_mining_pool_account(
|
||||
&config.keypair.pubkey(),
|
||||
storage_account_id,
|
||||
lamports,
|
||||
);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
|
||||
fn process_create_replicator_storage_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
storage_account_id: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let ixs = storage_instruction::create_replicator_storage_account(
|
||||
&config.keypair.pubkey(),
|
||||
storage_account_id,
|
||||
1,
|
||||
);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
|
||||
fn process_create_validator_storage_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
storage_account_id: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let ixs = storage_instruction::create_validator_storage_account(
|
||||
&config.keypair.pubkey(),
|
||||
storage_account_id,
|
||||
1,
|
||||
);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
|
||||
fn process_claim_storage_reward(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
storage_mining_pool_account_id: &Pubkey,
|
||||
storage_account_id: &Pubkey,
|
||||
slot: u64,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
|
||||
let instruction =
|
||||
storage_instruction::claim_reward(storage_account_id, storage_mining_pool_account_id, slot);
|
||||
let signers = [&config.keypair];
|
||||
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
|
||||
|
||||
let mut transaction = Transaction::new(&signers, message, recent_blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut transaction, &signers)?;
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
|
||||
fn process_show_storage_account(
|
||||
rpc_client: &RpcClient,
|
||||
_config: &WalletConfig,
|
||||
storage_account_id: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
use solana_storage_api::storage_contract::StorageContract;
|
||||
let account = rpc_client.get_account(storage_account_id)?;
|
||||
let storage_contract: StorageContract = account.state().map_err(|err| {
|
||||
WalletError::RpcRequestError(
|
||||
format!("Unable to deserialize storage account: {:?}", err).to_string(),
|
||||
)
|
||||
})?;
|
||||
println!("{:?}", storage_contract);
|
||||
println!("account lamports: {}", account.lamports);
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
fn process_deploy(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
|
@ -904,11 +1031,43 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
|||
&voting_account_id,
|
||||
),
|
||||
|
||||
// Show a vote account
|
||||
WalletCommand::ShowStakeAccount(staking_account_id) => {
|
||||
process_show_stake_account(&rpc_client, config, &staking_account_id)
|
||||
}
|
||||
|
||||
WalletCommand::CreateStorageMiningPoolAccount(storage_account_id, lamports) => {
|
||||
process_create_storage_mining_pool_account(
|
||||
&rpc_client,
|
||||
config,
|
||||
&storage_account_id,
|
||||
*lamports,
|
||||
)
|
||||
}
|
||||
|
||||
WalletCommand::CreateReplicatorStorageAccount(storage_account_id) => {
|
||||
process_create_replicator_storage_account(&rpc_client, config, &storage_account_id)
|
||||
}
|
||||
|
||||
WalletCommand::CreateValidatorStorageAccount(storage_account_id) => {
|
||||
process_create_validator_storage_account(&rpc_client, config, &storage_account_id)
|
||||
}
|
||||
|
||||
WalletCommand::ClaimStorageReward(
|
||||
storage_mining_pool_account_id,
|
||||
storage_account_id,
|
||||
slot,
|
||||
) => process_claim_storage_reward(
|
||||
&rpc_client,
|
||||
config,
|
||||
&storage_mining_pool_account_id,
|
||||
&storage_account_id,
|
||||
*slot,
|
||||
),
|
||||
|
||||
WalletCommand::ShowStorageAccount(storage_account_id) => {
|
||||
process_show_storage_account(&rpc_client, config, &storage_account_id)
|
||||
}
|
||||
|
||||
// Deploy a custom program to the chain
|
||||
WalletCommand::Deploy(ref program_location) => {
|
||||
process_deploy(&rpc_client, config, program_location)
|
||||
|
@ -1182,7 +1341,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("create-mining-pool-account")
|
||||
.about("Create mining pool account")
|
||||
.about("Create staking mining pool account")
|
||||
.arg(
|
||||
Arg::with_name("mining_pool_account_id")
|
||||
.index(1)
|
||||
|
@ -1190,7 +1349,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
.help("Staking account address to fund"),
|
||||
.help("Staking mining pool account address to fund"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("lamports")
|
||||
|
@ -1249,7 +1408,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.arg(
|
||||
Arg::with_name("mining_pool_account_id")
|
||||
.index(1)
|
||||
.value_name("PUBKEY")
|
||||
.value_name("MINING POOL PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
|
@ -1258,7 +1417,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.arg(
|
||||
Arg::with_name("staking_account_id")
|
||||
.index(2)
|
||||
.value_name("PUBKEY")
|
||||
.value_name("STAKING ACCOUNT PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
|
@ -1274,7 +1433,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.help("The voting account to which the stake was previously delegated."),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
.subcommand(
|
||||
SubCommand::with_name("show-stake-account")
|
||||
.about("Show the contents of a stake account")
|
||||
.arg(
|
||||
|
@ -1287,6 +1446,94 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.help("Stake account pubkey"),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("create-storage-mining-pool-account")
|
||||
.about("Create mining pool account")
|
||||
.arg(
|
||||
Arg::with_name("storage_account_id")
|
||||
.index(1)
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
.help("Storage mining pool account address to fund"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("lamports")
|
||||
.index(2)
|
||||
.value_name("NUM")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("The number of lamports to assign to the storage mining pool account"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("create-replicator-storage-account")
|
||||
.about("Create a replicator storage account")
|
||||
.arg(
|
||||
Arg::with_name("storage_account_id")
|
||||
.index(1)
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("create-validator-storage-account")
|
||||
.about("Create a validator storage account")
|
||||
.arg(
|
||||
Arg::with_name("storage_account_id")
|
||||
.index(1)
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("claim-storage-reward")
|
||||
.about("Redeem storage reward credits")
|
||||
.arg(
|
||||
Arg::with_name("storage_mining_pool_account_id")
|
||||
.index(1)
|
||||
.value_name("MINING POOL PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
.help("Mining pool account to redeem credits from"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("storage_account_id")
|
||||
.index(2)
|
||||
.value_name("STORAGE ACCOUNT PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
.help("Storage account address to redeem credits for"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("slot")
|
||||
.index(3)
|
||||
.value_name("SLOT")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("The slot to claim rewards for"),
|
||||
),)
|
||||
|
||||
.subcommand(
|
||||
SubCommand::with_name("show-storage-account")
|
||||
.about("Show the contents of a storage account")
|
||||
.arg(
|
||||
Arg::with_name("storage_account_id")
|
||||
.index(1)
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey)
|
||||
.help("Storage account pubkey"),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("deploy")
|
||||
.about("Deploy a program")
|
||||
|
|
Loading…
Reference in New Issue