Add command to create genesis accounts (#5343)

This commit is contained in:
Jack May 2019-07-30 23:43:12 -07:00 committed by GitHub
parent bd7e269280
commit 6d7cb23c61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 402 additions and 279 deletions

View File

@ -827,7 +827,7 @@ mod tests {
use solana::validator::ValidatorConfig; use solana::validator::ValidatorConfig;
use solana_client::thin_client::create_client; use solana_client::thin_client::create_client;
use solana_drone::drone::run_local_drone; use solana_drone::drone::run_local_drone;
use solana_librapay_api::{upload_mint_program, upload_payment_program}; use solana_librapay_api::{create_genesis, upload_mint_program, upload_payment_program};
use solana_runtime::bank::Bank; use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient; use solana_runtime::bank_client::BankClient;
use solana_sdk::client::SyncClient; use solana_sdk::client::SyncClient;
@ -872,12 +872,21 @@ mod tests {
FULLNODE_PORT_RANGE, FULLNODE_PORT_RANGE,
); );
let (libra_mint_id, libra_pay_program_id) = if config.use_move { let (libra_genesis_keypair, libra_mint_id, libra_pay_program_id) = if config.use_move {
let libra_genesis_keypair = create_genesis(&drone_keypair, &client, 1_000_000);
let libra_mint_id = upload_mint_program(&drone_keypair, &client); let libra_mint_id = upload_mint_program(&drone_keypair, &client);
let libra_pay_program_id = upload_payment_program(&drone_keypair, &client); let libra_pay_program_id = upload_payment_program(&drone_keypair, &client);
(libra_mint_id, libra_pay_program_id) (
Arc::new(libra_genesis_keypair),
libra_mint_id,
libra_pay_program_id,
)
} else { } else {
(Pubkey::default(), Pubkey::default()) (
Arc::new(Keypair::new()),
Pubkey::default(),
Pubkey::default(),
)
}; };
let (addr_sender, addr_receiver) = channel(); let (addr_sender, addr_receiver) = channel();
@ -890,7 +899,7 @@ mod tests {
Some(( Some((
&libra_pay_program_id, &libra_pay_program_id,
&libra_mint_id, &libra_mint_id,
&cluster.libra_mint_keypair, &libra_genesis_keypair,
)) ))
} else { } else {
None None
@ -912,7 +921,7 @@ mod tests {
keypairs, keypairs,
0, 0,
&libra_pay_program_id, &libra_pay_program_id,
&cluster.libra_mint_keypair.pubkey(), &libra_genesis_keypair.pubkey(),
); );
assert!(total > 100); assert!(total > 100);
} }

View File

@ -30,7 +30,6 @@ use std::io::{Error, ErrorKind, Result};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use solana_librapay_api::librapay_transaction;
use solana_move_loader_api; use solana_move_loader_api;
pub struct ValidatorInfo { pub struct ValidatorInfo {
@ -119,7 +118,6 @@ pub struct LocalCluster {
pub genesis_block: GenesisBlock, pub genesis_block: GenesisBlock,
replicators: Vec<Replicator>, replicators: Vec<Replicator>,
pub replicator_infos: HashMap<Pubkey, ReplicatorInfo>, pub replicator_infos: HashMap<Pubkey, ReplicatorInfo>,
pub libra_mint_keypair: Arc<Keypair>,
} }
impl LocalCluster { impl LocalCluster {
@ -166,11 +164,6 @@ impl LocalCluster {
storage_keypair.pubkey(), storage_keypair.pubkey(),
storage_contract::create_validator_storage_account(leader_pubkey, 1), storage_contract::create_validator_storage_account(leader_pubkey, 1),
)); ));
let libra_mint_keypair = Keypair::new();
genesis_block.accounts.push((
libra_mint_keypair.pubkey(),
librapay_transaction::create_libra_genesis_account(10_000),
));
genesis_block genesis_block
.native_instruction_processors .native_instruction_processors
.push(solana_storage_program!()); .push(solana_storage_program!());
@ -181,7 +174,6 @@ impl LocalCluster {
let (leader_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_block); let (leader_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_block);
let leader_contact_info = leader_node.info.clone(); let leader_contact_info = leader_node.info.clone();
let leader_storage_keypair = Arc::new(storage_keypair); let leader_storage_keypair = Arc::new(storage_keypair);
let libra_mint_keypair = Arc::new(libra_mint_keypair);
let leader_voting_keypair = Arc::new(voting_keypair); let leader_voting_keypair = Arc::new(voting_keypair);
let leader_server = Validator::new( let leader_server = Validator::new(
leader_node, leader_node,
@ -220,7 +212,6 @@ impl LocalCluster {
fullnode_infos, fullnode_infos,
replicator_infos: HashMap::new(), replicator_infos: HashMap::new(),
listener_infos: HashMap::new(), listener_infos: HashMap::new(),
libra_mint_keypair,
}; };
for (stake, validator_config) in (&config.node_stakes[1..]) for (stake, validator_config) in (&config.node_stakes[1..])

View File

@ -18,11 +18,36 @@ use solana_runtime::loader_utils::load_program;
use solana_sdk::account::KeyedAccount; use solana_sdk::account::KeyedAccount;
use solana_sdk::client::Client; use solana_sdk::client::Client;
use solana_sdk::instruction::InstructionError; use solana_sdk::instruction::InstructionError;
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction;
use types::account_address::AccountAddress; use types::account_address::AccountAddress;
pub fn create_genesis<T: Client>(from_key: &Keypair, client: &T, amount: u64) -> Keypair {
let libra_genesis_key = Keypair::new();
let instruction = system_instruction::create_account(
&from_key.pubkey(),
&libra_genesis_key.pubkey(),
1,
bincode::serialize(&LibraAccountState::create_genesis(1))
.unwrap()
.len() as u64,
&solana_move_loader_api::id(),
);
client.send_instruction(&from_key, instruction).unwrap();
let instruction = librapay_instruction::genesis(&libra_genesis_key.pubkey(), amount);
let message = Message::new_with_payer(vec![instruction], Some(&from_key.pubkey()));
client
.send_message(&[from_key, &libra_genesis_key], message)
.unwrap();
libra_genesis_key
}
pub fn upload_move_program<T: Client>(from: &Keypair, client: &T, code: &str) -> Pubkey { pub fn upload_move_program<T: Client>(from: &Keypair, client: &T, code: &str) -> Pubkey {
let address = AccountAddress::default(); let address = AccountAddress::default();
let account_state = LibraAccountState::create_program(&address, code, vec![]); let account_state = LibraAccountState::create_program(&address, code, vec![]);

View File

@ -1,14 +1,23 @@
use bincode; use bincode;
use solana_move_loader_api::account_state::pubkey_to_address; use solana_move_loader_api::account_state::pubkey_to_address;
use solana_move_loader_api::processor::InvokeInfo; use solana_move_loader_api::processor::InvokeCommand;
use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::loader_instruction::LoaderInstruction;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use types::account_address::AccountAddress; use types::account_address::AccountAddress;
use types::transaction::TransactionArgument; use types::transaction::TransactionArgument;
pub fn genesis(genesis_pubkey: &Pubkey, microlibras: u64) -> Instruction {
let data = bincode::serialize(&InvokeCommand::CreateGenesis(microlibras)).unwrap();
let ix_data = LoaderInstruction::InvokeMain { data };
let accounts = vec![AccountMeta::new(*genesis_pubkey, true)];
Instruction::new(solana_move_loader_api::id(), &ix_data, accounts)
}
pub fn mint( pub fn mint(
program_id: &Pubkey, program_pubkey: &Pubkey,
from_pubkey: &Pubkey, from_pubkey: &Pubkey,
to_pubkey: &Pubkey, to_pubkey: &Pubkey,
microlibras: u64, microlibras: u64,
@ -18,16 +27,16 @@ pub fn mint(
TransactionArgument::U64(microlibras), TransactionArgument::U64(microlibras),
]; ];
let invoke_info = InvokeInfo { let data = bincode::serialize(&InvokeCommand::RunProgram {
sender_address: AccountAddress::default(), sender_address: AccountAddress::default(),
function_name: "main".to_string(), function_name: "main".to_string(),
args, args,
}; })
let data = bincode::serialize(&invoke_info).unwrap(); .unwrap();
let ix_data = LoaderInstruction::InvokeMain { data }; let ix_data = LoaderInstruction::InvokeMain { data };
let accounts = vec![ let accounts = vec![
AccountMeta::new_credit_only(*program_id, false), AccountMeta::new_credit_only(*program_pubkey, false),
AccountMeta::new(*from_pubkey, true), AccountMeta::new(*from_pubkey, true),
AccountMeta::new(*to_pubkey, false), AccountMeta::new(*to_pubkey, false),
]; ];
@ -36,7 +45,7 @@ pub fn mint(
} }
pub fn transfer( pub fn transfer(
program_id: &Pubkey, program_pubkey: &Pubkey,
mint_pubkey: &Pubkey, mint_pubkey: &Pubkey,
from_pubkey: &Pubkey, from_pubkey: &Pubkey,
to_pubkey: &Pubkey, to_pubkey: &Pubkey,
@ -47,16 +56,16 @@ pub fn transfer(
TransactionArgument::U64(microlibras), TransactionArgument::U64(microlibras),
]; ];
let invoke_info = InvokeInfo { let data = bincode::serialize(&InvokeCommand::RunProgram {
sender_address: pubkey_to_address(from_pubkey), sender_address: pubkey_to_address(from_pubkey),
function_name: "main".to_string(), function_name: "main".to_string(),
args, args,
}; })
let data = bincode::serialize(&invoke_info).unwrap(); .unwrap();
let ix_data = LoaderInstruction::InvokeMain { data }; let ix_data = LoaderInstruction::InvokeMain { data };
let accounts = vec![ let accounts = vec![
AccountMeta::new_credit_only(*program_id, false), AccountMeta::new_credit_only(*program_pubkey, false),
AccountMeta::new_credit_only(*mint_pubkey, false), AccountMeta::new_credit_only(*mint_pubkey, false),
AccountMeta::new(*from_pubkey, true), AccountMeta::new(*from_pubkey, true),
AccountMeta::new(*to_pubkey, false), AccountMeta::new(*to_pubkey, false),

View File

@ -3,7 +3,6 @@ use language_e2e_tests::account::AccountResource;
use log::*; use log::*;
use solana_move_loader_api::account_state::{pubkey_to_address, LibraAccountState}; use solana_move_loader_api::account_state::{pubkey_to_address, LibraAccountState};
use solana_move_loader_api::data_store::DataStore; use solana_move_loader_api::data_store::DataStore;
use solana_sdk::account::Account;
use solana_sdk::client::Client; use solana_sdk::client::Client;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
@ -14,6 +13,20 @@ use std::boxed::Box;
use std::error; use std::error;
use std::fmt; use std::fmt;
pub fn create_genesis(
genesis_keypair: &Keypair,
microlibras: u64,
recent_blockhash: Hash,
) -> Transaction {
let ix = librapay_instruction::genesis(&genesis_keypair.pubkey(), microlibras);
Transaction::new_signed_with_payer(
vec![ix],
Some(&genesis_keypair.pubkey()),
&[genesis_keypair],
recent_blockhash,
)
}
pub fn mint_tokens( pub fn mint_tokens(
program_id: &Pubkey, program_id: &Pubkey,
payer: &Keypair, payer: &Keypair,
@ -100,7 +113,7 @@ pub fn get_libra_balance<T: Client>(
if let Some(account) = account { if let Some(account) = account {
let mut data_store = DataStore::default(); let mut data_store = DataStore::default();
match bincode::deserialize(&account)? { match bincode::deserialize(&account)? {
LibraAccountState::User(write_set) => { LibraAccountState::User(_, write_set) => {
data_store.apply_write_set(&write_set); data_store.apply_write_set(&write_set);
} }
LibraAccountState::Unallocated => { LibraAccountState::Unallocated => {
@ -122,45 +135,18 @@ pub fn get_libra_balance<T: Client>(
} }
} }
pub fn create_libra_genesis_account(microlibras: u64) -> Account {
let libra_genesis_data =
bincode::serialize(&LibraAccountState::create_genesis(microlibras)).unwrap();
Account {
lamports: 1,
data: libra_genesis_data,
owner: solana_move_loader_api::id(),
executable: false,
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{upload_mint_program, upload_payment_program}; use crate::{create_genesis, upload_mint_program, upload_payment_program};
use solana_runtime::bank::Bank; use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient; use solana_runtime::bank_client::BankClient;
use solana_sdk::account::Account; use solana_sdk::genesis_block::create_genesis_block;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_program;
use std::sync::Arc; use std::sync::Arc;
fn create_bank(lamports: u64) -> (Arc<Bank>, Keypair, Keypair, Pubkey, Pubkey) { fn create_bank(lamports: u64) -> (Arc<Bank>, Keypair, Keypair, Pubkey, Pubkey) {
let libra_genesis_account = create_libra_genesis_account(lamports); let (genesis_block, mint_keypair) = create_genesis_block(lamports);
//let (genesis_block, mint_keypair) = create_genesis_block(lamports);
let mint_keypair = Keypair::new();
let libra_mint_keypair = Keypair::new();
let genesis_block = GenesisBlock::new(
&[
(
mint_keypair.pubkey(),
Account::new(lamports, 0, &system_program::id()),
),
(libra_mint_keypair.pubkey(), libra_genesis_account),
],
&[],
);
let mut bank = Bank::new(&genesis_block); let mut bank = Bank::new(&genesis_block);
bank.add_instruction_processor( bank.add_instruction_processor(
solana_move_loader_api::id(), solana_move_loader_api::id(),
@ -168,12 +154,13 @@ mod tests {
); );
let shared_bank = Arc::new(bank); let shared_bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&shared_bank); let bank_client = BankClient::new_shared(&shared_bank);
let genesis_keypair = create_genesis(&mint_keypair, &bank_client, 1_000_000);
let mint_program_pubkey = upload_mint_program(&mint_keypair, &bank_client); let mint_program_pubkey = upload_mint_program(&mint_keypair, &bank_client);
let program_pubkey = upload_payment_program(&mint_keypair, &bank_client); let program_pubkey = upload_payment_program(&mint_keypair, &bank_client);
( (
shared_bank, shared_bank,
mint_keypair, mint_keypair,
libra_mint_keypair, genesis_keypair,
mint_program_pubkey, mint_program_pubkey,
program_pubkey, program_pubkey,
) )
@ -181,7 +168,7 @@ mod tests {
#[test] #[test]
fn test_transfer() { fn test_transfer() {
let (bank, mint_keypair, libra_mint_keypair, mint_program_id, program_id) = let (bank, mint_keypair, libra_genesis_keypair, mint_program_id, program_id) =
create_bank(10_000); create_bank(10_000);
let from = Keypair::new(); let from = Keypair::new();
let to = Keypair::new(); let to = Keypair::new();
@ -197,14 +184,14 @@ mod tests {
info!( info!(
"created accounts: mint: {} libra_mint: {}", "created accounts: mint: {} libra_mint: {}",
mint_keypair.pubkey(), mint_keypair.pubkey(),
libra_mint_keypair.pubkey() libra_genesis_keypair.pubkey()
); );
info!(" from: {} to: {}", from.pubkey(), to.pubkey()); info!(" from: {} to: {}", from.pubkey(), to.pubkey());
let tx = mint_tokens( let tx = mint_tokens(
&mint_program_id, &mint_program_id,
&mint_keypair, &mint_keypair,
&libra_mint_keypair, &libra_genesis_keypair,
&from.pubkey(), &from.pubkey(),
1, 1,
bank.last_blockhash(), bank.last_blockhash(),
@ -217,7 +204,7 @@ mod tests {
let tx = transfer( let tx = transfer(
&program_id, &program_id,
&libra_mint_keypair.pubkey(), &libra_genesis_keypair.pubkey(),
&mint_keypair, &mint_keypair,
&from, &from,
&to.pubkey(), &to.pubkey(),

View File

@ -1,8 +1,9 @@
use crate::data_store::DataStore; use crate::data_store::DataStore;
use crate::error_mappers::*;
use bytecode_verifier::VerifiedModule; use bytecode_verifier::VerifiedModule;
use compiler::Compiler; use compiler::Compiler;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use solana_sdk::pubkey::Pubkey; use solana_sdk::{instruction::InstructionError, pubkey::Pubkey};
use std::convert::TryInto; use std::convert::TryInto;
use stdlib::stdlib_modules; use stdlib::stdlib_modules;
use types::{ use types::{
@ -47,8 +48,8 @@ pub enum LibraAccountState {
script_bytes: Vec<u8>, script_bytes: Vec<u8>,
modules_bytes: Vec<Vec<u8>>, modules_bytes: Vec<Vec<u8>>,
}, },
/// Write set containing a Libra account's data /// Associated genesis account and the write set containing the Libra account data
User(WriteSet), User(Pubkey, WriteSet),
/// Write sets containing the mint and stdlib modules /// Write sets containing the mint and stdlib modules
Genesis(WriteSet), Genesis(WriteSet),
} }
@ -62,12 +63,12 @@ impl LibraAccountState {
code: &str, code: &str,
deps: Vec<&Vec<u8>>, deps: Vec<&Vec<u8>>,
) -> Self { ) -> Self {
// Compiler needs all the dependencies all the dependency module's account's // Compiler needs all the dependencies and the dependency module's account's
// data into `VerifiedModules` // data into `VerifiedModules`
let mut extra_deps: Vec<VerifiedModule> = vec![]; let mut extra_deps: Vec<VerifiedModule> = vec![];
for dep in deps { for dep in deps {
let state: LibraAccountState = bincode::deserialize(&dep).unwrap(); let state: Self = bincode::deserialize(&dep).unwrap();
if let LibraAccountState::User(write_set) = state { if let LibraAccountState::User(_, write_set) = state {
for (_, write_op) in write_set.iter() { for (_, write_op) in write_set.iter() {
if let WriteOp::Value(raw_bytes) = write_op { if let WriteOp::Value(raw_bytes) = write_op {
extra_deps.push( extra_deps.push(
@ -93,7 +94,7 @@ impl LibraAccountState {
.serialize(&mut script_bytes) .serialize(&mut script_bytes)
.expect("Unable to serialize script"); .expect("Unable to serialize script");
let mut modules_bytes = vec![]; let mut modules_bytes = vec![];
for module in compiled_program.modules.iter() { for module in &compiled_program.modules {
let mut buf = vec![]; let mut buf = vec![];
module module
.serialize(&mut buf) .serialize(&mut buf)
@ -106,11 +107,11 @@ impl LibraAccountState {
} }
} }
pub fn create_user(write_set: WriteSet) -> Self { pub fn create_user(owner: &Pubkey, write_set: WriteSet) -> Self {
LibraAccountState::User(write_set) LibraAccountState::User(*owner, write_set)
} }
pub fn create_genesis(mint_balance: u64) -> Self { pub fn create_genesis(mint_balance: u64) -> Result<(Self), InstructionError> {
let modules = stdlib_modules(); let modules = stdlib_modules();
let arena = Arena::new(); let arena = Arena::new();
let state_view = DataStore::default(); let state_view = DataStore::default();
@ -130,11 +131,14 @@ impl LibraAccountState {
txn_data.sender = mint_address; txn_data.sender = mint_address;
let mut txn_executor = TransactionExecutor::new(&block_cache, &data_cache, txn_data); let mut txn_executor = TransactionExecutor::new(&block_cache, &data_cache, txn_data);
txn_executor.create_account(mint_address).unwrap().unwrap(); txn_executor
.create_account(mint_address)
.map_err(map_vm_invariant_violation_error)?
.map_err(map_vm_runtime_error)?;
txn_executor txn_executor
.execute_function(&COIN_MODULE, "initialize", vec![]) .execute_function(&COIN_MODULE, "initialize", vec![])
.unwrap() .map_err(map_vm_invariant_violation_error)?
.unwrap(); .map_err(map_vm_runtime_error)?;
txn_executor txn_executor
.execute_function( .execute_function(
@ -142,8 +146,8 @@ impl LibraAccountState {
"mint_to_address", "mint_to_address",
vec![Local::address(mint_address), Local::u64(mint_balance)], vec![Local::address(mint_address), Local::u64(mint_balance)],
) )
.unwrap() .map_err(map_vm_invariant_violation_error)?
.unwrap(); .map_err(map_vm_runtime_error)?;
txn_executor txn_executor
.execute_function( .execute_function(
@ -151,28 +155,26 @@ impl LibraAccountState {
"rotate_authentication_key", "rotate_authentication_key",
vec![Local::bytearray(genesis_auth_key)], vec![Local::bytearray(genesis_auth_key)],
) )
.unwrap() .map_err(map_vm_invariant_violation_error)?
.unwrap(); .map_err(map_vm_runtime_error)?;
let stdlib_modules = modules let mut stdlib_modules = vec![];
.iter() for module in modules.iter() {
.map(|m| { let mut buf = vec![];
let mut module_vec = vec![]; module.serialize(&mut buf).map_err(map_failure_error)?;
m.serialize(&mut module_vec).unwrap(); stdlib_modules.push((module.self_id(), buf));
(m.self_id(), module_vec) }
})
.collect();
txn_executor txn_executor
.make_write_set(stdlib_modules, Ok(Ok(()))) .make_write_set(stdlib_modules, Ok(Ok(())))
.unwrap() .map_err(map_vm_runtime_error)?
.write_set() .write_set()
.clone() .clone()
.into_mut() .into_mut()
} }
.freeze() .freeze()
.unwrap(); .map_err(map_failure_error)?;
LibraAccountState::Genesis(write_set) Ok(LibraAccountState::Genesis(write_set))
} }
} }

View File

@ -26,7 +26,7 @@ pub struct DataStore {
impl DataStore { impl DataStore {
/// Creates a new `DataStore` with the provided initial data. /// Creates a new `DataStore` with the provided initial data.
pub fn new(data: IndexMap<AccessPath, Vec<u8>>) -> Self { pub fn new(data: IndexMap<AccessPath, Vec<u8>>) -> Self {
DataStore { data } Self { data }
} }
/// Applies a [`WriteSet`] to this data store. /// Applies a [`WriteSet`] to this data store.

View File

@ -0,0 +1,42 @@
//! Mapping functions to Instruction errors
use log::*;
use solana_sdk::instruction::InstructionError;
use vm::file_format::CompiledModule;
#[allow(clippy::needless_pass_by_value)]
pub fn map_vm_runtime_error(err: vm::errors::VMRuntimeError) -> InstructionError {
debug!("Execution failed: {:?}", err);
match err.err {
vm::errors::VMErrorKind::OutOfGasError => InstructionError::InsufficientFunds,
_ => InstructionError::GenericError,
}
}
pub fn map_vm_invariant_violation_error(err: vm::errors::VMInvariantViolation) -> InstructionError {
debug!("Error: Execution failed: {:?}", err);
InstructionError::GenericError
}
pub fn map_vm_binary_error(err: vm::errors::BinaryError) -> InstructionError {
debug!("Error: Script deserialize failed: {:?}", err);
InstructionError::InvalidInstructionData
}
#[allow(clippy::needless_pass_by_value)]
pub fn map_data_error(err: std::boxed::Box<bincode::ErrorKind>) -> InstructionError {
debug!("Error: Account data: {:?}", err);
InstructionError::InvalidAccountData
}
pub fn map_vm_verification_error(
err: (CompiledModule, Vec<vm::errors::VerificationError>),
) -> InstructionError {
debug!("Error: Script verification failed: {:?}", err.1);
InstructionError::InvalidInstructionData
}
pub fn map_failure_error(err: failure::Error) -> InstructionError {
debug!("Error: Script verification failed: {:?}", err);
InstructionError::InvalidInstructionData
}
#[allow(clippy::needless_pass_by_value)]
pub fn missing_account() -> InstructionError {
debug!("Error: Missing account");
InstructionError::InvalidAccountData
}

View File

@ -1,13 +1,14 @@
pub mod account_state; pub mod account_state;
pub mod data_store; pub mod data_store;
pub mod error_mappers;
pub mod processor; pub mod processor;
const MOVE_LOADER_PROGRAM_ID: [u8; 32] = [ const MOVE_LOADER_PROGRAM_ID: [u8; 32] = [
5, 91, 237, 31, 90, 253, 197, 145, 157, 236, 147, 43, 6, 5, 157, 238, 63, 151, 181, 165, 118, 5, 84, 172, 160, 172, 5, 64, 41, 134, 4, 81, 31, 45, 11, 30, 64, 219, 238, 140, 38, 194, 100,
224, 198, 97, 103, 136, 113, 64, 0, 0, 0, 0, 192, 219, 156, 94, 62, 208, 0, 0, 0, 0,
]; ];
solana_sdk::solana_name_id!( solana_sdk::solana_name_id!(
MOVE_LOADER_PROGRAM_ID, MOVE_LOADER_PROGRAM_ID,
"MvLdr11111111111111111111111111111111111111" "MoveLdr111111111111111111111111111111111111"
); );

View File

@ -1,5 +1,6 @@
use crate::account_state::{pubkey_to_address, LibraAccountState}; use crate::account_state::{pubkey_to_address, LibraAccountState};
use crate::data_store::DataStore; use crate::data_store::DataStore;
use crate::error_mappers::*;
use crate::id; use crate::id;
use bytecode_verifier::{VerifiedModule, VerifiedScript}; use bytecode_verifier::{VerifiedModule, VerifiedScript};
use log::*; use log::*;
@ -44,11 +45,11 @@ pub fn process_instruction(
match command { match command {
LoaderInstruction::Write { offset, bytes } => { LoaderInstruction::Write { offset, bytes } => {
MoveProcessor::do_write(keyed_accounts, offset, bytes) MoveProcessor::do_write(keyed_accounts, offset, &bytes)
} }
LoaderInstruction::Finalize => MoveProcessor::do_finalize(keyed_accounts), LoaderInstruction::Finalize => MoveProcessor::do_finalize(keyed_accounts),
LoaderInstruction::InvokeMain { data } => { LoaderInstruction::InvokeMain { data } => {
MoveProcessor::do_invoke_main(keyed_accounts, data) MoveProcessor::do_invoke_main(keyed_accounts, &data)
} }
} }
} }
@ -56,52 +57,25 @@ pub fn process_instruction(
pub const PROGRAM_INDEX: usize = 0; pub const PROGRAM_INDEX: usize = 0;
pub const GENESIS_INDEX: usize = 1; pub const GENESIS_INDEX: usize = 1;
// TODO: Not quite right yet /// Command to invoke
/// Invoke information passed via the Invoke Instruction #[derive(Debug, Serialize, Deserialize)]
#[derive(Default, Debug, Serialize, Deserialize)] pub enum InvokeCommand {
pub struct InvokeInfo { /// Create a new genesis account
/// Sender of the "transaction", the "sender" who is calling this program CreateGenesis(u64),
pub sender_address: AccountAddress, /// Run a Move program
/// Name of the function to call RunProgram {
pub function_name: String, /// Sender of the "transaction", the "sender" who is running this program
/// Arguments to pass to the program being invoked sender_address: AccountAddress,
pub args: Vec<TransactionArgument>, /// Name of the program's function to call
function_name: String,
/// Arguments to pass to the program being called
args: Vec<TransactionArgument>,
},
} }
pub struct MoveProcessor {} pub struct MoveProcessor {}
impl MoveProcessor { impl MoveProcessor {
#[allow(clippy::needless_pass_by_value)]
fn map_vm_runtime_error(err: vm::errors::VMRuntimeError) -> InstructionError {
debug!("Execution failed: {:?}", err);
match err.err {
vm::errors::VMErrorKind::OutOfGasError => InstructionError::InsufficientFunds,
_ => InstructionError::GenericError,
}
}
fn map_vm_invariant_violation_error(err: vm::errors::VMInvariantViolation) -> InstructionError {
debug!("Error: Execution failed: {:?}", err);
InstructionError::GenericError
}
fn map_vm_binary_error(err: vm::errors::BinaryError) -> InstructionError {
debug!("Error: Script deserialize failed: {:?}", err);
InstructionError::InvalidInstructionData
}
#[allow(clippy::needless_pass_by_value)]
fn map_data_error(err: std::boxed::Box<bincode::ErrorKind>) -> InstructionError {
debug!("Error: Account data: {:?}", err);
InstructionError::InvalidAccountData
}
fn map_vm_verification_error(
err: (CompiledModule, Vec<vm::errors::VerificationError>),
) -> InstructionError {
debug!("Error: Script verification failed: {:?}", err.1);
InstructionError::InvalidInstructionData
}
fn map_failure_error(err: failure::Error) -> InstructionError {
debug!("Error: Script verification failed: {:?}", err);
InstructionError::InvalidInstructionData
}
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
fn missing_account() -> InstructionError { fn missing_account() -> InstructionError {
debug!("Error: Missing account"); debug!("Error: Missing account");
@ -110,7 +84,7 @@ impl MoveProcessor {
fn arguments_to_locals(args: Vec<TransactionArgument>) -> Vec<Local> { fn arguments_to_locals(args: Vec<TransactionArgument>) -> Vec<Local> {
let mut locals = vec![]; let mut locals = vec![];
for arg in args.into_iter() { for arg in args {
locals.push(match arg { locals.push(match arg {
TransactionArgument::U64(i) => Local::u64(i), TransactionArgument::U64(i) => Local::u64(i),
TransactionArgument::Address(a) => Local::address(a), TransactionArgument::Address(a) => Local::address(a),
@ -129,28 +103,28 @@ impl MoveProcessor {
script script
.as_inner() .as_inner()
.serialize(&mut script_bytes) .serialize(&mut script_bytes)
.map_err(Self::map_failure_error)?; .map_err(map_failure_error)?;
let mut modules_bytes = vec![]; let mut modules_bytes = vec![];
for module in modules.iter() { for module in modules.iter() {
let mut buf = vec![]; let mut buf = vec![];
module module
.as_inner() .as_inner()
.serialize(&mut buf) .serialize(&mut buf)
.map_err(Self::map_failure_error)?; .map_err(map_failure_error)?;
modules_bytes.push(buf); modules_bytes.push(buf);
} }
bincode::serialize(&LibraAccountState::VerifiedProgram { bincode::serialize(&LibraAccountState::VerifiedProgram {
script_bytes, script_bytes,
modules_bytes, modules_bytes,
}) })
.map_err(Self::map_data_error) .map_err(map_data_error)
} }
fn deserialize_compiled_program( fn deserialize_compiled_program(
data: &[u8], data: &[u8],
) -> Result<(CompiledScript, Vec<CompiledModule>), InstructionError> { ) -> Result<(CompiledScript, Vec<CompiledModule>), InstructionError> {
let (script_bytes, modules_bytes) = let (script_bytes, modules_bytes) =
match bincode::deserialize(data).map_err(Self::map_data_error)? { match bincode::deserialize(data).map_err(map_data_error)? {
LibraAccountState::CompiledProgram { LibraAccountState::CompiledProgram {
script_bytes, script_bytes,
modules_bytes, modules_bytes,
@ -161,13 +135,12 @@ impl MoveProcessor {
} }
}; };
let script = let script = CompiledScript::deserialize(&script_bytes).map_err(map_vm_binary_error)?;
CompiledScript::deserialize(&script_bytes).map_err(Self::map_vm_binary_error)?;
let modules = modules_bytes let modules = modules_bytes
.iter() .iter()
.map(|bytes| CompiledModule::deserialize(&bytes)) .map(|bytes| CompiledModule::deserialize(&bytes))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(Self::map_vm_binary_error)?; .map_err(map_vm_binary_error)?;
Ok((script, modules)) Ok((script, modules))
} }
@ -176,7 +149,7 @@ impl MoveProcessor {
data: &[u8], data: &[u8],
) -> Result<(VerifiedScript, Vec<VerifiedModule>), InstructionError> { ) -> Result<(VerifiedScript, Vec<VerifiedModule>), InstructionError> {
let (script_bytes, modules_bytes) = let (script_bytes, modules_bytes) =
match bincode::deserialize(data).map_err(Self::map_data_error)? { match bincode::deserialize(data).map_err(map_data_error)? {
LibraAccountState::VerifiedProgram { LibraAccountState::VerifiedProgram {
script_bytes, script_bytes,
modules_bytes, modules_bytes,
@ -187,19 +160,20 @@ impl MoveProcessor {
} }
}; };
let script = let script = VerifiedScript::deserialize(&script_bytes).map_err(map_vm_binary_error)?;
VerifiedScript::deserialize(&script_bytes).map_err(Self::map_vm_binary_error)?;
let modules = modules_bytes let modules = modules_bytes
.iter() .iter()
.map(|bytes| VerifiedModule::deserialize(&bytes)) .map(|bytes| VerifiedModule::deserialize(&bytes))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(Self::map_vm_binary_error)?; .map_err(map_vm_binary_error)?;
Ok((script, modules)) Ok((script, modules))
} }
fn execute( fn execute(
invoke_info: InvokeInfo, sender_address: AccountAddress,
function_name: String,
args: Vec<TransactionArgument>,
script: VerifiedScript, script: VerifiedScript,
modules: Vec<VerifiedModule>, modules: Vec<VerifiedModule>,
data_store: &DataStore, data_store: &DataStore,
@ -217,38 +191,41 @@ impl MoveProcessor {
verified_module verified_module
.as_inner() .as_inner()
.serialize(&mut raw_bytes) .serialize(&mut raw_bytes)
.expect("Unable to serialize module"); // TODO remove expect .map_err(map_failure_error)?;
modules_to_publish.push((verified_module.self_id(), raw_bytes)); modules_to_publish.push((verified_module.self_id(), raw_bytes));
module_cache.cache_module(verified_module); module_cache.cache_module(verified_module);
} }
let mut txn_metadata = TransactionMetadata::default(); let mut txn_metadata = TransactionMetadata::default();
txn_metadata.sender = invoke_info.sender_address; txn_metadata.sender = sender_address;
// Caps execution to the Libra prescribed 10 milliseconds // Caps execution to the Libra prescribed 10 milliseconds
txn_metadata.max_gas_amount = *MAXIMUM_NUMBER_OF_GAS_UNITS; txn_metadata.max_gas_amount = *MAXIMUM_NUMBER_OF_GAS_UNITS;
txn_metadata.gas_unit_price = *MAX_PRICE_PER_GAS_UNIT; txn_metadata.gas_unit_price = *MAX_PRICE_PER_GAS_UNIT;
let mut vm = TransactionExecutor::new(&module_cache, data_store, txn_metadata); let mut vm = TransactionExecutor::new(&module_cache, data_store, txn_metadata);
vm.execute_function( vm.execute_function(&module_id, &function_name, Self::arguments_to_locals(args))
&module_id, .map_err(map_vm_invariant_violation_error)?
&invoke_info.function_name, .map_err(map_vm_runtime_error)?;
Self::arguments_to_locals(invoke_info.args),
)
.map_err(Self::map_vm_invariant_violation_error)?
.map_err(Self::map_vm_runtime_error)?;
Ok(vm Ok(vm
.make_write_set(modules_to_publish, Ok(Ok(()))) .make_write_set(modules_to_publish, Ok(Ok(())))
.map_err(Self::map_vm_runtime_error)?) .map_err(map_vm_runtime_error)?)
} }
fn keyed_accounts_to_data_store( fn keyed_accounts_to_data_store(
genesis_key: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
) -> Result<DataStore, InstructionError> { ) -> Result<DataStore, InstructionError> {
let mut data_store = DataStore::default(); let mut data_store = DataStore::default();
for keyed_account in keyed_accounts { for keyed_account in keyed_accounts {
match bincode::deserialize(&keyed_account.account.data).map_err(Self::map_data_error)? { match bincode::deserialize(&keyed_account.account.data).map_err(map_data_error)? {
LibraAccountState::Genesis(write_set) | LibraAccountState::User(write_set) => { LibraAccountState::Genesis(write_set) => data_store.apply_write_set(&write_set),
LibraAccountState::User(owner, write_set) => {
if owner != *genesis_key {
debug!("All user accounts must be owned by the genesis");
return Err(InstructionError::InvalidArgument);
}
data_store.apply_write_set(&write_set) data_store.apply_write_set(&write_set)
} }
_ => (), // ignore unallocated accounts _ => (), // ignore unallocated accounts
@ -257,10 +234,45 @@ impl MoveProcessor {
Ok(data_store) Ok(data_store)
} }
fn data_store_to_keyed_accounts(
data_store: DataStore,
keyed_accounts: &mut [KeyedAccount],
) -> Result<(), InstructionError> {
let mut write_sets = data_store
.into_write_sets()
.map_err(|_| InstructionError::GenericError)?;
// Genesis account holds both mint and stdlib under address 0x0
let genesis_key = *keyed_accounts[GENESIS_INDEX].unsigned_key();
let write_set = write_sets
.remove(&AccountAddress::default())
.ok_or_else(Self::missing_account)?;
keyed_accounts[GENESIS_INDEX].account.data.clear();
let writer = std::io::BufWriter::new(&mut keyed_accounts[GENESIS_INDEX].account.data);
bincode::serialize_into(writer, &LibraAccountState::Genesis(write_set))
.map_err(map_data_error)?;
// Now do the rest of the accounts
for keyed_account in keyed_accounts[GENESIS_INDEX + 1..].iter_mut() {
let write_set = write_sets
.remove(&pubkey_to_address(keyed_account.unsigned_key()))
.ok_or_else(Self::missing_account)?;
keyed_account.account.data.clear();
let writer = std::io::BufWriter::new(&mut keyed_account.account.data);
bincode::serialize_into(writer, &LibraAccountState::User(genesis_key, write_set))
.map_err(map_data_error)?;
}
if !write_sets.is_empty() {
debug!("Error: Missing keyed accounts");
return Err(InstructionError::GenericError);
}
Ok(())
}
pub fn do_write( pub fn do_write(
keyed_accounts: &mut [KeyedAccount], keyed_accounts: &mut [KeyedAccount],
offset: u32, offset: u32,
bytes: Vec<u8>, bytes: &[u8],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if keyed_accounts[PROGRAM_INDEX].signer_key().is_none() { if keyed_accounts[PROGRAM_INDEX].signer_key().is_none() {
debug!("Error: key[0] did not sign the transaction"); debug!("Error: key[0] did not sign the transaction");
@ -295,7 +307,7 @@ impl MoveProcessor {
.into_iter() .into_iter()
.map(VerifiedModule::new) .map(VerifiedModule::new)
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(Self::map_vm_verification_error)?; .map_err(map_vm_verification_error)?;
keyed_accounts[PROGRAM_INDEX].account.data = keyed_accounts[PROGRAM_INDEX].account.data =
Self::serialize_verified_program(&verified_script, &verified_modules)?; Self::serialize_verified_program(&verified_script, &verified_modules)?;
@ -312,62 +324,76 @@ impl MoveProcessor {
pub fn do_invoke_main( pub fn do_invoke_main(
keyed_accounts: &mut [KeyedAccount], keyed_accounts: &mut [KeyedAccount],
data: Vec<u8>, data: &[u8],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if keyed_accounts.len() < 2 { match bincode::deserialize(&data).map_err(map_data_error)? {
debug!("Error: Requires at least a program and a genesis accounts"); InvokeCommand::CreateGenesis(amount) => {
return Err(InstructionError::InvalidArgument); if keyed_accounts.is_empty() {
} debug!("Error: Requires an unallocated account");
if keyed_accounts[PROGRAM_INDEX].account.owner != id() { return Err(InstructionError::InvalidArgument);
debug!("Error: Move program account not owned by Move loader"); }
return Err(InstructionError::InvalidArgument); if keyed_accounts[0].account.owner != id() {
} debug!("Error: Move program account not owned by Move loader");
if !keyed_accounts[PROGRAM_INDEX].account.executable { return Err(InstructionError::InvalidArgument);
debug!("Error: Move program account not executable"); }
return Err(InstructionError::InvalidArgument);
}
let invoke_info: InvokeInfo = bincode::deserialize(&data).map_err(Self::map_data_error)?; match bincode::deserialize(&keyed_accounts[0].account.data)
let mut data_store = Self::keyed_accounts_to_data_store(&keyed_accounts[GENESIS_INDEX..])?; .map_err(map_data_error)?
let (verified_script, verified_modules) = {
Self::deserialize_verified_program(&keyed_accounts[PROGRAM_INDEX].account.data)?; LibraAccountState::Unallocated => {
keyed_accounts[0].account.data.clear();
let writer = std::io::BufWriter::new(&mut keyed_accounts[0].account.data);
bincode::serialize_into(writer, &LibraAccountState::create_genesis(amount)?)
.map_err(map_data_error)
}
_ => {
debug!("Error: Must provide an unallocated account");
Err(InstructionError::InvalidArgument)
}
}
}
InvokeCommand::RunProgram {
sender_address,
function_name,
args,
} => {
if keyed_accounts.len() < 2 {
debug!("Error: Requires at least a program and a genesis accounts");
return Err(InstructionError::InvalidArgument);
}
if keyed_accounts[PROGRAM_INDEX].account.owner != id() {
debug!("Error: Move program account not owned by Move loader");
return Err(InstructionError::InvalidArgument);
}
if !keyed_accounts[PROGRAM_INDEX].account.executable {
debug!("Error: Move program account not executable");
return Err(InstructionError::InvalidArgument);
}
let output = Self::execute(invoke_info, verified_script, verified_modules, &data_store)?; let mut data_store = Self::keyed_accounts_to_data_store(
for event in output.events() { keyed_accounts[GENESIS_INDEX].unsigned_key(),
trace!("Event: {:?}", event); &keyed_accounts[GENESIS_INDEX..],
)?;
let (verified_script, verified_modules) = Self::deserialize_verified_program(
&keyed_accounts[PROGRAM_INDEX].account.data,
)?;
let output = Self::execute(
sender_address,
function_name,
args,
verified_script,
verified_modules,
&data_store,
)?;
for event in output.events() {
trace!("Event: {:?}", event);
}
data_store.apply_write_set(&output.write_set());
Self::data_store_to_keyed_accounts(data_store, keyed_accounts)
}
} }
data_store.apply_write_set(&output.write_set());
// Break data store into a list of address keyed WriteSets
let mut write_sets = data_store
.into_write_sets()
.map_err(|_| InstructionError::GenericError)?;
// Genesis account holds both mint and stdlib under address 0x0
let write_set = write_sets
.remove(&AccountAddress::default())
.ok_or_else(Self::missing_account)?;
keyed_accounts[GENESIS_INDEX].account.data.clear();
let writer = std::io::BufWriter::new(&mut keyed_accounts[GENESIS_INDEX].account.data);
bincode::serialize_into(writer, &LibraAccountState::Genesis(write_set))
.map_err(Self::map_data_error)?;
// Now do the rest of the accounts
for keyed_account in keyed_accounts[GENESIS_INDEX + 1..].iter_mut() {
let write_set = write_sets
.remove(&pubkey_to_address(keyed_account.unsigned_key()))
.ok_or_else(Self::missing_account)?;
keyed_account.account.data.clear();
let writer = std::io::BufWriter::new(&mut keyed_account.account.data);
bincode::serialize_into(writer, &LibraAccountState::User(write_set))
.map_err(Self::map_data_error)?;
}
if !write_sets.is_empty() {
debug!("Error: Missing keyed accounts");
return Err(InstructionError::GenericError);
}
Ok(())
} }
} }
@ -389,6 +415,33 @@ mod tests {
let (_, _) = MoveProcessor::deserialize_verified_program(&program.account.data).unwrap(); let (_, _) = MoveProcessor::deserialize_verified_program(&program.account.data).unwrap();
} }
#[test]
fn test_create_genesis_account() {
solana_logger::setup();
let amount = 10_000_000;
let mut unallocated = LibraAccount::create_unallocated();
let mut keyed_accounts = vec![KeyedAccount::new(
&unallocated.key,
false,
&mut unallocated.account,
)];
MoveProcessor::do_invoke_main(
&mut keyed_accounts,
&bincode::serialize(&InvokeCommand::CreateGenesis(amount)).unwrap(),
)
.unwrap();
assert_eq!(
bincode::deserialize::<LibraAccountState>(
&LibraAccount::create_genesis(amount).account.data
)
.unwrap(),
bincode::deserialize::<LibraAccountState>(&keyed_accounts[0].account.data).unwrap()
);
}
#[test] #[test]
fn test_invoke_main() { fn test_invoke_main() {
solana_logger::setup(); solana_logger::setup();
@ -396,21 +449,21 @@ mod tests {
let code = "main() { return; }"; let code = "main() { return; }";
let sender_address = AccountAddress::default(); let sender_address = AccountAddress::default();
let mut program = LibraAccount::create_program(&sender_address, code, vec![]); let mut program = LibraAccount::create_program(&sender_address, code, vec![]);
let mut genesis = LibraAccount::create_genesis(); let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let mut keyed_accounts = vec![ let mut keyed_accounts = vec![
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
KeyedAccount::new(&genesis.key, false, &mut genesis.account), KeyedAccount::new(&genesis.key, false, &mut genesis.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let invoke_info = InvokeInfo {
sender_address,
function_name: "main".to_string(),
args: vec![],
};
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address,
function_name: "main".to_string(),
args: vec![],
})
.unwrap(),
) )
.unwrap(); .unwrap();
} }
@ -427,23 +480,22 @@ mod tests {
"; ";
let sender_address = AccountAddress::default(); let sender_address = AccountAddress::default();
let mut program = LibraAccount::create_program(&sender_address, code, vec![]); let mut program = LibraAccount::create_program(&sender_address, code, vec![]);
let mut genesis = LibraAccount::create_genesis(); let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let mut keyed_accounts = vec![ let mut keyed_accounts = vec![
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
KeyedAccount::new(&genesis.key, false, &mut genesis.account), KeyedAccount::new(&genesis.key, false, &mut genesis.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let invoke_info = InvokeInfo {
sender_address,
function_name: "main".to_string(),
args: vec![],
};
assert_eq!( assert_eq!(
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address,
function_name: "main".to_string(),
args: vec![],
})
.unwrap(),
), ),
Err(InstructionError::InsufficientFunds) Err(InstructionError::InsufficientFunds)
); );
@ -458,7 +510,12 @@ mod tests {
let mut data_store = DataStore::default(); let mut data_store = DataStore::default();
match bincode::deserialize(&accounts[GENESIS_INDEX + 1].account.data).unwrap() { match bincode::deserialize(&accounts[GENESIS_INDEX + 1].account.data).unwrap() {
LibraAccountState::User(write_set) => data_store.apply_write_set(&write_set), LibraAccountState::User(owner, write_set) => {
if owner != accounts[GENESIS_INDEX].key {
panic!();
}
data_store.apply_write_set(&write_set)
}
_ => panic!("Invalid account state"), _ => panic!("Invalid account state"),
} }
let payee_resource = data_store let payee_resource = data_store
@ -497,24 +554,24 @@ mod tests {
KeyedAccount::new(&payee.key, false, &mut payee.account), KeyedAccount::new(&payee.key, false, &mut payee.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let amount = 2; let amount = 2;
let invoke_info = InvokeInfo {
sender_address: sender.address.clone(),
function_name: "main".to_string(),
args: vec![
TransactionArgument::Address(payee.address.clone()),
TransactionArgument::U64(amount),
],
};
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address: sender.address.clone(),
function_name: "main".to_string(),
args: vec![
TransactionArgument::Address(payee.address.clone()),
TransactionArgument::U64(amount),
],
})
.unwrap(),
) )
.unwrap(); .unwrap();
let data_store = MoveProcessor::keyed_accounts_to_data_store(&keyed_accounts[1..]).unwrap(); let data_store =
MoveProcessor::keyed_accounts_to_data_store(&genesis.key, &keyed_accounts[1..])
.unwrap();
let sender_resource = data_store.read_account_resource(&sender.address).unwrap(); let sender_resource = data_store.read_account_resource(&sender.address).unwrap();
let payee_resource = data_store.read_account_resource(&payee.address).unwrap(); let payee_resource = data_store.read_account_resource(&payee.address).unwrap();
@ -549,7 +606,7 @@ mod tests {
return; return;
} }
"; ";
let mut genesis = LibraAccount::create_genesis(); let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let mut payee = LibraAccount::create_unallocated(); let mut payee = LibraAccount::create_unallocated();
let mut program = LibraAccount::create_program(&payee.address, code, vec![]); let mut program = LibraAccount::create_program(&payee.address, code, vec![]);
@ -559,14 +616,14 @@ mod tests {
KeyedAccount::new(&payee.key, false, &mut payee.account), KeyedAccount::new(&payee.key, false, &mut payee.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let invoke_info = InvokeInfo {
sender_address: payee.address,
function_name: "main".to_string(),
args: vec![],
};
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address: payee.address,
function_name: "main".to_string(),
args: vec![],
})
.unwrap(),
) )
.unwrap(); .unwrap();
} }
@ -586,7 +643,7 @@ mod tests {
"; ";
let mut module = LibraAccount::create_unallocated(); let mut module = LibraAccount::create_unallocated();
let mut program = LibraAccount::create_program(&module.address, code, vec![]); let mut program = LibraAccount::create_program(&module.address, code, vec![]);
let mut genesis = LibraAccount::create_genesis(); let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let mut keyed_accounts = vec![ let mut keyed_accounts = vec![
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
@ -594,14 +651,14 @@ mod tests {
KeyedAccount::new(&module.key, false, &mut module.account), KeyedAccount::new(&module.key, false, &mut module.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let invoke_info = InvokeInfo {
sender_address: module.address,
function_name: "main".to_string(),
args: vec![],
};
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address: module.address,
function_name: "main".to_string(),
args: vec![],
})
.unwrap(),
) )
.unwrap(); .unwrap();
@ -627,14 +684,14 @@ mod tests {
KeyedAccount::new(&module.key, false, &mut module.account), KeyedAccount::new(&module.key, false, &mut module.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let invoke_info = InvokeInfo {
sender_address: program.address,
function_name: "main".to_string(),
args: vec![],
};
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address: program.address,
function_name: "main".to_string(),
args: vec![],
})
.unwrap(),
) )
.unwrap(); .unwrap();
} }
@ -650,7 +707,7 @@ mod tests {
return; return;
} }
"; ";
let mut genesis = LibraAccount::create_genesis(); let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let mut program = LibraAccount::create_program(&genesis.address, code, vec![]); let mut program = LibraAccount::create_program(&genesis.address, code, vec![]);
let mut payee = LibraAccount::create_unallocated(); let mut payee = LibraAccount::create_unallocated();
@ -660,18 +717,17 @@ mod tests {
KeyedAccount::new(&payee.key, false, &mut payee.account), KeyedAccount::new(&payee.key, false, &mut payee.account),
]; ];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let invoke_info = InvokeInfo {
sender_address: genesis.address.clone(),
function_name: "main".to_string(),
args: vec![
TransactionArgument::Address(pubkey_to_address(&payee.key)),
TransactionArgument::U64(amount),
],
};
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
bincode::serialize(&invoke_info).unwrap(), &bincode::serialize(&InvokeCommand::RunProgram {
sender_address: genesis.address.clone(),
function_name: "main".to_string(),
args: vec![
TransactionArgument::Address(pubkey_to_address(&payee.key)),
TransactionArgument::U64(amount),
],
})
.unwrap(),
) )
.unwrap(); .unwrap();
@ -682,6 +738,7 @@ mod tests {
]) ])
} }
#[derive(Eq, PartialEq, Debug, Default)]
struct LibraAccount { struct LibraAccount {
pub key: Pubkey, pub key: Pubkey,
pub address: AccountAddress, pub address: AccountAddress,
@ -708,7 +765,7 @@ mod tests {
Self::new(key, account) Self::new(key, account)
} }
pub fn create_genesis() -> Self { pub fn create_genesis(amount: u64) -> Self {
let account = Account { let account = Account {
lamports: 1, lamports: 1,
data: vec![], data: vec![],
@ -717,7 +774,7 @@ mod tests {
}; };
let mut genesis = Self::new(Pubkey::default(), account); let mut genesis = Self::new(Pubkey::default(), account);
genesis.account.data = genesis.account.data =
bincode::serialize(&LibraAccountState::create_genesis(1_000_000_000)).unwrap(); bincode::serialize(&LibraAccountState::create_genesis(amount).unwrap()).unwrap();
genesis genesis
} }