Introduce basic skeleton for Polkadot runtime. (#32)

* Introduce basic skeleton for Polkador runtime.

* Clean up the runtime skeleton.

* Make initial runtime skeleton compile.

* Compile polkadot-runtime both for Wasm ad native, allowing for testing and direct usage.

* More fleshing out on runtime.

* Update native support.

* Fix warning.

* Update gitignore

* Update path.

* Fix path.

* Remove accidentally committed files.

* Add wasm binaries.

* Fix test.

* Native storage support API.

* Add environmental module

* Add native environment to make native source-code compatible with wasm.

Also tests.

* Finish up & polish environment stuff.

* Avoid using reentrancy issues.

* Add some docs and a test.

* Remove unneeded function.

* Documentation

* Tweak docs

* Remove TODOs.

* Balance transfers + util methods.

* Rejig tests and ensure authorities are addressed consistently.

* Add marshaller for xfer function

* Transaction dispatch test.

* Minor fix.

* Add test for ser/de transaction.

* Add ser/de for header.

* Add tests for header ser/de

* Introduce basic block decoding/execution framework.

* Introduce block decoding/execution framework (p2)

* Big refactor.

* Split out joiner.

* Hide away support modules.

* Fix up wasm runtime.

* use externalities for chain_id

* Clean up (Test)Externalities.

* Repot and introduce keccak-256 external.

* Signing with crypto.

* fix unsafety hole in environmental using function

* Introduce Ed25519 crypto.

* Repotting.

* Add ed25519_verify external.

* Introduce Ed25519 verify as an external.

* fix unsafety hole around unwinding

* Compile fixes.

* use new environmental API

* Tests for ed25519 verify.

* Polish

* Introduce UncheckedTransaction & test.

* Implement basic block and tx processing

* Introduce static hex and valid signature for block test.

* Repot session.

* comments.

* Refactor and timestamp test

* Remove fluff

* Remove fluff.

* Staking eras and tests.

* Implement sessions.

* Polish

* Test sessions.

* Introduce better hashing.

- Blake2 for secure hashing
- XX for fast hashing

* Fix tests.

* Introduce staking.

* Tests for simple staking system.

* Build fix for wasm.

* Fix tests.

* Repotting and docs.

* Docs and licence.

* Documentation.

* Remove superfluous code.

* Remove dummy key.

* Remove other superfluous file.

* Optimise with swap_remove
This commit is contained in:
Gav Wood
2018-01-23 15:24:17 +01:00
committed by Arkadiy Paronyan
parent 28d84d8ac4
commit 3402f169a7
70 changed files with 3578 additions and 282 deletions
+1 -1
View File
@@ -97,7 +97,7 @@ mod tests {
"candidates": [
{
"parachainIndex": 10,
"collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"collatorSignature": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"unprocessedIngress": [],
"block": "0x01030508"
}
+235
View File
@@ -0,0 +1,235 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Simple Ed25519 API.
use untrusted;
use ring::{rand, signature};
use rustc_hex::FromHex;
/// Verify a message without type checking the parameters' types for the right size.
pub fn verify(sig: &[u8], message: &[u8], public: &[u8]) -> bool {
let public_key = untrusted::Input::from(public);
let msg = untrusted::Input::from(message);
let sig = untrusted::Input::from(sig);
match signature::verify(&signature::ED25519, public_key, msg, sig) {
Ok(_) => true,
_ => false,
}
}
/// A public key.
#[derive(PartialEq, Clone, Debug)]
pub struct Public ([u8; 32]);
/// A key pair.
pub struct Pair(signature::Ed25519KeyPair);
/// A signature.
#[derive(Clone)]
pub struct Signature ([u8; 64]);
impl Signature {
/// A new signature from the given 64-byte `data`.
pub fn from(data: [u8; 64]) -> Self {
Signature(data)
}
/// A new signature from the given slice that should be 64 bytes long.
pub fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 64];
r.copy_from_slice(data);
Signature(r)
}
}
impl AsRef<[u8; 64]> for Signature {
fn as_ref(&self) -> &[u8; 64] {
&self.0
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl Public {
/// A new instance from the given 32-byte `data`.
pub fn from(data: [u8; 32]) -> Self {
Public(data)
}
/// A new instance from the given slice that should be 32 bytes long.
pub fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(data);
Public(r)
}
}
impl AsRef<[u8; 32]> for Public {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl AsRef<[u8]> for Public {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl Pair {
/// Generate new secure (random) key pair.
pub fn new() -> Pair {
let rng = rand::SystemRandom::new();
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
Pair(signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap())
}
/// Make a new key pair from a seed phrase.
pub fn from_seed(seed: &[u8; 32]) -> Pair {
Pair(signature::Ed25519KeyPair::from_seed_unchecked(untrusted::Input::from(&seed[..])).unwrap())
}
/// Make a new key pair from the raw secret.
pub fn from_secret(secret: &[u8; 32]) -> Pair {
let mut pkcs8_bytes = FromHex::from_hex("302e020100300506032b657004220420").unwrap();
pkcs8_bytes.extend_from_slice(&secret[..]);
Pair(signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(untrusted::Input::from(&pkcs8_bytes)).unwrap())
}
/// Make a new key pair from the raw secret and public key (it will check to make sure
/// they correspond to each other).
pub fn from_both(secret_public: &[u8; 64]) -> Option<Pair> {
let mut pkcs8_bytes = FromHex::from_hex("3053020101300506032b657004220420").unwrap();
pkcs8_bytes.extend_from_slice(&secret_public[0..32]);
pkcs8_bytes.extend_from_slice(&[0xa1u8, 0x23, 0x03, 0x21, 0x00]);
pkcs8_bytes.extend_from_slice(&secret_public[32..64]);
signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(untrusted::Input::from(&pkcs8_bytes)).ok().map(Pair)
}
/// Sign a message.
pub fn sign(&self, message: &[u8]) -> Signature {
let mut r = [0u8; 64];
r.copy_from_slice(self.0.sign(message).as_ref());
Signature(r)
}
/// Get the public key.
pub fn public(&self) -> Public {
let mut r = [0u8; 32];
let pk = self.0.public_key_bytes();
r.copy_from_slice(pk);
Public(r)
}
}
impl Signature {
/// Verify a message.
pub fn verify(&self, message: &[u8], public: &Public) -> bool {
let peer_public_key = untrusted::Input::from(&public.0[..]);
let msg = untrusted::Input::from(message);
let sig = untrusted::Input::from(&self.0[..]);
match signature::verify(&signature::ED25519, peer_public_key, msg, sig) {
Ok(_) => true,
_ => false,
}
}
}
impl From<&'static str> for Public {
fn from(hex: &'static str) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(&FromHex::from_hex(hex).unwrap()[0..32]);
Public(r)
}
}
impl From<&'static str> for Pair {
fn from(hex: &'static str) -> Self {
let data = FromHex::from_hex(hex).expect("Key pair given is static so hex should be good.");
match data.len() {
32 => {
let mut r = [0u8; 32];
r.copy_from_slice(&data[0..32]);
Pair::from_secret(&r)
}
64 => {
let mut r = [0u8; 64];
r.copy_from_slice(&data[0..64]);
Pair::from_both(&r).expect("Key pair given is static so should be good.")
}
_ => {
panic!("Key pair given is static so should be correct length.");
}
}
}
}
impl From<&'static str> for Signature {
fn from(hex: &'static str) -> Self {
let mut r = [0u8; 64];
r.copy_from_slice(&FromHex::from_hex(hex).unwrap()[0..64]);
Signature(r)
}
}
impl PartialEq for Signature {
fn eq(&self, other: &Signature) -> bool {
self.0.iter().eq(other.0.iter())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_vector_should_work() {
let pair: Pair = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".into();
let public = pair.public();
assert_eq!(public, "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".into());
let message = b"";
let signature: Signature = "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b".into();
assert!(&pair.sign(&message[..]) == &signature);
assert!(signature.verify(&message[..], &public));
}
#[test]
fn generated_pair_should_work() {
let pair = Pair::new();
let public = pair.public();
let message = b"Something important";
let signature = pair.sign(&message[..]);
assert!(signature.verify(&message[..], &public));
}
#[test]
fn seeded_pair_should_work() {
let pair = Pair::from_seed(b"12345678901234567890123456789012");
let public = pair.public();
assert_eq!(public, "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".into());
let message = b"Something important";
let signature = pair.sign(&message[..]);
assert!(signature.verify(&message[..], &public));
}
#[test]
fn can_sign_transaction() {
let pair = Pair::from_seed(b"12345678901234567890123456789012");
let public = pair.public();
assert_eq!(public, "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".into());
let message = FromHex::from_hex("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000").unwrap();
let signature = pair.sign(&message[..]);
assert!(signature.verify(&message[..], &public));
}
}
+2 -2
View File
@@ -41,8 +41,8 @@ impl_hash!(H160, 20);
impl_serde!(H160, 20);
impl_hash!(H256, 32);
impl_serde!(H256, 32);
impl_hash!(H520, 65);
impl_serde!(H520, 65);
impl_hash!(H512, 64);
impl_serde!(H512, 64);
#[cfg(test)]
mod tests {
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Hashing functions.
use blake2_rfc;
use twox_hash;
/// Do a Blake2 512-bit hash and place result in `dest`.
pub fn blake2_512_into(data: &[u8], dest: &mut[u8; 64]) {
dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes());
}
/// Do a Blake2 512-bit hash and return result.
pub fn blake2_512(data: &[u8]) -> [u8; 64] {
let mut r: [u8; 64] = unsafe { ::std::mem::uninitialized() };
blake2_512_into(data, &mut r);
r
}
/// Do a Blake2 256-bit hash and place result in `dest`.
pub fn blake2_256_into(data: &[u8], dest: &mut[u8; 32]) {
dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes());
}
/// Do a Blake2 256-bit hash and return result.
pub fn blake2_256(data: &[u8]) -> [u8; 32] {
let mut r: [u8; 32] = unsafe { ::std::mem::uninitialized() };
blake2_256_into(data, &mut r);
r
}
/// Do a Blake2 128-bit hash and place result in `dest`.
pub fn blake2_128_into(data: &[u8], dest: &mut[u8; 16]) {
dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes());
}
/// Do a Blake2 128-bit hash and return result.
pub fn blake2_128(data: &[u8]) -> [u8; 16] {
let mut r: [u8; 16] = unsafe { ::std::mem::uninitialized() };
blake2_128_into(data, &mut r);
r
}
/// Do a XX 128-bit hash and place result in `dest`.
pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) {
use ::std::hash::Hasher;
let mut h0 = twox_hash::XxHash::with_seed(0);
let mut h1 = twox_hash::XxHash::with_seed(1);
h0.write(data);
h1.write(data);
let r0 = h0.finish();
let r1 = h1.finish();
use byteorder::{ByteOrder, LittleEndian};
LittleEndian::write_u64(&mut dest[0..8], r0);
LittleEndian::write_u64(&mut dest[8..16], r1);
}
/// Do a XX 128-bit hash and return result.
pub fn twox_128(data: &[u8]) -> [u8; 16] {
let mut r: [u8; 16] = unsafe { ::std::mem::uninitialized() };
twox_128_into(data, &mut r);
r
}
/// Do a XX 256-bit hash and place result in `dest`.
pub fn twox_256_into(data: &[u8], dest: &mut [u8; 32]) {
use ::std::hash::Hasher;
use byteorder::{ByteOrder, LittleEndian};
let mut h0 = twox_hash::XxHash::with_seed(0);
let mut h1 = twox_hash::XxHash::with_seed(1);
let mut h2 = twox_hash::XxHash::with_seed(2);
let mut h3 = twox_hash::XxHash::with_seed(3);
h0.write(data);
h1.write(data);
h2.write(data);
h3.write(data);
let r0 = h0.finish();
let r1 = h1.finish();
let r2 = h2.finish();
let r3 = h3.finish();
LittleEndian::write_u64(&mut dest[0..8], r0);
LittleEndian::write_u64(&mut dest[8..16], r1);
LittleEndian::write_u64(&mut dest[16..24], r2);
LittleEndian::write_u64(&mut dest[24..32], r3);
}
/// Do a XX 256-bit hash and return result.
pub fn twox_256(data: &[u8]) -> [u8; 32] {
let mut r: [u8; 32] = unsafe { ::std::mem::uninitialized() };
twox_256_into(data, &mut r);
r
}
+60
View File
@@ -0,0 +1,60 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Wrapper type for byte collections that outputs hex.
/// Simple wrapper to display hex representation of bytes.
pub struct HexDisplay<'a>(&'a [u8]);
impl<'a> HexDisplay<'a> {
/// Create new instance that will display `d` as a hex string when displayed.
pub fn from(d: &'a AsBytesRef) -> Self { HexDisplay(d.as_bytes_ref()) }
}
impl<'a> ::std::fmt::Display for HexDisplay<'a> {
fn fmt(&self, fmtr: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
for byte in self.0 {
try!( fmtr.write_fmt(format_args!("{:02x}", byte)));
}
Ok(())
}
}
/// Simple trait to transferm various types to `&[u8]`
pub trait AsBytesRef {
/// Transferm `self` into `&[u8]`.
fn as_bytes_ref(&self) -> &[u8];
}
impl AsBytesRef for [u8] {
fn as_bytes_ref(&self) -> &[u8] { &self }
}
impl AsBytesRef for Vec<u8> {
fn as_bytes_ref(&self) -> &[u8] { &self }
}
macro_rules! impl_non_endians {
( $( $t:ty ),* ) => { $(
impl AsBytesRef for $t {
fn as_bytes_ref(&self) -> &[u8] { &self[..] }
}
)* }
}
impl_non_endians!([u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8],
[u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40],
[u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128]);
+11 -3
View File
@@ -20,7 +20,11 @@
extern crate rustc_hex;
extern crate serde;
extern crate tiny_keccak;
extern crate ring;
extern crate untrusted;
extern crate twox_hash;
extern crate byteorder;
extern crate blake2_rfc;
#[macro_use]
extern crate crunchy;
@@ -46,16 +50,20 @@ pub mod hash;
pub mod parachain;
pub mod uint;
pub mod validator;
pub mod ed25519;
pub mod hexdisplay;
pub mod hashing;
/// Alias to 160-bit hash when used in the context of an account address.
pub type Address = hash::H160;
/// Alias to 520-bit hash when used in the context of a signature.
pub type Signature = hash::H520;
pub type Signature = hash::H512;
pub use self::hash::{H160, H256};
pub use self::uint::{U256, U512};
pub use hashing::{blake2_256, twox_128, twox_256};
/// A hash function.
pub fn hash(data: &[u8]) -> hash::H256 {
tiny_keccak::keccak256(data).into()
blake2_256(data).into()
}
+1 -1
View File
@@ -118,7 +118,7 @@ mod tests {
block: BlockData(vec![1, 2, 3]),
}), r#"{
"parachainIndex": 5,
"collatorSignature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a",
"collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a",
"unprocessedIngress": [
[
1,