Update libra to new fork (#6523)

* Update to new libra branch

* Use core and association addresses
This commit is contained in:
TristanDebrunner 2019-10-29 10:39:10 -07:00 committed by GitHub
parent 029a2837e4
commit 489dc657c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 523 additions and 663 deletions

902
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -76,7 +76,7 @@ fn test_bench_tps_local_cluster_solana() {
fn test_bench_tps_local_cluster_move() {
let mut config = Config::default();
config.tx_count = 100;
config.duration = Duration::from_secs(20);
config.duration = Duration::from_secs(25);
config.use_move = true;
test_bench_tps_local_cluster(config);

View File

@ -14,8 +14,8 @@ log = "0.4.8"
solana-logger = { path = "../../logger", version = "0.21.0" }
solana-sdk = { path = "../../sdk", version = "0.21.0" }
solana-runtime = { path = "../../runtime", version = "0.21.0" }
types = { version = "0.0.0", package = "solana_libra_types" }
language_e2e_tests = { version = "0.0.0", package = "solana_libra_language_e2e_tests" }
types = { version = "0.0.1-sol4", package = "solana_libra_types" }
language_e2e_tests = { version = "0.0.1-sol4", package = "solana_libra_language_e2e_tests" }
solana-move-loader-api = { path = "../move_loader_api", version = "0.21.0" }
[lib]

View File

@ -23,7 +23,7 @@ use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction;
use types::account_address::AccountAddress;
use types::account_config;
pub fn create_genesis<T: Client>(from_key: &Keypair, client: &T, amount: u64) -> Keypair {
let libra_genesis_key = Keypair::new();
@ -48,7 +48,7 @@ pub fn create_genesis<T: Client>(from_key: &Keypair, client: &T, amount: u64) ->
}
pub fn upload_move_program<T: Client>(from: &Keypair, client: &T, code: &str) -> Pubkey {
let address = AccountAddress::default();
let address = account_config::association_address();
let account_state = LibraAccountState::create_program(&address, code, vec![]);
let program_bytes = bincode::serialize(&account_state).unwrap();

View File

@ -4,7 +4,7 @@ use solana_move_loader_api::processor::InvokeCommand;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::loader_instruction::LoaderInstruction;
use solana_sdk::pubkey::Pubkey;
use types::account_address::AccountAddress;
use types::account_config;
use types::transaction::TransactionArgument;
pub fn genesis(genesis_pubkey: &Pubkey, microlibras: u64) -> Instruction {
@ -28,7 +28,7 @@ pub fn mint(
];
let data = bincode::serialize(&InvokeCommand::RunProgram {
sender_address: AccountAddress::default(),
sender_address: account_config::association_address(),
function_name: "main".to_string(),
args,
})

View File

@ -1,5 +1,4 @@
use crate::librapay_instruction;
use language_e2e_tests::account::AccountResource;
use log::*;
use solana_move_loader_api::account_state::{pubkey_to_address, LibraAccountState};
use solana_move_loader_api::data_store::DataStore;
@ -75,7 +74,7 @@ pub fn create_accounts(
&from.pubkey(),
to,
lamports,
200,
400,
&solana_move_loader_api::id(),
)
})
@ -128,7 +127,7 @@ pub fn get_libra_balance<T: Client>(
.read_account_resource(&pubkey_to_address(account_address))
.unwrap();
let res = AccountResource::read_balance(&resource);
let res = resource.balance();
Ok(res)
} else {
Ok(0)

View File

@ -21,16 +21,18 @@ serde_json = "1.0.41"
solana-logger = { path = "../../logger", version = "0.21.0" }
solana-sdk = { path = "../../sdk", version = "0.21.0" }
bytecode_verifier = { version = "0.0.0", package = "solana_libra_bytecode_verifier" }
compiler = { version = "0.0.0", package = "solana_libra_compiler" }
failure = { version = "0.0.0", package = "solana_libra_failure_ext" }
language_e2e_tests = { version = "0.0.0", package = "solana_libra_language_e2e_tests" }
state_view = { version = "0.0.0", package = "solana_libra_state_view" }
stdlib = { version = "0.0.0", package = "solana_libra_stdlib" }
types = { version = "0.0.0", package = "solana_libra_types" }
vm = { version = "0.0.0", package = "solana_libra_vm" }
vm_cache_map = { version = "0.0.0", package = "solana_libra_vm_cache_map" }
vm_runtime = { version = "0.0.0", package = "solana_libra_vm_runtime" }
bytecode_verifier = { version = "0.0.1-sol4", package = "solana_libra_bytecode_verifier" }
canonical_serialization = { version = "0.0.1-sol4", package = "solana_libra_canonical_serialization" }
compiler = { version = "0.0.1-sol4", package = "solana_libra_compiler" }
failure = { version = "0.0.1-sol4", package = "solana_libra_failure_ext" }
language_e2e_tests = { version = "0.0.1-sol4", package = "solana_libra_language_e2e_tests" }
state_view = { version = "0.0.1-sol4", package = "solana_libra_state_view" }
stdlib = { version = "0.0.1-sol4", package = "solana_libra_stdlib" }
types = { version = "0.0.1-sol4", package = "solana_libra_types" }
vm = { version = "0.0.1-sol4", package = "solana_libra_vm" }
vm_cache_map = { version = "0.0.1-sol4", package = "solana_libra_vm_cache_map" }
vm_runtime = { version = "0.0.1-sol4", package = "solana_libra_vm_runtime" }
vm_runtime_types = { version = "0.0.1-sol4", package = "solana_libra_vm_runtime_types" }
[lib]
crate-type = ["lib"]

View File

@ -8,7 +8,9 @@ use std::convert::TryInto;
use stdlib::stdlib_modules;
use types::{
account_address::AccountAddress,
account_config,
byte_array::ByteArray,
identifier::Identifier,
transaction::Program,
write_set::{WriteOp, WriteSet},
};
@ -22,9 +24,9 @@ use vm_runtime::{
module_cache::{BlockModuleCache, VMModuleCache},
},
data_cache::BlockDataCache,
txn_executor::{TransactionExecutor, ACCOUNT_MODULE, COIN_MODULE},
value::Local,
txn_executor::{TransactionExecutor, ACCOUNT_MODULE, BLOCK_MODULE, COIN_MODULE},
};
use vm_runtime_types::value::Value;
// Helper function that converts a Solana Pubkey to a Libra AccountAddress (WIP)
pub fn pubkey_to_address(key: &Pubkey) -> AccountAddress {
@ -87,11 +89,12 @@ impl LibraAccountState {
let compiler = Compiler {
address: *sender_address,
code,
extra_deps,
..Compiler::default()
};
let compiled_program = compiler.into_compiled_program().expect("Failed to compile");
let compiled_program = compiler
.into_compiled_program(code)
.expect("Failed to compile");
let mut script_bytes = vec![];
compiled_program
@ -120,10 +123,9 @@ impl LibraAccountState {
let arena = Arena::new();
let state_view = DataStore::default();
let vm_cache = VMModuleCache::new(&arena);
// Libra enforces the mint address to be 0x0 (see Libra's `mint_to_address` function)
let mint_address = AccountAddress::default();
let genesis_addr = account_config::association_address();
// TODO: Need this?
let genesis_auth_key = ByteArray::new(mint_address.to_vec());
let genesis_auth_key = ByteArray::new(genesis_addr.to_vec());
let write_set = {
let fake_fetcher =
@ -132,35 +134,55 @@ impl LibraAccountState {
let block_cache = BlockModuleCache::new(&vm_cache, fake_fetcher);
let mut txn_data = TransactionMetadata::default();
txn_data.sender = mint_address;
txn_data.sender = genesis_addr;
let mut txn_executor = TransactionExecutor::new(&block_cache, &data_cache, txn_data);
txn_executor.create_account(genesis_addr).unwrap();
txn_executor
.create_account(mint_address)
.map_err(map_vm_invariant_violation_error)?
.map_err(map_vm_runtime_error)?;
.create_account(account_config::core_code_address())
.map_err(map_err_vm_status)?;
txn_executor
.execute_function(&COIN_MODULE, "initialize", vec![])
.map_err(map_vm_invariant_violation_error)?
.map_err(map_vm_runtime_error)?;
.execute_function(
&BLOCK_MODULE,
&Identifier::new("initialize").unwrap(),
vec![],
)
.map_err(map_err_vm_status)?;
txn_executor
.execute_function(
&COIN_MODULE,
&Identifier::new("initialize").unwrap(),
vec![],
)
.map_err(map_err_vm_status)?;
txn_executor
.execute_function(
&ACCOUNT_MODULE,
"mint_to_address",
vec![Local::address(mint_address), Local::u64(mint_balance)],
&Identifier::new("mint_to_address").unwrap(),
vec![Value::address(genesis_addr), Value::u64(mint_balance)],
)
.map_err(map_vm_invariant_violation_error)?
.map_err(map_vm_runtime_error)?;
.map_err(map_err_vm_status)?;
txn_executor
.execute_function(
&ACCOUNT_MODULE,
"rotate_authentication_key",
vec![Local::bytearray(genesis_auth_key)],
&Identifier::new("rotate_authentication_key").unwrap(),
vec![Value::byte_array(genesis_auth_key)],
)
.map_err(map_vm_invariant_violation_error)?
.map_err(map_vm_runtime_error)?;
.map_err(map_err_vm_status)?;
// Bump the sequence number for the Association account. If we don't do this and a
// subsequent transaction (e.g., minting) is sent from the Association account, a problem
// arises: both the genesis transaction and the subsequent transaction have sequence
// number 0
txn_executor
.execute_function(
&ACCOUNT_MODULE,
&Identifier::new("epilogue").unwrap(),
vec![],
)
.map_err(map_err_vm_status)?;
let mut stdlib_modules = vec![];
for module in modules.iter() {
@ -170,8 +192,8 @@ impl LibraAccountState {
}
txn_executor
.make_write_set(stdlib_modules, Ok(Ok(())))
.map_err(map_vm_runtime_error)?
.make_write_set(stdlib_modules, Ok(()))
.map_err(map_err_vm_status)?
.write_set()
.clone()
.into_mut()

View File

@ -1,3 +1,4 @@
use canonical_serialization::SimpleDeserializer;
use failure::prelude::*;
use indexmap::IndexMap;
use log::*;
@ -5,17 +6,12 @@ use state_view::StateView;
use types::{
access_path::AccessPath,
account_address::AccountAddress,
account_config,
account_config::{self, AccountResource},
language_storage::ModuleId,
write_set::{WriteOp, WriteSet, WriteSetMut},
};
use vm::{errors::VMInvariantViolation, CompiledModule};
use vm_runtime::{
data_cache::RemoteCache,
identifier::create_access_path,
loaded_data::{struct_def::StructDef, types::Type},
value::Value,
};
use vm::{errors::VMResult, CompiledModule};
use vm_runtime::{data_cache::RemoteCache, identifier::create_access_path};
/// An in-memory implementation of [`StateView`] and [`RemoteCache`] for the VM.
#[derive(Debug, Default)]
@ -66,17 +62,11 @@ impl DataStore {
}
/// Read an account's resource
pub fn read_account_resource(&self, addr: &AccountAddress) -> Option<Value> {
pub fn read_account_resource(&self, addr: &AccountAddress) -> Option<AccountResource> {
let access_path = create_access_path(&addr, account_config::account_struct_tag());
match self.data.get(&access_path) {
None => None,
Some(blob) => {
let account_type = get_account_struct_def();
match Value::simple_deserialize(blob, account_type) {
Ok(account) => Some(account),
Err(_) => None,
}
}
Some(blob) => SimpleDeserializer::deserialize(blob).ok(),
}
}
@ -134,32 +124,11 @@ impl StateView for DataStore {
}
impl RemoteCache for DataStore {
fn get(
&self,
access_path: &AccessPath,
) -> ::std::result::Result<Option<Vec<u8>>, VMInvariantViolation> {
fn get(&self, access_path: &AccessPath) -> VMResult<Option<Vec<u8>>> {
Ok(StateView::get(self, access_path).expect("it should not error"))
}
}
// TODO: internal Libra function and very likely to break soon, need something better
fn get_account_struct_def() -> StructDef {
// STRUCT DEF StructDef(StructDefInner { field_definitions: [ByteArray,
// Struct(StructDef(StructDefInner { field_definitions: [U64] })), U64, U64,
// U64] }) let coin = StructDef(StructDefInner { field_definitions:
// [Type::U64] })
let int_type = Type::U64;
let byte_array_type = Type::ByteArray;
let coin = Type::Struct(StructDef::new(vec![int_type.clone()]));
StructDef::new(vec![
byte_array_type,
coin,
int_type.clone(),
int_type.clone(),
int_type.clone(),
])
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -2,24 +2,10 @@
use log::*;
use solana_sdk::instruction::InstructionError;
use std::convert::TryInto;
use types::vm_error::{StatusCode, VMStatus};
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);
@ -28,23 +14,34 @@ pub fn map_data_error(err: std::boxed::Box<bincode::ErrorKind>) -> InstructionEr
_ => InstructionError::InvalidAccountData,
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn map_json_error(err: serde_json::error::Error) -> InstructionError {
debug!("Error: serde_json: {:?}", err);
InstructionError::InvalidAccountData
}
pub fn map_vm_verification_error(
err: (CompiledModule, Vec<vm::errors::VerificationError>),
) -> InstructionError {
pub fn map_vm_verification_error(err: (CompiledModule, Vec<VMStatus>)) -> 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
}
pub fn map_failure_error(err: failure::Error) -> InstructionError {
debug!("Error: Script verification failed: {:?}", err);
InstructionError::InvalidInstructionData
}
pub fn map_err_vm_status(status: VMStatus) -> InstructionError {
// Attempt to map the StatusCode (repr(u64)) to a u32 for CustomError.
// The only defined StatusCode that fails is StatusCode::UNKNOWN_ERROR
match <StatusCode as Into<u64>>::into(status.major_status).try_into() {
Ok(u) => InstructionError::CustomError(u),
Err(_) => InstructionError::GenericError,
}
}

View File

@ -2,7 +2,7 @@ use crate::account_state::{pubkey_to_address, LibraAccountState, ModuleBytes};
use crate::data_store::DataStore;
use crate::error_mappers::*;
use crate::id;
use bytecode_verifier::{VerifiedModule, VerifiedScript};
use bytecode_verifier::verifier::{VerifiedModule, VerifiedScript};
use log::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::{
@ -12,6 +12,8 @@ use solana_sdk::{
};
use types::{
account_address::AccountAddress,
account_config,
identifier::Identifier,
transaction::{Program, TransactionArgument, TransactionOutput},
};
use vm::{
@ -19,6 +21,7 @@ use vm::{
file_format::{CompiledModule, CompiledScript},
gas_schedule::{MAXIMUM_NUMBER_OF_GAS_UNITS, MAX_PRICE_PER_GAS_UNIT},
transaction_metadata::TransactionMetadata,
vm_string::VMString,
};
use vm_cache_map::Arena;
use vm_runtime::{
@ -27,8 +30,8 @@ use vm_runtime::{
module_cache::{BlockModuleCache, ModuleCache, VMModuleCache},
},
txn_executor::TransactionExecutor,
value::Local,
};
use vm_runtime_types::value::Value;
pub fn process_instruction(
_program_id: &Pubkey,
@ -76,14 +79,14 @@ impl MoveProcessor {
InstructionError::InvalidAccountData
}
fn arguments_to_locals(args: Vec<TransactionArgument>) -> Vec<Local> {
fn arguments_to_values(args: Vec<TransactionArgument>) -> Vec<Value> {
let mut locals = vec![];
for arg in args {
locals.push(match arg {
TransactionArgument::U64(i) => Local::u64(i),
TransactionArgument::Address(a) => Local::address(a),
TransactionArgument::ByteArray(b) => Local::bytearray(b),
TransactionArgument::String(s) => Local::string(s),
TransactionArgument::U64(i) => Value::u64(i),
TransactionArgument::Address(a) => Value::address(a),
TransactionArgument::ByteArray(b) => Value::byte_array(b),
TransactionArgument::String(s) => Value::string(VMString::new(s)),
});
}
locals
@ -137,13 +140,13 @@ impl MoveProcessor {
let program: Program = serde_json::from_str(&string).map_err(map_json_error)?;
let script =
CompiledScript::deserialize(&program.code()).map_err(map_vm_binary_error)?;
CompiledScript::deserialize(&program.code()).map_err(map_err_vm_status)?;
let modules = program
.modules()
.iter()
.map(|bytes| CompiledModule::deserialize(&bytes))
.collect::<Result<Vec<_>, _>>()
.map_err(map_vm_binary_error)?;
.map_err(map_err_vm_status)?;
Ok((script, modules))
}
@ -163,12 +166,12 @@ impl MoveProcessor {
modules_bytes,
} => {
let script =
VerifiedScript::deserialize(&script_bytes).map_err(map_vm_binary_error)?;
VerifiedScript::deserialize(&script_bytes).map_err(map_err_vm_status)?;
let modules = modules_bytes
.iter()
.map(|module_bytes| VerifiedModule::deserialize(&module_bytes.bytes))
.collect::<Result<Vec<_>, _>>()
.map_err(map_vm_binary_error)?;
.map_err(map_err_vm_status)?;
Ok((script, modules))
}
@ -213,13 +216,16 @@ impl MoveProcessor {
txn_metadata.gas_unit_price = *MAX_PRICE_PER_GAS_UNIT;
let mut vm = TransactionExecutor::new(&module_cache, data_store, txn_metadata);
vm.execute_function(&module_id, &function_name, Self::arguments_to_locals(args))
.map_err(map_vm_invariant_violation_error)?
.map_err(map_vm_runtime_error)?;
vm.execute_function(
&module_id,
&Identifier::new(function_name).unwrap(),
Self::arguments_to_values(args),
)
.map_err(map_err_vm_status)?;
Ok(vm
.make_write_set(modules_to_publish, Ok(Ok(())))
.map_err(map_vm_runtime_error)?)
.make_write_set(modules_to_publish, Ok(()))
.map_err(map_err_vm_status)?)
}
fn keyed_accounts_to_data_store(
@ -251,11 +257,20 @@ impl MoveProcessor {
.into_write_sets()
.map_err(|_| InstructionError::GenericError)?;
// Genesis account holds both mint and stdlib under address 0x0
// Genesis account holds both mint and stdlib
let genesis_key = *keyed_accounts[GENESIS_INDEX].unsigned_key();
let write_set = write_sets
.remove(&AccountAddress::default())
.ok_or_else(Self::missing_account)?;
let mut write_set = write_sets
.remove(&account_config::association_address())
.ok_or_else(Self::missing_account)?
.into_mut();
for (access_path, write_op) in write_sets
.remove(&account_config::core_code_address())
.ok_or_else(Self::missing_account)?
.into_iter()
{
write_set.push((access_path, write_op));
}
let write_set = write_set.freeze().unwrap();
Self::serialize_and_enforce_length(
&LibraAccountState::Genesis(write_set),
&mut keyed_accounts[GENESIS_INDEX].account.data,
@ -413,12 +428,11 @@ impl MoveProcessor {
#[cfg(test)]
mod tests {
use super::*;
use language_e2e_tests::account::AccountResource;
use solana_sdk::account::Account;
use solana_sdk::rent_calculator::RentCalculator;
use solana_sdk::sysvar::rent;
const BIG_ENOUGH: usize = 6_000;
const BIG_ENOUGH: usize = 10_000;
#[test]
fn test_account_size() {
@ -564,7 +578,7 @@ mod tests {
})
.unwrap(),
),
Err(InstructionError::InsufficientFunds)
Err(InstructionError::CustomError(4002))
);
}
@ -589,8 +603,8 @@ mod tests {
.read_account_resource(&accounts[GENESIS_INDEX + 1].address)
.unwrap();
assert_eq!(amount, AccountResource::read_balance(&payee_resource));
assert_eq!(0, AccountResource::read_sequence_number(&payee_resource));
assert_eq!(amount, payee_resource.balance());
assert_eq!(0, payee_resource.sequence_number());
}
#[test]
@ -655,13 +669,10 @@ mod tests {
let sender_resource = data_store.read_account_resource(&sender.address).unwrap();
let payee_resource = data_store.read_account_resource(&payee.address).unwrap();
assert_eq!(
amount_to_mint - amount,
AccountResource::read_balance(&sender_resource)
);
assert_eq!(0, AccountResource::read_sequence_number(&sender_resource));
assert_eq!(amount, AccountResource::read_balance(&payee_resource));
assert_eq!(0, AccountResource::read_sequence_number(&payee_resource));
assert_eq!(amount_to_mint - amount, sender_resource.balance());
assert_eq!(0, sender_resource.sequence_number());
assert_eq!(amount, payee_resource.balance());
assert_eq!(0, payee_resource.sequence_number());
}
#[test]
@ -893,9 +904,13 @@ mod tests {
owner: id(),
..Account::default()
};
let mut genesis = Self::new(Pubkey::default(), account);
genesis.account.data =
bincode::serialize(&LibraAccountState::create_genesis(amount).unwrap()).unwrap();
let mut genesis = Self::new(
Pubkey::new(&account_config::association_address().to_vec()),
account,
);
let pre_data = LibraAccountState::create_genesis(amount).unwrap();
let _hi = "hello";
genesis.account.data = bincode::serialize(&pre_data).unwrap();
genesis
}