mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Balance transfers + util methods.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user