Balance transfers + util methods.

This commit is contained in:
Gav
2018-01-14 20:51:46 +01:00
parent 6146779e6e
commit bd8f67a20d
2 changed files with 212 additions and 47 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ pub use std::cell::RefCell;
pub use std::boxed::Box;
pub use std::mem::{size_of, transmute};
use polkadot_state_machine::Externalities;
pub use polkadot_state_machine::Externalities;
use std::fmt;
// TODO: use the real error, not NoError.
+211 -46
View File
@@ -3,7 +3,7 @@
#[macro_use]
extern crate runtime_support;
use runtime_support::{set_storage, storage, storage_into, Vec, size_of};
use runtime_support::{Vec, size_of};
use runtime_support::{Rc, RefCell, transmute, Box};
/// The hash of an ECDSA pub key which is used to identify an external transactor.
@@ -93,6 +93,12 @@ struct Environment {
block_number: BlockNumber,
}
fn with_env<T, F: FnOnce(&mut Environment) -> T>(f: F) -> T {
let e = env();
let mut eb = e.borrow_mut();
f(&mut *eb)
}
fn env() -> Rc<RefCell<Environment>> {
// Initialize it to a null value
static mut SINGLETON: *const Rc<RefCell<Environment>> = 0 as *const Rc<RefCell<Environment>>;
@@ -111,6 +117,77 @@ fn env() -> Rc<RefCell<Environment>> {
}
}
fn value_vec(mut value: u32, initial: Vec<u8>) -> Vec<u8> {
let mut acc = initial;
while value > 0 {
acc.push(value as u8);
value /= 256;
}
acc
}
trait EndianSensitive: Sized {
fn to_le(self) -> Self { self }
fn to_be(self) -> Self { self }
fn from_le(self) -> Self { self }
fn from_be(self) -> Self { self }
}
macro_rules! impl_endians {
( $( $t:ty ),* ) => { $(
impl EndianSensitive for $t {
fn to_le(self) -> Self { <$t>::to_le(self) }
fn to_be(self) -> Self { <$t>::to_be(self) }
fn from_le(self) -> Self { <$t>::from_le(self) }
fn from_be(self) -> Self { <$t>::from_be(self) }
}
)* }
}
macro_rules! impl_non_endians {
( $( $t:ty ),* ) => { $(
impl EndianSensitive for $t {}
)* }
}
impl_endians!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
impl_non_endians!([u8; 20], [u8; 32]);
trait Storage {
fn storage_into(key: &[u8]) -> Self;
fn store(self, key: &[u8]);
}
impl<T: Default + EndianSensitive> Storage for T {
fn storage_into(key: &[u8]) -> Self {
runtime_support::storage_into(key).map(EndianSensitive::from_le).unwrap_or_else(Default::default)
}
fn store(self, key: &[u8]) {
let size = size_of::<Self>();
let value_bytes = self.to_le();
let value_slice = unsafe {
std::slice::from_raw_parts(transmute::<*const Self, *const u8>(&value_bytes), size)
};
runtime_support::set_storage(key, value_slice);
}
}
fn storage_into<T: Storage>(key: &[u8]) -> T {
T::storage_into(key)
}
trait KeyedVec {
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8>;
}
impl KeyedVec for AccountID {
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
let mut r = prepend_key.to_vec();
r.extend_from_slice(self);
r
}
}
// TODO: include RLP implementation
// TODO: add keccak256 (or some better hashing scheme) & ECDSA-recover (or some better sig scheme)
@@ -127,26 +204,27 @@ pub fn execute_transaction(_input: Vec<u8>) -> Vec<u8> {
impl_stubs!(execute_block, execute_transaction);
/// The current relay chain identifier.
fn chain_id() -> ChainID {
pub fn chain_id() -> ChainID {
// TODO: retrieve from external
unimplemented!()
}
mod environment {
pub mod environment {
use super::*;
/// The current block number being processed. Set by `execute_block`.
pub fn block_number() -> BlockNumber { let e = env(); let eb = e.borrow(); eb.block_number }
pub fn block_number() -> BlockNumber {
with_env(|e| e.block_number)
}
/// Get the block hash of a given block.
pub fn block_hash(_number: BlockNumber) -> Hash { unimplemented!() }
pub fn block_hash(_number: BlockNumber) -> Hash {
unimplemented!()
}
pub fn execute_block(_block: &Block) -> Vec<u8> {
// populate environment from header.
{
let e = env();
e.borrow_mut().block_number = _block.header.number;
}
with_env(|e| e.block_number = _block.header.number);
staking::pre_transactions();
@@ -174,7 +252,7 @@ mod environment {
/// Set the new code.
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
runtime_support::set_storage(b"\0code", new)
}
/// Set the light-client digest for the header.
@@ -184,33 +262,24 @@ mod environment {
}
}
mod consensus {
pub mod consensus {
use super::*;
fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
let mut acc = initial;
while value > 0 {
acc.push(value as u8);
value /= 256;
}
acc
pub fn set_authority(index: u32, authority: AccountID) {
runtime_support::set_storage(&value_vec(index, b"\0authority".to_vec()), &authority[..]);
}
fn set_authority(index: usize, authority: AccountID) {
set_storage(&value_vec(index, b"\0authority".to_vec()), &authority[..]);
fn authority(index: u32) -> AccountID {
runtime_support::storage_into(&value_vec(index, b"\0authority".to_vec())).unwrap()
}
fn authority(index: usize) -> AccountID {
storage_into(&value_vec(index, b"\0authority".to_vec())).unwrap()
}
fn set_authority_count(count: usize) {
pub fn set_authority_count(count: u32) {
(count..authority_count()).for_each(|i| set_authority(i, SessionKey::default()));
set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
runtime_support::set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
}
fn authority_count() -> usize {
storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
fn authority_count() -> u32 {
runtime_support::storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as u32))
}
/// Get the current set of authorities. These are the session keys.
@@ -221,9 +290,9 @@ mod consensus {
/// Set the current set of authorities' session keys.
///
/// Called by `next_session` only.
fn set_authorities(authorities: &[AccountID]) {
set_authority_count(authorities.len());
authorities.iter().enumerate().for_each(|(v, &i)| set_authority(v, i));
pub fn set_authorities(authorities: &[AccountID]) {
set_authority_count(authorities.len() as u32);
authorities.iter().enumerate().for_each(|(v, &i)| set_authority(v as u32, i));
}
/// Get the current set of validators. These are the long-term identifiers for the validators
@@ -265,35 +334,56 @@ mod consensus {
}
}
mod staking {
pub mod staking {
use super::*;
/// The length of a staking era in blocks.
pub fn era_length() -> BlockNumber { sessions_per_era() * consensus::session_length() }
pub fn era_length() -> BlockNumber {
sessions_per_era() * consensus::session_length()
}
/// The length of a staking era in sessions.
pub fn sessions_per_era() -> BlockNumber { 10 }
pub fn sessions_per_era() -> BlockNumber {
10
}
/// The era has changed - enact new staking set.
///
/// NOTE: This always happens on a session change.
fn next_era() { unimplemented!() }
pub fn next_era() {
unimplemented!()
}
/// The balance of a given account.
fn balance(_who: AccountID) -> Balance { unimplemented!() }
pub fn balance(who: &AccountID) -> Balance {
storage_into(&who.to_keyed_vec(b"sta\0bal\0"))
}
/// Transfer some unlocked staking balance to another staker.
pub fn transfer_stake(_transactor: AccountID, _dest: AccountID, _value: Balance) { unimplemented!() }
pub fn transfer_stake(transactor: &AccountID, dest: &AccountID, value: Balance) {
let from_key = transactor.to_keyed_vec(b"sta\0bal\0");
let from_balance: Balance = storage_into(&from_key);
assert!(from_balance >= value);
let to_key = dest.to_keyed_vec(b"sta\0bal\0");
let to_balance: Balance = storage_into(&to_key);
assert!(to_balance + value > to_balance); // no overflow
(from_balance - value).store(&from_key);
(to_balance + value).store(&to_key);
}
/// Declare the desire to stake for the transactor.
///
/// Effects will be felt at the beginning of the next era.
pub fn stake(_transactor: &AccountID) { unimplemented!() }
pub fn stake(_transactor: &AccountID) {
unimplemented!()
}
/// Retract the desire to stake for the transactor.
///
/// Effects will be felt at the beginning of the next era.
pub fn unstake(_transactor: &AccountID) { unimplemented!() }
pub fn unstake(_transactor: &AccountID) {
unimplemented!()
}
/// Hook to be called prior to transaction processing.
pub fn pre_transactions() {
@@ -307,17 +397,92 @@ mod staking {
}
}
mod authentication {
pub mod authentication {
use super::*;
fn validate_signature(_tx: Transaction) -> ( AccountID, TxOrder ) { unimplemented!() }
fn nonce(_id: AccountID) -> TxOrder { unimplemented!() }
fn authenticate(_tx: Transaction) -> AccountID { unimplemented!() }
pub fn validate_signature(_tx: Transaction) -> ( AccountID, TxOrder ) {
unimplemented!()
}
pub fn nonce(_id: AccountID) -> TxOrder {
unimplemented!()
}
pub fn authenticate(_tx: Transaction) -> AccountID {
unimplemented!()
}
}
mod timestamp {
pub mod timestamp {
use super::*;
fn timestamp() -> Timestamp { unimplemented!() }
fn set_timestamp(_now: Timestamp) { unimplemented!() }
pub fn timestamp() -> Timestamp {
unimplemented!()
}
pub fn set_timestamp(_now: Timestamp) {
unimplemented!()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use runtime_support::{NoError, with_externalities, Externalities};
#[derive(Debug, Default)]
struct TestExternalities {
storage: HashMap<Vec<u8>, Vec<u8>>,
}
impl Externalities for TestExternalities {
type Error = NoError;
fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> {
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
}
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.storage.insert(key, value);
}
}
macro_rules! map {
($( $name:expr => $value:expr ),*) => (
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
)
}
#[test]
fn staking_balance_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let mut t = TestExternalities { storage: map![
{ let mut r = b"sta\0bal\0".to_vec(); r.extend_from_slice(&one); r } => vec![42u8, 0, 0, 0, 0, 0, 0, 0]
], };
with_externalities(&mut t, || {
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 0);
});
}
#[test]
fn staking_balance_transfer_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let mut t = TestExternalities { storage: map![
{ let mut r = b"sta\0bal\0".to_vec(); r.extend_from_slice(&one); r } => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
], };
with_externalities(&mut t, || {
staking::transfer_stake(&one, &two, 69);
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
}
}