diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index f886c60be5..7d5f50ddc4 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -532,6 +532,7 @@ name = "native-runtime" version = "0.1.0" dependencies = [ "runtime-support 0.1.0", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/substrate/native-runtime/Cargo.toml b/substrate/native-runtime/Cargo.toml index c971a6d694..eb5eb82408 100644 --- a/substrate/native-runtime/Cargo.toml +++ b/substrate/native-runtime/Cargo.toml @@ -10,3 +10,4 @@ without-std = [] [dependencies] runtime-support = { path = "./support", version = "0.1" } +rustc-hex = "1.0" diff --git a/substrate/primitives/src/ed25519.rs b/substrate/primitives/src/ed25519.rs index f6a02a735b..2630f858d2 100644 --- a/substrate/primitives/src/ed25519.rs +++ b/substrate/primitives/src/ed25519.rs @@ -4,17 +4,6 @@ use untrusted; use ring::{rand, signature}; use rustc_hex::FromHex; -struct HexDisplay<'a>(&'a [u8]); - -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(()) - } -} - pub fn verify(sig: &[u8], message: &[u8], public: &[u8]) -> bool { let public_key = untrusted::Input::from(public); let msg = untrusted::Input::from(message); @@ -181,6 +170,41 @@ impl PartialEq for Signature { mod test { use super::*; +pub struct HexDisplay<'a>(&'a [u8]); + +impl<'a> HexDisplay<'a> { + 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(()) + } +} + +pub trait AsBytesRef { + fn as_bytes_ref(&self) -> &[u8]; +} + +impl AsBytesRef for [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]); + #[test] fn test_vector_should_work() { let pair: Pair = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".into(); @@ -205,8 +229,22 @@ mod test { fn seeded_pair_should_work() { let pair = Pair::from_seed(b"12345678901234567890123456789012"); let public = pair.public(); + println!("{}", HexDisplay::from(&public.0)); + 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[..]); + println!("pub: {}", HexDisplay::from(&public.0)); + println!("sig: {}", HexDisplay::from(&signature.0)); + assert!(signature.verify(&message[..], &public)); + } } diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs index 7653aaff9b..6a6201945d 100644 --- a/substrate/wasm-runtime/polkadot/src/lib.rs +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -4,13 +4,16 @@ #[macro_use] extern crate runtime_support; +#[cfg(test)] +extern crate rustc_hex; + mod codec; mod support; mod runtime; pub use codec::{endiansensitive, streamreader, joiner, slicable, keyedvec}; pub use support::{primitives, function, environment, storage}; #[cfg(test)] -pub use support::testing; +pub use support::{testing, statichex}; #[allow(unused_imports)] // TODO: remove in due course diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs index 2ddc83bdb2..fe0e835608 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -90,11 +90,14 @@ pub fn set_code(new: &[u8]) { mod tests { use joiner::Joiner; use function::Function; - use codec::keyedvec::KeyedVec; + use keyedvec::KeyedVec; + use slicable::Slicable; use std::collections::HashMap; use runtime_support::{NoError, with_externalities, Externalities}; - use primitives::{AccountID, UncheckedTransaction, Transaction}; + use primitives::{AccountID, UncheckedTransaction, Transaction, Hashable}; + use statichex::StaticHexInto; use runtime::{system, staking}; + use testing::HexDisplay; #[derive(Debug, Default)] struct TestExternalities { @@ -120,10 +123,13 @@ mod tests { ) } + fn one() -> AccountID { "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".convert() } + fn two() -> AccountID { "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".convert() } + #[test] fn staking_balance_transfer_dispatch_works() { - let one: AccountID = [1u8; 32]; - let two: AccountID = [2u8; 32]; + let one = one(); + let two = two(); let mut t = TestExternalities { storage: map![ one.to_keyed_vec(b"sta\0bal\0") => vec![111u8, 0, 0, 0, 0, 0, 0, 0] @@ -136,8 +142,12 @@ mod tests { function: Function::StakingTransferStake, input_data: vec![].join(&two).join(&69u64), }, - signature: [1u8; 64], + signature: "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a".convert(), }; + // tx: 2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000 + // sig: 679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a + + println!("tx is {}", HexDisplay::from(&tx.transaction.to_vec())); with_externalities(&mut t, || { system::execute_transaction(&tx); diff --git a/substrate/wasm-runtime/polkadot/src/support/mod.rs b/substrate/wasm-runtime/polkadot/src/support/mod.rs index aa14ad2f5d..732552effd 100644 --- a/substrate/wasm-runtime/polkadot/src/support/mod.rs +++ b/substrate/wasm-runtime/polkadot/src/support/mod.rs @@ -3,5 +3,7 @@ pub mod function; pub mod environment; pub mod storage; +#[cfg(test)] +pub mod statichex; #[cfg(test)] pub mod testing; diff --git a/substrate/wasm-runtime/polkadot/src/support/statichex.rs b/substrate/wasm-runtime/polkadot/src/support/statichex.rs new file mode 100644 index 0000000000..774cb82538 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/statichex.rs @@ -0,0 +1,29 @@ +use rustc_hex::FromHex; + +pub trait StaticHexConversion: Sized { + fn from_static_hex(hex: &'static str) -> Self; +} + +macro_rules! impl_sizes { + ( $( $t:expr ),* ) => { $( + impl StaticHexConversion for [u8; $t] { + fn from_static_hex(hex: &'static str) -> Self { + let mut r = [0u8; $t]; + r.copy_from_slice(&FromHex::from_hex(hex).unwrap()); + r + } + } + )* } +} + +impl_sizes!(1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128); + +pub trait StaticHexInto { + fn convert(self) -> T; +} + +impl StaticHexInto for &'static str { + fn convert(self) -> T { + T::from_static_hex(self) + } +} diff --git a/substrate/wasm-runtime/polkadot/src/support/testing.rs b/substrate/wasm-runtime/polkadot/src/support/testing.rs index ec7fac6d6d..5338add635 100644 --- a/substrate/wasm-runtime/polkadot/src/support/testing.rs +++ b/substrate/wasm-runtime/polkadot/src/support/testing.rs @@ -19,3 +19,46 @@ impl Externalities for TestExternalities { fn chain_id(&self) -> u64 { 42 } } + +pub struct HexDisplay<'a>(&'a [u8]); + +impl<'a> HexDisplay<'a> { + 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(()) + } +} + +pub trait AsBytesRef { + fn as_bytes_ref(&self) -> &[u8]; +} + +impl AsBytesRef for [u8] { + fn as_bytes_ref(&self) -> &[u8] { &self } +} + +impl<'a> AsBytesRef for &'a[u8] { + fn as_bytes_ref(&self) -> &[u8] { self } +} + +impl AsBytesRef for Vec { + 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]);