Introduce basic skeleton for Polkador runtime.

This commit is contained in:
Gav
2018-01-08 17:13:44 +01:00
parent a670208a33
commit 1f183d688a
4 changed files with 311 additions and 85 deletions
+20 -8
View File
@@ -76,7 +76,7 @@ impl WritePrimitive<u32> for MemoryInstance {
}
impl_function_executor!(this: FunctionExecutor<'e, E>,
ext_print(utf8_data: *const u8, utf8_len: i32) => {
ext_print(utf8_data: *const u8, utf8_len: u32) => {
if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) {
if let Ok(message) = String::from_utf8(utf8) {
println!("Runtime: {}", message);
@@ -96,7 +96,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
println!("memmove {} from {}, {} bytes", dest, src, count);
dest
},
ext_memset(dest: *mut u8, val: i32, count: usize) -> *mut u8 => {
ext_memset(dest: *mut u8, val: u32, count: usize) -> *mut u8 => {
let _ = this.memory.clear(dest as usize, val as u8, count as usize);
println!("memset {} with {}, {} bytes", dest, val, count);
dest
@@ -110,12 +110,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.heap.deallocate(addr);
println!("free {}", addr)
},
ext_set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32) => {
ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) => {
if let (Ok(key), Ok(value)) = (this.memory.get(key_data, key_len as usize), this.memory.get(value_data, value_len as usize)) {
this.ext.set_storage(key, value);
}
},
ext_get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8 => {
ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => {
let (offset, written) = if let Ok(key) = this.memory.get(key_data, key_len as usize) {
if let Ok(value) = this.ext.storage(&key) {
let offset = this.heap.allocate(value.len() as u32) as u32;
@@ -126,6 +126,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.memory.write_primitive(written_out, written);
offset as u32
},
ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32 => {
if let Ok(key) = this.memory.get(key_data, key_len as usize) {
if let Ok(value) = this.ext.storage(&key) {
let written = ::std::cmp::min(value_len as usize, value.len());
let _ = this.memory.set(value_data, &value[0..written]);
written as u32
} else { 0 }
} else { 0 }
},
ext_deposit_log(_log_data: *const u8, _log_len: u32) {
unimplemented!()
}
=> <'e, E: Externalities + 'e>
);
@@ -163,8 +175,8 @@ impl CodeExecutor for WasmExecutor {
let returned = program
.params_with_external("env", &mut fec)
.map(|p| p
.add_argument(I32(offset as i32))
.add_argument(I32(size as i32)))
.add_argument(I32(offset as u32))
.add_argument(I32(size as u32)))
.and_then(|p| module.execute_export(method, p))
.map_err(|_| -> Error { ErrorKind::Runtime.into() })?;
@@ -221,8 +233,8 @@ mod tests {
let returned = program
.params_with_external("env", &mut fec)
.map(|p| p
.add_argument(I32(offset as i32))
.add_argument(I32(size as i32)))
.add_argument(I32(offset as u32))
.add_argument(I32(size as u32)))
.and_then(|p| module.execute_export("test_data_in", p))
.map_err(|_| -> Error { ErrorKind::Runtime.into() }).expect("function should be callable");
+207 -21
View File
@@ -8,29 +8,215 @@ use alloc::vec::Vec;
#[macro_use]
extern crate runtime_support;
use runtime_support::{set_storage, code, set_code, storage, validators, set_validators, print};
use runtime_support::{set_storage, storage, storage_into, print, Value20};
impl_stub!(test_data_in);
fn test_data_in(input: Vec<u8>) -> Vec<u8> {
print(b"set_storage" as &[u8]);
set_storage(b"input", &input);
/// The hash of an ECDSA pub key which is used to identify an external transactor.
type AccountID = [u8; 32];
/// The ECDSA pub key of an authority. This is what the external environment/consensus algorithm
/// refers to as a "authority".
type SessionKey = [u8; 65];
type Balance = u64;
type ChainID = u64;
type Hash = [u8; 32];
type BlockNumber = u64;
/// A proportion (rational number).
struct Proportion { nom: u64, denom: u64, };
type Timestamp = u64;
type TxOrder = u64;
/// Statistics concerning consensus.
// TODO.
struct Statistics;
/// A report of bad behaviour.
// TODO.
struct Complaint;
print(b"code" as &[u8]);
set_storage(b"code", &code());
/// The state of a parachain.
/*struct ParachainState {
head_data: Vec<u8>,
balance: Balance,
user_balances: HashMap<AccountID, Balance>,
balance_downloads: HashMap<AccountID, ( Balance, Vec<u8> ),
egress_roots: Vec<Hash>
}*/
//struct CandidateReceipt;
print(b"set_code" as &[u8]);
set_code(&input);
// TODO: include RLP implementation
// TODO: add keccak256 (or some better hashing scheme) & ECDSA-recover (or some better sig scheme)
print(b"storage" as &[u8]);
let copy = storage(b"input");
print(b"validators" as &[u8]);
let mut v = validators();
v.push(copy);
print(b"set_validators" as &[u8]);
set_validators(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
print(b"finished!" as &[u8]);
b"all ok!".to_vec()
impl_stub!(execute_block);
fn execute_block(_input: Vec<u8>) -> Vec<u8> {
// TODO: decode block and ensure valid
// TODO: iterate through transactions amd decode/dispatch them
// TODO: progress to next session if it's time
// TODO: progress to next era if it's time
Vec::new()
}
impl_stub!(execute_transaction);
fn execute_transaction(tx: Vec<u8>) -> Vec<u8> {
environment::execute_transaction(&tx)
}
/// The current relay chain identifier.
fn chain_id() -> ChainID { unimplemented!() } // TODO: retrieve from external
mod environment {
/// The current block number being processed. Set by `execute_block`.
pub fn block_number() -> BlockNumber { unimplemented!() }
/// Get the block hash of a given block.
pub fn block_hash(_number: BlockNumber) -> Hash { unimplemented!() }
/// ?
fn set_digest(_preserialised_rlp_digest: &[u8]) { unimplemented!() }
/// Get the current user's ID
pub fn current_user() -> AccountID { unimplemented!() }
/// Execute a given transaction.
pub fn execute_transaction(_tx: &[u8]) -> Vec<u8> {
// TODO: decode data and ensure valid
// TODO: ensure signature valid and recover id
// TODO: ensure target_function valid
// TODO: decode parameters
// TODO: make call
// TODO: encode any return
Vec::new()
}
/// Set the new code.
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
}
/// ?
fn set_active_parachains(_data: &[u8]) { unimplemented!() }
}
mod consensus {
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
}
fn set_authority(index: usize, authority: AccountID) {
set_storage(&value_vec(index, b"\0authority".to_vec()), &authority[..]);
}
fn authority(index: usize) -> AccountID {
storage_into::<Value20>(&value_vec(index, b"\0authority".to_vec()))
}
fn set_authority_count(count: usize) {
(count..authority_count()).for_each(|i| set_authority(i, &[]));
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))
}
/// Get the current set of authorities. These are the session keys.
pub fn authorities() -> Vec<AccountID> {
(0..authority_count()).into_iter().map(authority).map.collect()
}
/// 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));
}
/// Get the current set of validators. These are the long-term identifiers for the validators
/// and will be mapped to a session key with the most recent `set_next_session_key`.
pub fn validators() -> Vec<AccountID> {
unimplemented!()
}
/// Set the current set of validators.
///
/// Called by staking::next_era() only.
pub fn set_validators(_new: &[AccountID]) {
unimplemented!()
}
/// Flush out any statistics.
pub fn flush_statistics() -> Statistics { unimplemented!() }
/// Sets the session key of `_validator` to `_session`. This doesn't take effect until the next
/// session.
pub fn set_session_key(_validator: AccountID, _session: AccountID) {
unimplemented!()
}
/// Move onto next session: register the new authority set.
pub fn next_session() {
// TODO: Call set_authorities().
unimplemented!()
}
}
mod staking {
/// The length of a staking era in blocks.
fn era_length() -> BlockNumber { unimplemented!() }
/// The era has changed - enact new staking set.
///
/// NOTE: This is always a session change.
fn next_era() { unimplemented!() }
/// The balance of a given account.
fn balance(_who: AccountID) -> Balance { unimplemented!() }
/// User-level function to move funds onto a parachain. Calls `parachains::credit_parachain`.
fn move_to_parachain(chain_id: ChainID, value: Balance) { unimplemented!() }
/// System-level function to be called only by Parachains object when funds have left that
/// object and are to be credited here.
fn credit_staker(value: Balance) { unimplemented!() }
/// Declare the desire to stake under the requirement that under flawless operation, each era
/// should return `minimum_era_return` on the amount staked.
///
/// Effects will be felt at the beginning of the next era.
fn stake(minimum_era_return: Proportion) { unimplemented!() }
/// Retract the desire to stake.
///
/// Effects will be felt at the beginning of the next era.
fn unstake() { unimplemented!() }
/// Report invalid behaviour by a staking participant.
fn complain(complaint: Complaint) { unimplemented!() }
}
/*
mod parachains {
fn chain_ids(self) -> [ ChainID ];
fn validation_function(self, chain_id: ChainID) -> Fn(consolidated_ingress: [ ( ChainID, bytes ) ], balance_downloads: [ ( AccountID, Balance ) ], block_data: bytes, previous_head_data: bytes) -> (head_data: bytes, egress_queues: [ [ bytes ] ], balance_uploads: [ ( AccountID, Balance ) ]);
fn validate_and_calculate_fees_function(self, chain_id: ChainID) -> Fn(egress_queues: [ [ bytes ] ], balance_uploads: [ ( AccountID, Balance ) ]) -> Balance;
fn balance(self, chain_id: ChainID, id: AccountID) -> Balance;
fn verify_and_consolidate_queues(self, unprocessed_ingress: [ [ [ bytes ] ] ]) -> [ (chain_id: ChainID, message: bytes) ];
fn chain_state(self, chain_id: ChainID) -> ParachainState;
fn move_to_staking(mut self, chain_id: ChainID, value: Balance);
fn credit_parachain(mut self, chain_id: ChainID, value: Balance);
fn download(mut self, chain_id: ChainID, value: Balance, instruction: bytes);
fn update_heads(mut self, candidate_receipts: &[ ( ChainID, CandidateReceipt ) ]);
}
mod authentication {
fn validate_signature(self, tx: Transaction) -> ( AccountID, TxOrder );
fn nonce(self, id: AccountID) -> TxOrder;
fn authenticate(mut self, tx: Transaction) -> AccountID;
}
*/
mod timestamp {
fn timestamp() -> Timestamp { unimplemented!() }
fn set_timestamp(Timestamp) { unimplemented!() }
}
+36 -51
View File
@@ -17,70 +17,57 @@ pub fn panic_fmt() -> ! {
}
extern "C" {
fn ext_print(utf8_data: *const u8, utf8_len: i32);
fn ext_print(utf8_data: *const u8, utf8_len: u32);
fn ext_print_num(value: u64);
fn ext_set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32);
fn ext_get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8;
fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32);
fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8;
fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32;
fn ext_deposit_log(log_data: *const u8, log_len: u32);
}
pub fn storage(key: &[u8]) -> Vec<u8> {
let mut length: i32 = 0;
let mut length: u32 = 0;
unsafe {
let ptr = ext_get_allocated_storage(&key[0], key.len() as i32, &mut length);
let ptr = ext_get_allocated_storage(&key[0], key.len() as u32, &mut length);
Vec::from_raw_parts(ptr, length as usize, length as usize)
}
}
pub trait IsValue {
const value: usize;
}
pub struct Value20; impl IsValue for Value20 { const value = 20usize; }
pub struct Value32; impl IsValue for Value32 { const value = 32usize; }
pub struct Value64; impl IsValue for Value64 { const value = 64usize; }
pub struct Value65; impl IsValue for Value65 { const value = 65usize; }
pub fn storage_into<T: IsValue>(key: &[u8]) -> Option<[u8; T::value]> {
let mut result = [0u8; T::value];
let written = unsafe {
ext_get_storage_into(&key[0], key.len() as u32, &result[0], result.len())
};
match written {
T::value => Some(result),
_ => None,
}
}
pub fn set_storage(key: &[u8], value: &[u8]) {
unsafe {
ext_set_storage(
&key[0] as *const u8, key.len() as i32,
&value[0] as *const u8, value.len() as i32
&key[0] as *const u8, key.len() as u32,
&value[0] as *const u8, value.len() as u32
);
}
}
pub fn code() -> Vec<u8> {
storage(b"\0code")
}
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
}
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;
pub fn deposit_log(log: &[u8]) {
unsafe {
ext_deposit_log(
&log[0] as *const u8, log.len() as u32,
)
}
acc
}
pub fn set_validator(index: usize, validator: &[u8]) {
set_storage(&value_vec(index, b"\0validator".to_vec()), validator);
}
pub fn validator(index: usize) -> Vec<u8> {
storage(&value_vec(index, b"\0validator".to_vec()))
}
pub fn set_validator_count(count: usize) {
(count..validator_count()).for_each(|i| set_validator(i, &[]));
set_storage(b"\0validator_count", &value_vec(count, Vec::new()));
}
pub fn validator_count() -> usize {
storage(b"\0validator_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
}
pub fn validators() -> Vec<Vec<u8>> {
(0..validator_count()).into_iter().map(validator).collect()
}
pub fn set_validators(validators: &[&[u8]]) {
set_validator_count(validators.len());
validators.iter().enumerate().for_each(|(v, i)| set_validator(v, i));
}
pub trait Printable {
@@ -90,7 +77,7 @@ pub trait Printable {
impl<'a> Printable for &'a [u8] {
fn print(self) {
unsafe {
ext_print(&self[0] as *const u8, self.len() as i32);
ext_print(&self[0] as *const u8, self.len() as u32);
}
}
}
@@ -109,12 +96,10 @@ pub fn print<T: Printable + Sized>(value: T) {
macro_rules! impl_stub {
($name:ident) => {
pub mod _internal {
extern crate alloc;
#[no_mangle]
pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
let input = unsafe {
::alloc::vec::Vec::from_raw_parts(input_data, input_len, input_len)
super::alloc::vec::Vec::from_raw_parts(input_data, input_len, input_len)
};
let output = super::$name(input);
+48 -5
View File
@@ -8,7 +8,50 @@ use alloc::vec::Vec;
#[macro_use]
extern crate runtime_support;
use runtime_support::{set_storage, code, set_code, storage, validators, set_validators, print};
use runtime_support::{set_storage, storage, print};
pub fn code() -> Vec<u8> {
storage(b"\0code")
}
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
}
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: usize, authority: &[u8]) {
set_storage(&value_vec(index, b"\0authority".to_vec()), authority);
}
pub fn authority(index: usize) -> Vec<u8> {
storage(&value_vec(index, b"\0authority".to_vec()))
}
pub fn set_authority_count(count: usize) {
(count..authority_count()).for_each(|i| set_authority(i, &[]));
set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
}
pub fn authority_count() -> usize {
storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
}
pub fn authorities() -> Vec<Vec<u8>> {
(0..authority_count()).into_iter().map(authority).collect()
}
pub fn set_authorities(authorities: &[&[u8]]) {
set_authority_count(authorities.len());
authorities.iter().enumerate().for_each(|(v, i)| set_authority(v, i));
}
impl_stub!(test_data_in);
fn test_data_in(input: Vec<u8>) -> Vec<u8> {
@@ -24,12 +67,12 @@ fn test_data_in(input: Vec<u8>) -> Vec<u8> {
print(b"storage" as &[u8]);
let copy = storage(b"input");
print(b"validators" as &[u8]);
let mut v = validators();
print(b"authorities" as &[u8]);
let mut v = authorities();
v.push(copy);
print(b"set_validators" as &[u8]);
set_validators(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
print(b"set_authorities" as &[u8]);
set_authorities(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
print(b"finished!" as &[u8]);
b"all ok!".to_vec()