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

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