Skip to content

Commit

Permalink
feat(native-contract): Support for asset creation and transfer. (nerv…
Browse files Browse the repository at this point in the history
…osnetwork#37)

* feat(native-contract): Support for asset creation and transfer.

* handle deploy asset.

* refactor: Abstract trie database.

* Update self root.

* Reuse trie

* fill invok context.

* add tests for state adapter and trie.

* add test and fix bug

* fix ci
  • Loading branch information
Wenchao Hu authored and zeroqn committed Sep 25, 2019
1 parent 4609526 commit 1c505fb
Show file tree
Hide file tree
Showing 34 changed files with 1,920 additions and 163 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ members = [
"common/pubsub",

"core/api",
"core/bank",
"core/consensus",
"core/executor",
"core/mempool",
Expand Down
9 changes: 0 additions & 9 deletions core/bank/Cargo.toml

This file was deleted.

7 changes: 0 additions & 7 deletions core/bank/src/lib.rs

This file was deleted.

10 changes: 6 additions & 4 deletions core/consensus/src/fixed_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ mod test {

use protocol::codec::ProtocolCodec;
use protocol::types::{
Fee, Hash, RawTransaction, SignedTransaction, TransactionAction, UserAddress,
CarryingAsset, Fee, Hash, RawTransaction, SignedTransaction, TransactionAction, UserAddress,
};

use super::FixedSignedTxs;
Expand All @@ -177,9 +177,11 @@ mod test {
cycle: random::<u64>(),
};
let action = TransactionAction::Transfer {
receiver: address.clone(),
asset_id: nonce.clone(),
amount: FromPrimitive::from_i32(42).unwrap(),
receiver: address.clone(),
carrying_asset: CarryingAsset {
asset_id: nonce.clone(),
amount: FromPrimitive::from_i32(42).unwrap(),
},
};
let mut raw = RawTransaction {
chain_id: nonce.clone(),
Expand Down
38 changes: 27 additions & 11 deletions core/executor/src/adapter/contract.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error;
use std::rc::Rc;

use bytes::Bytes;
use derive_more::{Display, From};
Expand All @@ -9,19 +11,21 @@ use protocol::traits::executor::{ContractSchema, ContractSer};
use protocol::types::MerkleRoot;
use protocol::{ProtocolError, ProtocolErrorKind, ProtocolResult};

use crate::trie::MPTTrie;
use crate::trie::{MPTTrie, TrieDB};

pub struct GeneralContractStateAdapter {
trie: MPTTrie,
pub type RcGeneralContractStateAdapter<DB> = Rc<RefCell<GeneralContractStateAdapter<DB>>>;

// TODO(@yejiayu): The value of "map" should be changed to Box<dyn Any> to avoid multiple
pub struct GeneralContractStateAdapter<DB: TrieDB> {
trie: MPTTrie<DB>,

// TODO(@yejiayu): The value of HashMap should be changed to Box<dyn Any> to avoid multiple
// serializations.
cache_map: HashMap<Bytes, Bytes>,
stash_map: HashMap<Bytes, Bytes>,
}

impl GeneralContractStateAdapter {
pub fn new(trie: MPTTrie) -> Self {
impl<DB: TrieDB> GeneralContractStateAdapter<DB> {
pub fn new(trie: MPTTrie<DB>) -> Self {
Self {
trie,

Expand All @@ -31,22 +35,24 @@ impl GeneralContractStateAdapter {
}
}

impl ContractStateAdapter for GeneralContractStateAdapter {
impl<DB: TrieDB> ContractStateAdapter for GeneralContractStateAdapter<DB> {
fn get<Schema: ContractSchema>(
&self,
key: &<Schema as ContractSchema>::Key,
) -> ProtocolResult<Option<<Schema as ContractSchema>::Value>> {
if let Some(value_bytes) = self.cache_map.get(&key.encode()?) {
let encoded_key = key.encode()?;

if let Some(value_bytes) = self.cache_map.get(&encoded_key) {
let inst = <_>::decode(value_bytes.clone())?;
return Ok(Some(inst));
}

if let Some(value_bytes) = self.stash_map.get(&key.encode()?) {
if let Some(value_bytes) = self.stash_map.get(&encoded_key) {
let inst = <_>::decode(value_bytes.clone())?;
return Ok(Some(inst));
}

if let Some(value_bytes) = self.trie.get(key.encode()?)? {
if let Some(value_bytes) = self.trie.get(&encoded_key)? {
return Ok(Some(Schema::Value::decode(value_bytes)?));
}

Expand All @@ -57,7 +63,17 @@ impl ContractStateAdapter for GeneralContractStateAdapter {
&self,
key: &<Schema as ContractSchema>::Key,
) -> ProtocolResult<bool> {
Ok(self.get::<Schema>(key)?.is_some())
let encoded_key = key.encode()?;

if self.cache_map.contains_key(&encoded_key) {
return Ok(true);
};

if self.stash_map.contains_key(&encoded_key) {
return Ok(true);
};

self.trie.contains(&encoded_key)
}

fn insert_cache<Schema: ContractSchema>(
Expand Down
4 changes: 3 additions & 1 deletion core/executor/src/adapter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod contract;

pub use contract::{GeneralContractStateAdapter, GeneralContractStateAdapterError};
pub use contract::{
GeneralContractStateAdapter, GeneralContractStateAdapterError, RcGeneralContractStateAdapter,
};
59 changes: 59 additions & 0 deletions core/executor/src/cycles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::collections::HashMap;
use std::error::Error;

use derive_more::{Display, From};
use lazy_static::lazy_static;

use protocol::types::Fee;
use protocol::{ProtocolError, ProtocolErrorKind, ProtocolResult};

const NATIVE_BASE_CYCLES: u64 = 10;

lazy_static! {
static ref CYCLES_TABLE: HashMap<CyclesAction, u64> = {
let mut table = HashMap::new();
table.insert(CyclesAction::AccountTransfer, NATIVE_BASE_CYCLES * 21);
table.insert(CyclesAction::BankRegister, NATIVE_BASE_CYCLES * 210);
table
};
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum CyclesAction {
AccountTransfer,
BankRegister,
}

pub fn consume_cycles(
action: CyclesAction,
cycles_price: u64,
fee: &mut Fee,
limit: &Fee,
) -> ProtocolResult<()> {
let cycles_used = fee.cycle
+ CYCLES_TABLE
.get(&action)
.unwrap_or_else(|| panic!("cycles action {:?} uninitialized", action));
let cycles_used = cycles_used * cycles_price;

if cycles_used > limit.cycle {
return Err(CyclesError::OutOfCycles.into());
}

fee.cycle = cycles_used;
Ok(())
}

#[derive(Debug, Display, From)]
pub enum CyclesError {
#[display(fmt = "out of cycles")]
OutOfCycles,
}

impl Error for CyclesError {}

impl From<CyclesError> for ProtocolError {
fn from(err: CyclesError) -> ProtocolError {
ProtocolError::new(ProtocolErrorKind::Executor, Box::new(err))
}
}
20 changes: 10 additions & 10 deletions core/executor/src/fixed_types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::collections::BTreeMap;
use std::error::Error;
use std::mem;

use bytes::Bytes;
use derive_more::{Display, From};
Expand Down Expand Up @@ -186,7 +185,7 @@ impl rlp::Encodable for FixedAccount {
Account::User(user) => {
s.begin_list(3);
s.append(&USER_ACCOUNT_FLAG);
s.append(&u64_to_vec(user.nonce));
s.append(&user.nonce.to_be_bytes().to_vec());

let mut asset_list = Vec::with_capacity(user.assets.len());

Expand All @@ -205,7 +204,7 @@ impl rlp::Encodable for FixedAccount {
Account::Contract(contract) => {
s.begin_list(4);
s.append(&CONTRACT_ACCOUNT_FLAG);
s.append(&u64_to_vec(contract.nonce));
s.append(&contract.nonce.to_be_bytes().to_vec());
s.append(&contract.storage_root.as_bytes().to_vec());

let mut asset_list = Vec::with_capacity(contract.assets.len());
Expand Down Expand Up @@ -233,7 +232,7 @@ impl rlp::Decodable for FixedAccount {

match flag {
USER_ACCOUNT_FLAG => {
let nonce: u64 = r.at(1)?.as_val()?;
let nonce = bytes_to_u64(r.at(1)?.data()?);
let asset_list: Vec<FixedUserAssetInfo> = rlp::decode_list(r.at(2)?.as_raw());

let mut assets = BTreeMap::new();
Expand All @@ -250,7 +249,7 @@ impl rlp::Decodable for FixedAccount {
})
}
CONTRACT_ACCOUNT_FLAG => {
let nonce: u64 = r.at(1)?.as_val()?;
let nonce = bytes_to_u64(r.at(1)?.data()?);
let storage_root_bytes = r.at(2)?.data()?;
let asset_list: Vec<FixedContractAsset> = rlp::decode_list(r.at(3)?.as_raw());

Expand Down Expand Up @@ -403,11 +402,6 @@ impl rlp::Decodable for FixedContractAsset {
}
}

fn u64_to_vec(n: u64) -> Vec<u8> {
let nonce_bytes: [u8; 8] = unsafe { mem::transmute(n.to_be()) };
nonce_bytes.to_vec()
}

#[derive(Debug, Display, From)]
pub enum FixedTypesError {
Decoder(rlp::DecoderError),
Expand All @@ -420,3 +414,9 @@ impl From<FixedTypesError> for ProtocolError {
ProtocolError::new(ProtocolErrorKind::Executor, Box::new(err))
}
}

fn bytes_to_u64(bytes: &[u8]) -> u64 {
let mut nonce_bytes = [0u8; 8];
nonce_bytes.copy_from_slice(bytes);
u64::from_be_bytes(nonce_bytes)
}
Loading

0 comments on commit 1c505fb

Please sign in to comment.