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:
Michael Vines
2019-05-23 14:50:23 -07:00
committed by GitHub
parent 6b35e16676
commit b37d2fde3d
18 changed files with 735 additions and 177 deletions

View File

@ -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;

View File

@ -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());

View File

@ -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,

View File

@ -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(

View File

@ -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(