From 075ca7199abb4177b5f01f0a21fe6e79588c4347 Mon Sep 17 00:00:00 2001 From: 2581015450 <2581015450@qq.com> Date: Sun, 8 Oct 2023 10:42:52 +0800 Subject: [PATCH 01/16] feat: polkadot module --- anychain-polkadot/Cargo.toml | 2 ++ anychain-polkadot/src/address.rs | 37 ++++++++++++++++++++++++++++ anychain-polkadot/src/format.rs | 14 +++++++++++ anychain-polkadot/src/lib.rs | 10 ++++++++ anychain-polkadot/src/public_key.rs | 37 ++++++++++++++++++++++++++++ anychain-polkadot/src/transaction.rs | 0 6 files changed, 100 insertions(+) create mode 100644 anychain-polkadot/src/address.rs create mode 100644 anychain-polkadot/src/format.rs create mode 100644 anychain-polkadot/src/public_key.rs create mode 100644 anychain-polkadot/src/transaction.rs diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index 2b95767..3515542 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -5,3 +5,5 @@ edition = "2021" [dependencies] anychain-core = { path = "../anychain-core", version = "0.1.1" } +blake2b_simd = "1.0.2" +ed25519-dalek-fiat = "0.1.0" diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs new file mode 100644 index 0000000..3ab7248 --- /dev/null +++ b/anychain-polkadot/src/address.rs @@ -0,0 +1,37 @@ +use std::{str::FromStr, fmt::Display}; + +use anychain_core::{Address, TransactionError}; + +use crate::{PolkadotFormat, PolkadotPublicKey}; + + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct PolkadotAddress(String); + + +impl Address for PolkadotAddress { + type SecretKey = ed25519_dalek_fiat::SecretKey; + type PublicKey = PolkadotPublicKey; + type Format = PolkadotFormat; + + fn from_secret_key(secret_key: &Self::SecretKey, format: &Self::Format) -> Result { + todo!() + } + + fn from_public_key(public_key: &Self::PublicKey, format: &Self::Format) -> Result { + todo!() + } +} + +impl FromStr for PolkadotAddress { + type Err = TransactionError; + fn from_str(s: &str) -> Result { + todo!() + } +} + +impl Display for PolkadotAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} \ No newline at end of file diff --git a/anychain-polkadot/src/format.rs b/anychain-polkadot/src/format.rs new file mode 100644 index 0000000..1932158 --- /dev/null +++ b/anychain-polkadot/src/format.rs @@ -0,0 +1,14 @@ +use std::fmt::Display; +use anychain_core::Format; + + +#[derive(Hash, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)] +pub struct PolkadotFormat; + +impl Format for PolkadotFormat {} + +impl Display for PolkadotFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} \ No newline at end of file diff --git a/anychain-polkadot/src/lib.rs b/anychain-polkadot/src/lib.rs index 8b13789..39a45ef 100644 --- a/anychain-polkadot/src/lib.rs +++ b/anychain-polkadot/src/lib.rs @@ -1 +1,11 @@ +mod public_key; +pub use public_key::*; +mod address; +pub use address::*; + +mod format; +pub use format::*; + +mod transaction; +pub use transaction::*; diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs new file mode 100644 index 0000000..963ec44 --- /dev/null +++ b/anychain-polkadot/src/public_key.rs @@ -0,0 +1,37 @@ +use std::{str::FromStr, fmt::Display}; +use anychain_core::{PublicKey, TransactionError}; +use crate::{PolkadotAddress, PolkadotFormat}; + +#[derive(Debug, Clone)] +pub struct PolkadotPublicKey(ed25519_dalek_fiat::PublicKey); + +impl PublicKey for PolkadotPublicKey { + type SecretKey = ed25519_dalek_fiat::SecretKey; + type Address = PolkadotAddress; + type Format = PolkadotFormat; + + fn from_secret_key(secret_key: &Self::SecretKey) -> Self { + Self(ed25519_dalek_fiat::PublicKey::from(secret_key)) + } + + fn to_address(&self, format: &Self::Format) -> Result { + + todo!() + + + + } +} + +impl FromStr for PolkadotPublicKey { + type Err = TransactionError; + fn from_str(s: &str) -> Result { + todo!() + } +} + +impl Display for PolkadotPublicKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs new file mode 100644 index 0000000..e69de29 From ebc753fc4b9e8ef9aab496cc618a4cdd938e7e41 Mon Sep 17 00:00:00 2001 From: 2581015450 <2581015450@qq.com> Date: Mon, 9 Oct 2023 17:10:04 +0800 Subject: [PATCH 02/16] style: cargo fmt --- anychain-polkadot/src/address.rs | 20 ++++++++++++-------- anychain-polkadot/src/format.rs | 5 ++--- anychain-polkadot/src/public_key.rs | 15 +++++++-------- anychain-polkadot/src/transaction.rs | 1 + 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index 3ab7248..9508bec 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -1,24 +1,28 @@ -use std::{str::FromStr, fmt::Display}; +use std::{fmt::Display, str::FromStr}; use anychain_core::{Address, TransactionError}; use crate::{PolkadotFormat, PolkadotPublicKey}; - #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct PolkadotAddress(String); - impl Address for PolkadotAddress { type SecretKey = ed25519_dalek_fiat::SecretKey; type PublicKey = PolkadotPublicKey; type Format = PolkadotFormat; - - fn from_secret_key(secret_key: &Self::SecretKey, format: &Self::Format) -> Result { + + fn from_secret_key( + secret_key: &Self::SecretKey, + format: &Self::Format, + ) -> Result { todo!() } - fn from_public_key(public_key: &Self::PublicKey, format: &Self::Format) -> Result { + fn from_public_key( + public_key: &Self::PublicKey, + format: &Self::Format, + ) -> Result { todo!() } } @@ -32,6 +36,6 @@ impl FromStr for PolkadotAddress { impl Display for PolkadotAddress { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() + todo!() } -} \ No newline at end of file +} diff --git a/anychain-polkadot/src/format.rs b/anychain-polkadot/src/format.rs index 1932158..c39875f 100644 --- a/anychain-polkadot/src/format.rs +++ b/anychain-polkadot/src/format.rs @@ -1,6 +1,5 @@ -use std::fmt::Display; use anychain_core::Format; - +use std::fmt::Display; #[derive(Hash, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)] pub struct PolkadotFormat; @@ -11,4 +10,4 @@ impl Display for PolkadotFormat { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } -} \ No newline at end of file +} diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index 963ec44..43ef44e 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -1,6 +1,6 @@ -use std::{str::FromStr, fmt::Display}; -use anychain_core::{PublicKey, TransactionError}; use crate::{PolkadotAddress, PolkadotFormat}; +use anychain_core::{PublicKey, TransactionError}; +use std::{fmt::Display, str::FromStr}; #[derive(Debug, Clone)] pub struct PolkadotPublicKey(ed25519_dalek_fiat::PublicKey); @@ -9,17 +9,16 @@ impl PublicKey for PolkadotPublicKey { type SecretKey = ed25519_dalek_fiat::SecretKey; type Address = PolkadotAddress; type Format = PolkadotFormat; - + fn from_secret_key(secret_key: &Self::SecretKey) -> Self { Self(ed25519_dalek_fiat::PublicKey::from(secret_key)) } - fn to_address(&self, format: &Self::Format) -> Result { - + fn to_address( + &self, + format: &Self::Format, + ) -> Result { todo!() - - - } } diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index e69de29..8b13789 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -0,0 +1 @@ + From 5611d9590c208bd1bc4983e85f737919970ebf23 Mon Sep 17 00:00:00 2001 From: 2581015450 <2581015450@qq.com> Date: Tue, 10 Oct 2023 17:49:36 +0800 Subject: [PATCH 03/16] feat: polkadot construct --- anychain-polkadot/Cargo.toml | 4 +- anychain-polkadot/src/address.rs | 45 ++++++++++++++++------- anychain-polkadot/src/format.rs | 2 +- anychain-polkadot/src/lib.rs | 3 ++ anychain-polkadot/src/network/kusama.rs | 30 +++++++++++++++ anychain-polkadot/src/network/mod.rs | 8 ++++ anychain-polkadot/src/network/polkadot.rs | 30 +++++++++++++++ anychain-polkadot/src/public_key.rs | 40 +++++++++++++------- 8 files changed, 131 insertions(+), 31 deletions(-) create mode 100644 anychain-polkadot/src/network/kusama.rs create mode 100644 anychain-polkadot/src/network/mod.rs create mode 100644 anychain-polkadot/src/network/polkadot.rs diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index 3515542..ba90129 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" [dependencies] anychain-core = { path = "../anychain-core", version = "0.1.1" } -blake2b_simd = "1.0.2" -ed25519-dalek-fiat = "0.1.0" +sp-core = "24.0.0" +base58 = { workspace = true } \ No newline at end of file diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index 9508bec..1fcd37e 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -1,41 +1,58 @@ -use std::{fmt::Display, str::FromStr}; +use std::{fmt::Display, str::FromStr, marker::PhantomData}; -use anychain_core::{Address, TransactionError}; +use anychain_core::{Address, TransactionError, libsecp256k1, PublicKey}; -use crate::{PolkadotFormat, PolkadotPublicKey}; +use crate::{PolkadotFormat, PolkadotPublicKey, PolkadotNetwork}; +use sp_core::hashing::{blake2_256, blake2_512}; +use base58::ToBase58; #[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct PolkadotAddress(String); +pub struct PolkadotAddress { + addr: String, + _network: PhantomData, +} -impl Address for PolkadotAddress { - type SecretKey = ed25519_dalek_fiat::SecretKey; - type PublicKey = PolkadotPublicKey; +impl Address for PolkadotAddress { + type SecretKey = libsecp256k1::SecretKey; + type PublicKey = PolkadotPublicKey; type Format = PolkadotFormat; fn from_secret_key( secret_key: &Self::SecretKey, format: &Self::Format, ) -> Result { - todo!() + Self::PublicKey::from_secret_key(secret_key).to_address(format) } fn from_public_key( public_key: &Self::PublicKey, - format: &Self::Format, + _format: &Self::Format, ) -> Result { - todo!() + let pk_hash = blake2_256(&public_key.serialize()).to_vec(); + let network = N::version(); + let payload = [vec![network], pk_hash].concat(); + + let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; + + let checksum = blake2_512(&[ss_prefix, payload.clone()].concat()).to_vec(); + let addr = [payload, checksum[..2].to_vec()].concat().to_base58(); + + Ok(PolkadotAddress { + addr, + _network: PhantomData::, + }) } } -impl FromStr for PolkadotAddress { +impl FromStr for PolkadotAddress { type Err = TransactionError; - fn from_str(s: &str) -> Result { + fn from_str(_s: &str) -> Result { todo!() } } -impl Display for PolkadotAddress { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Display for PolkadotAddress { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } } diff --git a/anychain-polkadot/src/format.rs b/anychain-polkadot/src/format.rs index c39875f..de2efdf 100644 --- a/anychain-polkadot/src/format.rs +++ b/anychain-polkadot/src/format.rs @@ -7,7 +7,7 @@ pub struct PolkadotFormat; impl Format for PolkadotFormat {} impl Display for PolkadotFormat { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } } diff --git a/anychain-polkadot/src/lib.rs b/anychain-polkadot/src/lib.rs index 39a45ef..e2416c1 100644 --- a/anychain-polkadot/src/lib.rs +++ b/anychain-polkadot/src/lib.rs @@ -9,3 +9,6 @@ pub use format::*; mod transaction; pub use transaction::*; + +mod network; +pub use network::*; \ No newline at end of file diff --git a/anychain-polkadot/src/network/kusama.rs b/anychain-polkadot/src/network/kusama.rs new file mode 100644 index 0000000..74bb253 --- /dev/null +++ b/anychain-polkadot/src/network/kusama.rs @@ -0,0 +1,30 @@ +use std::{str::FromStr, fmt::Display}; + +use anychain_core::{Network, NetworkError}; +use crate::PolkadotNetwork; + +#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] +pub struct Kusama; + +impl Network for Kusama { + const NAME: &'static str = "kusama"; +} + +impl PolkadotNetwork for Kusama { + fn version() -> u8 { + 0x02 + } +} + +impl FromStr for Kusama { + type Err = NetworkError; + fn from_str(_s: &str) -> Result { + todo!() + } +} + +impl Display for Kusama { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} \ No newline at end of file diff --git a/anychain-polkadot/src/network/mod.rs b/anychain-polkadot/src/network/mod.rs new file mode 100644 index 0000000..38c2d1c --- /dev/null +++ b/anychain-polkadot/src/network/mod.rs @@ -0,0 +1,8 @@ +mod polkadot; +mod kusama; + +use anychain_core::Network; + +pub trait PolkadotNetwork: Network { + fn version() -> u8; +} diff --git a/anychain-polkadot/src/network/polkadot.rs b/anychain-polkadot/src/network/polkadot.rs new file mode 100644 index 0000000..9c188f8 --- /dev/null +++ b/anychain-polkadot/src/network/polkadot.rs @@ -0,0 +1,30 @@ +use std::{str::FromStr, fmt::Display}; + +use anychain_core::{Network, NetworkError}; +use crate::PolkadotNetwork; + +#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] +pub struct Polkadot; + +impl Network for Polkadot { + const NAME: &'static str = "polkadot"; +} + +impl PolkadotNetwork for Polkadot { + fn version() -> u8 { + 0x00 + } +} + +impl FromStr for Polkadot { + type Err = NetworkError; + fn from_str(_s: &str) -> Result { + todo!() + } +} + +impl Display for Polkadot { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} \ No newline at end of file diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index 43ef44e..a2a4bb0 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -1,36 +1,48 @@ -use crate::{PolkadotAddress, PolkadotFormat}; -use anychain_core::{PublicKey, TransactionError}; -use std::{fmt::Display, str::FromStr}; +use anychain_core::{PublicKey, PublicKeyError, libsecp256k1, Address}; +use crate::{PolkadotAddress, PolkadotFormat, PolkadotNetwork}; +use std::{fmt::Display, str::FromStr, marker::PhantomData}; #[derive(Debug, Clone)] -pub struct PolkadotPublicKey(ed25519_dalek_fiat::PublicKey); +pub struct PolkadotPublicKey { + key: libsecp256k1::PublicKey, + _network: PhantomData, +} -impl PublicKey for PolkadotPublicKey { - type SecretKey = ed25519_dalek_fiat::SecretKey; - type Address = PolkadotAddress; +impl PublicKey for PolkadotPublicKey { + type SecretKey = libsecp256k1::SecretKey; + type Address = PolkadotAddress; type Format = PolkadotFormat; fn from_secret_key(secret_key: &Self::SecretKey) -> Self { - Self(ed25519_dalek_fiat::PublicKey::from(secret_key)) + Self { + key: libsecp256k1::PublicKey::from_secret_key(&secret_key), + _network: PhantomData::, + } } fn to_address( &self, format: &Self::Format, ) -> Result { - todo!() + Ok(Self::Address::from_public_key(self, format)?) + } +} + +impl PolkadotPublicKey { + pub fn serialize(&self) -> Vec { + self.key.serialize_compressed().to_vec() } } -impl FromStr for PolkadotPublicKey { - type Err = TransactionError; - fn from_str(s: &str) -> Result { +impl FromStr for PolkadotPublicKey { + type Err = PublicKeyError; + fn from_str(_s: &str) -> Result { todo!() } } -impl Display for PolkadotPublicKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Display for PolkadotPublicKey { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } } From 00d2636a37509fd71402731846d3f7ff9426a4c4 Mon Sep 17 00:00:00 2001 From: 2581015450 <2581015450@qq.com> Date: Wed, 11 Oct 2023 14:29:04 +0800 Subject: [PATCH 04/16] feat: polkadot transaction --- anychain-polkadot/src/address.rs | 40 ++++++++++++++++++++++++---- anychain-polkadot/src/format.rs | 4 ++- anychain-polkadot/src/network/mod.rs | 3 +++ anychain-polkadot/src/transaction.rs | 14 ++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index 1fcd37e..5681478 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, str::FromStr, marker::PhantomData}; -use anychain_core::{Address, TransactionError, libsecp256k1, PublicKey}; +use anychain_core::{Address, TransactionError, libsecp256k1, PublicKey, hex}; use crate::{PolkadotFormat, PolkadotPublicKey, PolkadotNetwork}; use sp_core::hashing::{blake2_256, blake2_512}; @@ -29,8 +29,26 @@ impl Address for PolkadotAddress { _format: &Self::Format, ) -> Result { let pk_hash = blake2_256(&public_key.serialize()).to_vec(); - let network = N::version(); - let payload = [vec![network], pk_hash].concat(); + println!("pk hash = {}", hex::encode(&pk_hash)); + + let payload = [vec![N::version()], pk_hash].concat(); + + let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; + + let checksum = blake2_512(&[ss_prefix, payload.clone()].concat()).to_vec(); + let addr = [payload, checksum[..2].to_vec()].concat().to_base58(); + + Ok(PolkadotAddress { + addr, + _network: PhantomData::, + }) + } +} + +impl PolkadotAddress { + fn from_pk_hash(pk_hash: &str) -> Result { + let pk_hash = hex::decode(pk_hash).unwrap(); + let payload = [vec![N::version()], pk_hash].concat(); let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; @@ -52,7 +70,19 @@ impl FromStr for PolkadotAddress { } impl Display for PolkadotAddress { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.addr) } } + +#[cfg(test)] +mod tests { + use crate::{PolkadotAddress, Polkadot}; + + #[test] + fn test() { + let pkhash = "ead52b489146143b3a78957668eebb973ea745888f3cfa1706f693bed17c3b1f"; + let addr = PolkadotAddress::::from_pk_hash(pkhash).unwrap(); + println!("address = {}", addr); + } +} \ No newline at end of file diff --git a/anychain-polkadot/src/format.rs b/anychain-polkadot/src/format.rs index de2efdf..2705650 100644 --- a/anychain-polkadot/src/format.rs +++ b/anychain-polkadot/src/format.rs @@ -2,7 +2,9 @@ use anychain_core::Format; use std::fmt::Display; #[derive(Hash, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)] -pub struct PolkadotFormat; +pub enum PolkadotFormat { + Standard, +} impl Format for PolkadotFormat {} diff --git a/anychain-polkadot/src/network/mod.rs b/anychain-polkadot/src/network/mod.rs index 38c2d1c..c3fe0ef 100644 --- a/anychain-polkadot/src/network/mod.rs +++ b/anychain-polkadot/src/network/mod.rs @@ -1,5 +1,8 @@ mod polkadot; +pub use polkadot::*; + mod kusama; +pub use kusama::*; use anychain_core::Network; diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index 8b13789..be5398b 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -1 +1,15 @@ +use crate::{PolkadotAddress, PolkadotNetwork}; + +pub struct PolkadotTransactionParameters { + from: PolkadotAddress, + to: PolkadotAddress, + + + +} + +pub struct PolkadotTransaction { + pub params: PolkadotTransactionParameters, + pub signature: Vec +} From 116b7ef0b9b773a32977d7591e783731e2861585 Mon Sep 17 00:00:00 2001 From: 2581015450 <2581015450@qq.com> Date: Wed, 8 Nov 2023 11:36:54 +0800 Subject: [PATCH 05/16] feat: add crate polkadot-scale-codec --- anychain-polkadot/Cargo.toml | 3 ++- anychain-polkadot/src/transaction.rs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index ba90129..fd9683f 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" [dependencies] anychain-core = { path = "../anychain-core", version = "0.1.1" } sp-core = "24.0.0" -base58 = { workspace = true } \ No newline at end of file +base58 = { workspace = true } +parity-scale-codec = "3.6.5" \ No newline at end of file diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index be5398b..25aed43 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -1,7 +1,13 @@ use crate::{PolkadotAddress, PolkadotNetwork}; +use parity_scale_codec::Encode; pub struct PolkadotTransactionParameters { + extrinsic_version: u8, + spec_version: u32, + tx_version: u32, + genesis_hash: Vec, + block_hash: Vec, from: PolkadotAddress, to: PolkadotAddress, From 3b2b2c458c941c48656903deab9a722141a392e8 Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Tue, 28 Nov 2023 17:31:26 +0800 Subject: [PATCH 06/16] feat: polkadot transaction to_bytes() --- anychain-polkadot/Cargo.toml | 3 +- anychain-polkadot/src/address.rs | 55 +++++++----- anychain-polkadot/src/public_key.rs | 4 +- anychain-polkadot/src/transaction.rs | 121 +++++++++++++++++++++++++-- 4 files changed, 149 insertions(+), 34 deletions(-) diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index fd9683f..18327c2 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" anychain-core = { path = "../anychain-core", version = "0.1.1" } sp-core = "24.0.0" base58 = { workspace = true } -parity-scale-codec = "3.6.5" \ No newline at end of file +parity-scale-codec = "3.6.5" +ed25519-dalek-fiat = "0.1.0" \ No newline at end of file diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index 5681478..addaa04 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -1,10 +1,10 @@ use std::{fmt::Display, str::FromStr, marker::PhantomData}; -use anychain_core::{Address, TransactionError, libsecp256k1, PublicKey, hex}; +use anychain_core::{Address, AddressError, TransactionError, PublicKey, hex, libsecp256k1}; use crate::{PolkadotFormat, PolkadotPublicKey, PolkadotNetwork}; use sp_core::hashing::{blake2_256, blake2_512}; -use base58::ToBase58; +use base58::{ToBase58, FromBase58}; #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct PolkadotAddress { @@ -29,24 +29,12 @@ impl Address for PolkadotAddress { _format: &Self::Format, ) -> Result { let pk_hash = blake2_256(&public_key.serialize()).to_vec(); - println!("pk hash = {}", hex::encode(&pk_hash)); - - let payload = [vec![N::version()], pk_hash].concat(); - - let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; - - let checksum = blake2_512(&[ss_prefix, payload.clone()].concat()).to_vec(); - let addr = [payload, checksum[..2].to_vec()].concat().to_base58(); - - Ok(PolkadotAddress { - addr, - _network: PhantomData::, - }) + Self::from_pk_hash(&hex::encode(&pk_hash)) } } impl PolkadotAddress { - fn from_pk_hash(pk_hash: &str) -> Result { + pub fn from_pk_hash(pk_hash: &str) -> Result { let pk_hash = hex::decode(pk_hash).unwrap(); let payload = [vec![N::version()], pk_hash].concat(); @@ -60,6 +48,11 @@ impl PolkadotAddress { _network: PhantomData::, }) } + + pub fn to_pk_hash(&self) -> Result, AddressError> { + let bin = self.addr.as_str().from_base58()?; + Ok(bin[1..33].to_vec()) + } } impl FromStr for PolkadotAddress { @@ -77,12 +70,30 @@ impl Display for PolkadotAddress { #[cfg(test)] mod tests { - use crate::{PolkadotAddress, Polkadot}; + use anychain_core::Address; + use super::libsecp256k1::SecretKey; + use crate::{PolkadotAddress, Polkadot, PolkadotFormat}; #[test] - fn test() { - let pkhash = "ead52b489146143b3a78957668eebb973ea745888f3cfa1706f693bed17c3b1f"; - let addr = PolkadotAddress::::from_pk_hash(pkhash).unwrap(); - println!("address = {}", addr); + fn test_address() { + let sk = [ + 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + ]; + let sk = SecretKey::parse_slice(&sk).unwrap(); + + let address = PolkadotAddress::::from_secret_key( + &sk, + &PolkadotFormat::Standard + ).unwrap(); + + println!("address = {}", address); } -} \ No newline at end of file + + #[test] + fn test_address_2() { + let hash = "0c2f3c6dabb4a0600eccae87aeaa39242042f9a576aa8dca01e1b419cf17d7a2"; + let address = PolkadotAddress::::from_pk_hash(hash).unwrap(); + println!("address = {}", address); + } +} diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index a2a4bb0..f14b830 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -1,4 +1,4 @@ -use anychain_core::{PublicKey, PublicKeyError, libsecp256k1, Address}; +use anychain_core::{PublicKey, PublicKeyError, Address, libsecp256k1}; use crate::{PolkadotAddress, PolkadotFormat, PolkadotNetwork}; use std::{fmt::Display, str::FromStr, marker::PhantomData}; @@ -15,7 +15,7 @@ impl PublicKey for PolkadotPublicKey { fn from_secret_key(secret_key: &Self::SecretKey) -> Self { Self { - key: libsecp256k1::PublicKey::from_secret_key(&secret_key), + key: libsecp256k1::PublicKey::from_secret_key(secret_key), _network: PhantomData::, } } diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index 25aed43..f35daa0 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -1,21 +1,124 @@ -use crate::{PolkadotAddress, PolkadotNetwork}; +use std::fmt::Display; +use anychain_core::{Transaction, TransactionError, TransactionId, hex}; +use crate::{PolkadotAddress, PolkadotNetwork, PolkadotFormat, PolkadotPublicKey}; use parity_scale_codec::Encode; +#[derive(Clone)] pub struct PolkadotTransactionParameters { - extrinsic_version: u8, - spec_version: u32, - tx_version: u32, - genesis_hash: Vec, - block_hash: Vec, + version: String, from: PolkadotAddress, to: PolkadotAddress, - - - + amount: u64, + nonce: u64, + tip: u64, + block_height: u64, + block_hash: String, + genesis_hash: String, + spec_version: u32, + tx_version: u32, + era_height: u64, } +#[derive(Clone)] pub struct PolkadotTransaction { pub params: PolkadotTransactionParameters, pub signature: Vec } + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct PolkadotTransactionId { + txid: Vec, +} + +impl TransactionId for PolkadotTransactionId {} + +impl Display for PolkadotTransactionId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "0x{}", hex::encode(&self.txid)) + } +} + +fn get_era(block_height: u64, era_height: u64) -> Vec { + + todo!() +} + +fn encode(val: u64) -> Vec { + if val == 0 { + vec![0] + } else { + val.encode() + } +} + +impl Transaction for PolkadotTransaction { + type Address = PolkadotAddress; + type Format = PolkadotFormat; + type PublicKey = PolkadotPublicKey; + type TransactionId = PolkadotTransactionId; + type TransactionParameters = PolkadotTransactionParameters; + + fn new(params: &Self::TransactionParameters) -> Result { + + todo!() + } + + fn sign(&mut self, sig: Vec, recid: u8) -> Result, TransactionError> { + + todo!() + } + + fn from_bytes(tx: &[u8]) -> Result { + + todo!() + } + + fn to_bytes(&self) -> Result, TransactionError> { + let params = &self.params; + + let to = params.to.to_pk_hash()?; + let amount = encode(params.amount); + let era = get_era(params.block_height, params.era_height); + + let nonce = encode(params.nonce); + let tip = encode(params.nonce); + + let spec_version = params.spec_version.to_le_bytes().to_vec(); + let tx_version = params.tx_version.to_le_bytes().to_vec(); + + let genesis_hash = hex::decode(¶ms.genesis_hash)?; + let block_hash = hex::decode(¶ms.block_hash)?; + + Ok([ + vec![0], + to, + amount, + era, + nonce, + tip, + spec_version, + tx_version, + genesis_hash, + block_hash, + ].concat()) + } + + fn to_transaction_id(&self) -> Result { + todo!() + } +} + +#[cfg(test)] +mod tests { + use anychain_core::hex; + use parity_scale_codec::{Encode}; + + #[test] + fn test() { + let s = 1073741u64; + let s = s.encode(); + let s = hex::encode(&s); + println!("s = {}", s); + } +} \ No newline at end of file From 151f57fed312417a9b49a96a3997ccebb2892baa Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Wed, 29 Nov 2023 11:20:59 +0800 Subject: [PATCH 07/16] feat: polkadot transaction sign() --- anychain-polkadot/src/transaction.rs | 147 ++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 26 deletions(-) diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index f35daa0..13630f4 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -1,5 +1,7 @@ use std::fmt::Display; -use anychain_core::{Transaction, TransactionError, TransactionId, hex}; +use anychain_core::{ + Transaction, TransactionError, TransactionId, hex, + crypto::{blake2b_256, sha256, keccak256, sha512}}; use crate::{PolkadotAddress, PolkadotNetwork, PolkadotFormat, PolkadotPublicKey}; use parity_scale_codec::Encode; @@ -20,10 +22,21 @@ pub struct PolkadotTransactionParameters { era_height: u64, } +pub struct Interim { + method: Vec, + era: Vec, + nonce: Vec, + tip: Vec, + spec_version: Vec, + genesis_hash: Vec, + block_hash: Vec, + tx_version: Vec, +} + #[derive(Clone)] pub struct PolkadotTransaction { pub params: PolkadotTransactionParameters, - pub signature: Vec + pub signature: Option>, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -39,9 +52,27 @@ impl Display for PolkadotTransactionId { } } -fn get_era(block_height: u64, era_height: u64) -> Vec { - - todo!() +fn get_era(block_height: u64, mut era_height: u64) -> Vec { + if era_height == 0 { + era_height = 64 + } + let phase = block_height % era_height; + let index = 6u64; + let trailing_zero = index - 1; + + let mut encoded = if trailing_zero > 15 { + 15 + } else if trailing_zero < 1 { + 1 + } else { + trailing_zero + }; + + encoded += phase / 1 << 4; + let first = (encoded >> 8) as u8; + let second = (encoded & 0xff) as u8; + + vec![second, first] } fn encode(val: u64) -> Vec { @@ -60,40 +91,88 @@ impl Transaction for PolkadotTransaction { type TransactionParameters = PolkadotTransactionParameters; fn new(params: &Self::TransactionParameters) -> Result { - - todo!() + Ok(PolkadotTransaction { params: params.clone(), signature: None }) } - fn sign(&mut self, sig: Vec, recid: u8) -> Result, TransactionError> { - - todo!() + fn sign(&mut self, rs: Vec, _recid: u8) -> Result, TransactionError> { + if rs.len() != 64 { + return Err(TransactionError::Message(format!( + "Invalid signature length {}", + rs.len(), + ))); + } + self.signature = Some(rs); + self.to_bytes() } - fn from_bytes(tx: &[u8]) -> Result { - + fn from_bytes(_tx: &[u8]) -> Result { todo!() } fn to_bytes(&self) -> Result, TransactionError> { - let params = &self.params; + match &self.signature { + Some(sig) => { + let interim = self.to_interim()?; + let version = hex::decode(&self.params.version)?; + let from = self.params.from.to_pk_hash()?; + + let stream = [ + version, + vec![0], + from, + vec![2], // secp256k1 signature scheme = 2 + sig.clone(), + interim.era, + interim.nonce, + interim.tip, + interim.method, + ].concat(); + + let len = stream.len() as u64; + let len = encode(len); + + Ok([len, stream].concat()) + } + None => { + let interim = self.to_interim()?; + Ok([ + interim.method, + interim.era, + interim.nonce, + interim.tip, + interim.spec_version, + interim.tx_version, + interim.genesis_hash, + interim.block_hash, + ].concat()) + } + } + } + + fn to_transaction_id(&self) -> Result { + Ok(PolkadotTransactionId { txid: self.digest(1)? }) + } +} +impl PolkadotTransaction { + pub fn to_interim(&self) -> Result { + let params = &self.params; + let to = params.to.to_pk_hash()?; let amount = encode(params.amount); let era = get_era(params.block_height, params.era_height); let nonce = encode(params.nonce); - let tip = encode(params.nonce); + let tip = encode(params.tip); let spec_version = params.spec_version.to_le_bytes().to_vec(); let tx_version = params.tx_version.to_le_bytes().to_vec(); let genesis_hash = hex::decode(¶ms.genesis_hash)?; let block_hash = hex::decode(¶ms.block_hash)?; - - Ok([ - vec![0], - to, - amount, + + let interim = Interim { + method: [vec![0], to, amount].concat(), era, nonce, tip, @@ -101,24 +180,40 @@ impl Transaction for PolkadotTransaction { tx_version, genesis_hash, block_hash, - ].concat()) - } + }; - fn to_transaction_id(&self) -> Result { - todo!() + Ok(interim) + } + + pub fn digest(&self, index: u8) -> Result, TransactionError> { + match index { + 0 => Ok(blake2b_256(&self.to_bytes()?).to_vec()), + 1 => Ok(sha256(&self.to_bytes()?).to_vec()), + 2 => Ok(keccak256(&self.to_bytes()?).to_vec()), + 3 => Ok(sha512(&self.to_bytes()?)[..32].to_vec()), + _ => Err(TransactionError::Message("invalid digest code".to_string())), + } } } #[cfg(test)] mod tests { use anychain_core::hex; - use parity_scale_codec::{Encode}; + use parity_scale_codec::Encode; #[test] - fn test() { + fn test_encode() { let s = 1073741u64; let s = s.encode(); let s = hex::encode(&s); println!("s = {}", s); } -} \ No newline at end of file + + #[test] + fn test_tx() { + + + + + } +} From d4933f9a3eace771baa4c3e09e367289ad7854dc Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Wed, 29 Nov 2023 11:21:48 +0800 Subject: [PATCH 08/16] type: cargo fmt --- anychain-polkadot/src/address.rs | 24 ++++----- anychain-polkadot/src/lib.rs | 2 +- anychain-polkadot/src/network/kusama.rs | 6 +-- anychain-polkadot/src/network/polkadot.rs | 6 +-- anychain-polkadot/src/public_key.rs | 4 +- anychain-polkadot/src/transaction.rs | 64 ++++++++++++----------- 6 files changed, 53 insertions(+), 53 deletions(-) diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index addaa04..2cfea90 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -1,10 +1,10 @@ -use std::{fmt::Display, str::FromStr, marker::PhantomData}; +use std::{fmt::Display, marker::PhantomData, str::FromStr}; -use anychain_core::{Address, AddressError, TransactionError, PublicKey, hex, libsecp256k1}; +use anychain_core::{hex, libsecp256k1, Address, AddressError, PublicKey, TransactionError}; -use crate::{PolkadotFormat, PolkadotPublicKey, PolkadotNetwork}; +use crate::{PolkadotFormat, PolkadotNetwork, PolkadotPublicKey}; +use base58::{FromBase58, ToBase58}; use sp_core::hashing::{blake2_256, blake2_512}; -use base58::{ToBase58, FromBase58}; #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct PolkadotAddress { @@ -70,23 +70,21 @@ impl Display for PolkadotAddress { #[cfg(test)] mod tests { - use anychain_core::Address; use super::libsecp256k1::SecretKey; - use crate::{PolkadotAddress, Polkadot, PolkadotFormat}; + use crate::{Polkadot, PolkadotAddress, PolkadotFormat}; + use anychain_core::Address; #[test] fn test_address() { let sk = [ - 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, ]; let sk = SecretKey::parse_slice(&sk).unwrap(); - let address = PolkadotAddress::::from_secret_key( - &sk, - &PolkadotFormat::Standard - ).unwrap(); - + let address = + PolkadotAddress::::from_secret_key(&sk, &PolkadotFormat::Standard).unwrap(); + println!("address = {}", address); } diff --git a/anychain-polkadot/src/lib.rs b/anychain-polkadot/src/lib.rs index e2416c1..fdc803d 100644 --- a/anychain-polkadot/src/lib.rs +++ b/anychain-polkadot/src/lib.rs @@ -11,4 +11,4 @@ mod transaction; pub use transaction::*; mod network; -pub use network::*; \ No newline at end of file +pub use network::*; diff --git a/anychain-polkadot/src/network/kusama.rs b/anychain-polkadot/src/network/kusama.rs index 74bb253..65c5cfe 100644 --- a/anychain-polkadot/src/network/kusama.rs +++ b/anychain-polkadot/src/network/kusama.rs @@ -1,7 +1,7 @@ -use std::{str::FromStr, fmt::Display}; +use std::{fmt::Display, str::FromStr}; -use anychain_core::{Network, NetworkError}; use crate::PolkadotNetwork; +use anychain_core::{Network, NetworkError}; #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] pub struct Kusama; @@ -27,4 +27,4 @@ impl Display for Kusama { fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } -} \ No newline at end of file +} diff --git a/anychain-polkadot/src/network/polkadot.rs b/anychain-polkadot/src/network/polkadot.rs index 9c188f8..a3e6916 100644 --- a/anychain-polkadot/src/network/polkadot.rs +++ b/anychain-polkadot/src/network/polkadot.rs @@ -1,7 +1,7 @@ -use std::{str::FromStr, fmt::Display}; +use std::{fmt::Display, str::FromStr}; -use anychain_core::{Network, NetworkError}; use crate::PolkadotNetwork; +use anychain_core::{Network, NetworkError}; #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] pub struct Polkadot; @@ -27,4 +27,4 @@ impl Display for Polkadot { fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } -} \ No newline at end of file +} diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index f14b830..0f9ae28 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -1,6 +1,6 @@ -use anychain_core::{PublicKey, PublicKeyError, Address, libsecp256k1}; use crate::{PolkadotAddress, PolkadotFormat, PolkadotNetwork}; -use std::{fmt::Display, str::FromStr, marker::PhantomData}; +use anychain_core::{libsecp256k1, Address, PublicKey, PublicKeyError}; +use std::{fmt::Display, marker::PhantomData, str::FromStr}; #[derive(Debug, Clone)] pub struct PolkadotPublicKey { diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index 13630f4..b36f8f5 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -1,10 +1,10 @@ -use std::fmt::Display; +use crate::{PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotPublicKey}; use anychain_core::{ - Transaction, TransactionError, TransactionId, hex, - crypto::{blake2b_256, sha256, keccak256, sha512}}; -use crate::{PolkadotAddress, PolkadotNetwork, PolkadotFormat, PolkadotPublicKey}; + crypto::{blake2b_256, keccak256, sha256, sha512}, + hex, Transaction, TransactionError, TransactionId, +}; use parity_scale_codec::Encode; - +use std::fmt::Display; #[derive(Clone)] pub struct PolkadotTransactionParameters { @@ -54,11 +54,11 @@ impl Display for PolkadotTransactionId { fn get_era(block_height: u64, mut era_height: u64) -> Vec { if era_height == 0 { - era_height = 64 - } - let phase = block_height % era_height; - let index = 6u64; - let trailing_zero = index - 1; + era_height = 64 + } + let phase = block_height % era_height; + let index = 6u64; + let trailing_zero = index - 1; let mut encoded = if trailing_zero > 15 { 15 @@ -67,10 +67,10 @@ fn get_era(block_height: u64, mut era_height: u64) -> Vec { } else { trailing_zero }; - - encoded += phase / 1 << 4; - let first = (encoded >> 8) as u8; - let second = (encoded & 0xff) as u8; + + encoded += phase / 1 << 4; + let first = (encoded >> 8) as u8; + let second = (encoded & 0xff) as u8; vec![second, first] } @@ -91,7 +91,10 @@ impl Transaction for PolkadotTransaction { type TransactionParameters = PolkadotTransactionParameters; fn new(params: &Self::TransactionParameters) -> Result { - Ok(PolkadotTransaction { params: params.clone(), signature: None }) + Ok(PolkadotTransaction { + params: params.clone(), + signature: None, + }) } fn sign(&mut self, rs: Vec, _recid: u8) -> Result, TransactionError> { @@ -115,7 +118,7 @@ impl Transaction for PolkadotTransaction { let interim = self.to_interim()?; let version = hex::decode(&self.params.version)?; let from = self.params.from.to_pk_hash()?; - + let stream = [ version, vec![0], @@ -126,11 +129,12 @@ impl Transaction for PolkadotTransaction { interim.nonce, interim.tip, interim.method, - ].concat(); - + ] + .concat(); + let len = stream.len() as u64; let len = encode(len); - + Ok([len, stream].concat()) } None => { @@ -144,24 +148,27 @@ impl Transaction for PolkadotTransaction { interim.tx_version, interim.genesis_hash, interim.block_hash, - ].concat()) + ] + .concat()) } } } fn to_transaction_id(&self) -> Result { - Ok(PolkadotTransactionId { txid: self.digest(1)? }) + Ok(PolkadotTransactionId { + txid: self.digest(1)?, + }) } } impl PolkadotTransaction { pub fn to_interim(&self) -> Result { let params = &self.params; - + let to = params.to.to_pk_hash()?; let amount = encode(params.amount); let era = get_era(params.block_height, params.era_height); - + let nonce = encode(params.nonce); let tip = encode(params.tip); @@ -170,7 +177,7 @@ impl PolkadotTransaction { let genesis_hash = hex::decode(¶ms.genesis_hash)?; let block_hash = hex::decode(¶ms.block_hash)?; - + let interim = Interim { method: [vec![0], to, amount].concat(), era, @@ -184,7 +191,7 @@ impl PolkadotTransaction { Ok(interim) } - + pub fn digest(&self, index: u8) -> Result, TransactionError> { match index { 0 => Ok(blake2b_256(&self.to_bytes()?).to_vec()), @@ -210,10 +217,5 @@ mod tests { } #[test] - fn test_tx() { - - - - - } + fn test_tx() {} } From e80b1d09404855d06b5d4cb8d463ba12d893b9cc Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Thu, 30 Nov 2023 11:10:47 +0800 Subject: [PATCH 09/16] feat: SCALE compact encoding --- anychain-polkadot/Cargo.toml | 2 +- anychain-polkadot/src/transaction.rs | 56 ++++++++++++++-------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index 18327c2..bdde7b5 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -7,5 +7,5 @@ edition = "2021" anychain-core = { path = "../anychain-core", version = "0.1.1" } sp-core = "24.0.0" base58 = { workspace = true } -parity-scale-codec = "3.6.5" +parity-scale-codec = { version = "3.6.5", feature = "derive" } ed25519-dalek-fiat = "0.1.0" \ No newline at end of file diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index b36f8f5..5686b59 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -3,26 +3,27 @@ use anychain_core::{ crypto::{blake2b_256, keccak256, sha256, sha512}, hex, Transaction, TransactionError, TransactionId, }; -use parity_scale_codec::Encode; +use parity_scale_codec::{Encode, Decode, HasCompact}; use std::fmt::Display; #[derive(Clone)] pub struct PolkadotTransactionParameters { - version: String, - from: PolkadotAddress, - to: PolkadotAddress, - amount: u64, - nonce: u64, - tip: u64, - block_height: u64, - block_hash: String, - genesis_hash: String, - spec_version: u32, - tx_version: u32, - era_height: u64, + pub module_method: String, + pub version: String, + pub from: PolkadotAddress, + pub to: PolkadotAddress, + pub amount: u64, + pub nonce: u64, + pub tip: u64, + pub block_height: u64, + pub block_hash: String, + pub genesis_hash: String, + pub spec_version: u32, + pub tx_version: u32, + pub era_height: u64, } -pub struct Interim { +struct TxInterim { method: Vec, era: Vec, nonce: Vec, @@ -52,6 +53,12 @@ impl Display for PolkadotTransactionId { } } +#[derive(Debug, PartialEq, Encode, Decode)] +struct CompactWrapper { + #[codec(encoded_as = "::Type")] + val: T, +} + fn get_era(block_height: u64, mut era_height: u64) -> Vec { if era_height == 0 { era_height = 64 @@ -79,7 +86,7 @@ fn encode(val: u64) -> Vec { if val == 0 { vec![0] } else { - val.encode() + CompactWrapper { val }.encode() } } @@ -162,9 +169,10 @@ impl Transaction for PolkadotTransaction { } impl PolkadotTransaction { - pub fn to_interim(&self) -> Result { + fn to_interim(&self) -> Result { let params = &self.params; + let method = hex::decode(¶ms.module_method)?; let to = params.to.to_pk_hash()?; let amount = encode(params.amount); let era = get_era(params.block_height, params.era_height); @@ -178,8 +186,8 @@ impl PolkadotTransaction { let genesis_hash = hex::decode(¶ms.genesis_hash)?; let block_hash = hex::decode(¶ms.block_hash)?; - let interim = Interim { - method: [vec![0], to, amount].concat(), + let interim = TxInterim { + method: [method, vec![0], to, amount].concat(), era, nonce, tip, @@ -205,17 +213,9 @@ impl PolkadotTransaction { #[cfg(test)] mod tests { - use anychain_core::hex; - use parity_scale_codec::Encode; #[test] - fn test_encode() { - let s = 1073741u64; - let s = s.encode(); - let s = hex::encode(&s); - println!("s = {}", s); - } + fn test_tx_gen() { - #[test] - fn test_tx() {} + } } From 4aa17265526c2870f8abdec3c6ebe05c586e202c Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Thu, 30 Nov 2023 11:40:25 +0800 Subject: [PATCH 10/16] type: cargo fmt --- anychain-polkadot/src/transaction.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index 5686b59..f9245da 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -3,7 +3,7 @@ use anychain_core::{ crypto::{blake2b_256, keccak256, sha256, sha512}, hex, Transaction, TransactionError, TransactionId, }; -use parity_scale_codec::{Encode, Decode, HasCompact}; +use parity_scale_codec::{Decode, Encode, HasCompact}; use std::fmt::Display; #[derive(Clone)] @@ -215,7 +215,5 @@ impl PolkadotTransaction { mod tests { #[test] - fn test_tx_gen() { - - } + fn test_tx_gen() {} } From 90272d55b42122e2493e773605f97dc91c32cfd7 Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Thu, 30 Nov 2023 16:29:45 +0800 Subject: [PATCH 11/16] feat: polkadot test modules --- anychain-polkadot/Cargo.toml | 3 +- anychain-polkadot/src/address.rs | 25 ++++++- anychain-polkadot/src/transaction.rs | 99 +++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 4 deletions(-) diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index bdde7b5..08911ae 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -8,4 +8,5 @@ anychain-core = { path = "../anychain-core", version = "0.1.1" } sp-core = "24.0.0" base58 = { workspace = true } parity-scale-codec = { version = "3.6.5", feature = "derive" } -ed25519-dalek-fiat = "0.1.0" \ No newline at end of file +ed25519-dalek-fiat = "0.1.0" +serde_json = { workspace = true } \ No newline at end of file diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index 2cfea90..be96dbb 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -57,8 +57,29 @@ impl PolkadotAddress { impl FromStr for PolkadotAddress { type Err = TransactionError; - fn from_str(_s: &str) -> Result { - todo!() + fn from_str(s: &str) -> Result { + let bytes = s.from_base58()?; + if N::version() != bytes[0] { + return Err(TransactionError::Message(format!( + "Invalid version byte {} for polkadot network {}", + bytes[0], + N::NAME, + ))); + } + let checksum_provided = bytes[33..].to_vec(); + let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; + let checksum_expected = + blake2_512(&[ss_prefix, bytes[..33].to_vec()].concat())[..2].to_vec(); + if checksum_expected != checksum_provided { + return Err(TransactionError::Message(format!( + "Invalid {} address", + N::NAME + ))); + } + Ok(PolkadotAddress { + addr: s.to_string(), + _network: PhantomData, + }) } } diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index f9245da..a1eea53 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -211,9 +211,106 @@ impl PolkadotTransaction { } } +impl Display for PolkadotTransaction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(self.to_bytes().unwrap())) + } +} + #[cfg(test)] mod tests { + use crate::{ + transaction, Kusama, Polkadot, PolkadotAddress, PolkadotFormat, PolkadotNetwork, + PolkadotTransaction, PolkadotTransactionParameters, + }; + use anychain_core::Address; + use anychain_core::{hex, libsecp256k1, Transaction}; + use serde_json::Value; + use std::str::FromStr; + + fn tx_from_str(json: &str) -> PolkadotTransaction { + let json = serde_json::from_str::(json).unwrap(); + + let module_method = json["module_method"].as_str().unwrap().to_string(); + + let version = json["version"].as_str().unwrap().to_string(); + + let from = PolkadotAddress::::from_str(json["from"].as_str().unwrap()).unwrap(); + + let to = PolkadotAddress::::from_str(json["to"].as_str().unwrap()).unwrap(); + + let amount = json["amount"].as_u64().unwrap(); + let nonce = json["nonce"].as_u64().unwrap(); + let tip = json["tip"].as_u64().unwrap(); + let block_height = json["block_height"].as_u64().unwrap(); + let block_hash = json["block_hash"].as_str().unwrap().to_string(); + let genesis_hash = json["genesis_hash"].as_str().unwrap().to_string(); + let spec_version = json["spec_version"].as_u64().unwrap() as u32; + let tx_version = json["tx_version"].as_u64().unwrap() as u32; + let era_height = json["era_height"].as_u64().unwrap(); + + let params = PolkadotTransactionParameters:: { + module_method, + version, + from, + to, + amount, + nonce, + tip, + block_height, + block_hash, + genesis_hash, + spec_version, + tx_version, + era_height, + }; + + PolkadotTransaction::::new(¶ms).unwrap() + } + + #[test] + fn test_address_gen() { + let format = &PolkadotFormat::Standard; + + let sk_from = [ + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1u8, + ]; + + let sk_to = [ + 3, 1, 2, 5, 8, 1, 118, 203, 0, 1, 2, 1, 1, 2, 1, 1, 1, 103, 0, 0, 2, 2, 2, 2, 2, 2, 3, + 5, 8, 13, 17, 29, + ]; + + let sk_from = libsecp256k1::SecretKey::parse_slice(&sk_from).unwrap(); + let sk_to = libsecp256k1::SecretKey::parse_slice(&sk_to).unwrap(); + + let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); + let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); + + println!("from = {}\nto = {}", from, to); + } #[test] - fn test_tx_gen() {} + fn test_tx_gen() { + let tx = r#"{ + "module_method": "aaff", + "version": "1122", + "from": "15ckxVUHr2jvdRk43xfHRSqvo7ru6tnBD1FDmNT88dZbmEiR", + "to": "12joHcYyhDwJ6c5zuisLmTRS78vFUzCpD3XC4t8aQivUx3K3", + "amount": 80000000, + "nonce": 32, + "tip": 80000, + "block_height": 150000, + "block_hash": "36d3815b142fc9a93c1fff1ef7994fe6f3919ccc54a51c891e8418ca95a51020", + "genesis_hash": "ba2bcfed866d89c59110901ee513ffaba1ab6c8e3b99ab8d386c0f8fc0f8a38b", + "spec_version": 2, + "tx_version": 3, + "era_height": 88888 + }"#; + + let tx = tx_from_str::(tx); + + println!("tx = {}", tx); + } } From ffcf4ea1cac947eded30e1b22146e3cb706d4bab Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Fri, 1 Dec 2023 17:08:21 +0800 Subject: [PATCH 12/16] feat: signed transaction construction --- anychain-polkadot/Cargo.toml | 2 +- anychain-polkadot/src/network/mod.rs | 3 ++ anychain-polkadot/src/network/substrate.rs | 30 +++++++++++++ anychain-polkadot/src/transaction.rs | 50 ++++++++++++++-------- 4 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 anychain-polkadot/src/network/substrate.rs diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index 08911ae..2ddb704 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -7,6 +7,6 @@ edition = "2021" anychain-core = { path = "../anychain-core", version = "0.1.1" } sp-core = "24.0.0" base58 = { workspace = true } -parity-scale-codec = { version = "3.6.5", feature = "derive" } +parity-scale-codec = { version = "3.6.5" } ed25519-dalek-fiat = "0.1.0" serde_json = { workspace = true } \ No newline at end of file diff --git a/anychain-polkadot/src/network/mod.rs b/anychain-polkadot/src/network/mod.rs index c3fe0ef..bf99515 100644 --- a/anychain-polkadot/src/network/mod.rs +++ b/anychain-polkadot/src/network/mod.rs @@ -4,6 +4,9 @@ pub use polkadot::*; mod kusama; pub use kusama::*; +mod substrate; +pub use substrate::*; + use anychain_core::Network; pub trait PolkadotNetwork: Network { diff --git a/anychain-polkadot/src/network/substrate.rs b/anychain-polkadot/src/network/substrate.rs new file mode 100644 index 0000000..bc4b6b6 --- /dev/null +++ b/anychain-polkadot/src/network/substrate.rs @@ -0,0 +1,30 @@ +use std::{fmt::Display, str::FromStr}; + +use crate::PolkadotNetwork; +use anychain_core::{Network, NetworkError}; + +#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] +pub struct Substrate; + +impl Network for Substrate { + const NAME: &'static str = "substrate"; +} + +impl PolkadotNetwork for Substrate { + fn version() -> u8 { + 0x2a + } +} + +impl FromStr for Substrate { + type Err = NetworkError; + fn from_str(_s: &str) -> Result { + todo!() + } +} + +impl Display for Substrate { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index a1eea53..11c2c13 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -220,11 +220,11 @@ impl Display for PolkadotTransaction { #[cfg(test)] mod tests { use crate::{ - transaction, Kusama, Polkadot, PolkadotAddress, PolkadotFormat, PolkadotNetwork, - PolkadotTransaction, PolkadotTransactionParameters, + PolkadotAddress, PolkadotFormat, PolkadotNetwork, + PolkadotTransaction, PolkadotTransactionParameters, Substrate, }; use anychain_core::Address; - use anychain_core::{hex, libsecp256k1, Transaction}; + use anychain_core::{libsecp256k1, Transaction, hex}; use serde_json::Value; use std::str::FromStr; @@ -285,8 +285,8 @@ mod tests { let sk_from = libsecp256k1::SecretKey::parse_slice(&sk_from).unwrap(); let sk_to = libsecp256k1::SecretKey::parse_slice(&sk_to).unwrap(); - let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); - let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); + let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); + let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); println!("from = {}\nto = {}", from, to); } @@ -294,23 +294,37 @@ mod tests { #[test] fn test_tx_gen() { let tx = r#"{ - "module_method": "aaff", - "version": "1122", - "from": "15ckxVUHr2jvdRk43xfHRSqvo7ru6tnBD1FDmNT88dZbmEiR", - "to": "12joHcYyhDwJ6c5zuisLmTRS78vFUzCpD3XC4t8aQivUx3K3", - "amount": 80000000, - "nonce": 32, - "tip": 80000, - "block_height": 150000, - "block_hash": "36d3815b142fc9a93c1fff1ef7994fe6f3919ccc54a51c891e8418ca95a51020", - "genesis_hash": "ba2bcfed866d89c59110901ee513ffaba1ab6c8e3b99ab8d386c0f8fc0f8a38b", - "spec_version": 2, + "module_method": "", + "version": "84", + "from": "5GgTpADDzFUTBtjY6KcHHJ1mwVsFQbE38WWjc5TmaYY5b7zF", + "to": "5DoW9HHuqSfpf55Ux5pLdJbHFWvbngeg8Ynhub9DrdtxmZeV", + "amount": 50000000000000, + "nonce": 0, + "tip": 1000000000000, + "block_height": 8117556, + "block_hash": "d268b9ef1c92dbaf68bd850ef65b3ea2764b9dabc41980c56d440848288f536c", + "genesis_hash": "e3777fa922cafbff200cadeaea1a76bd7898ad5b89f7848999058b50e715f636", + "spec_version": 104000, "tx_version": 3, "era_height": 88888 }"#; - let tx = tx_from_str::(tx); + let mut tx = tx_from_str::(tx); + let hash = tx.to_transaction_id().unwrap().txid; + let msg = libsecp256k1::Message::parse_slice(&hash).unwrap(); - println!("tx = {}", tx); + let sk = [ + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1u8, + ]; + + let sk = libsecp256k1::SecretKey::parse_slice(&sk).unwrap(); + let sig = libsecp256k1::sign(&msg, &sk).0; + let sig = sig.serialize().to_vec(); + + let signed_tx = tx.sign(sig, 0).unwrap(); + let signed_tx = hex::encode(&signed_tx); + + println!("signed tx = {}", signed_tx); } } From 6ccd727583f3bdae3c1170b4b79528d7820b7da7 Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Fri, 1 Dec 2023 17:09:42 +0800 Subject: [PATCH 13/16] type: cargo fmt --- anychain-polkadot/src/transaction.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index 11c2c13..6b98d77 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -220,11 +220,11 @@ impl Display for PolkadotTransaction { #[cfg(test)] mod tests { use crate::{ - PolkadotAddress, PolkadotFormat, PolkadotNetwork, - PolkadotTransaction, PolkadotTransactionParameters, Substrate, + PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotTransaction, + PolkadotTransactionParameters, Substrate, }; use anychain_core::Address; - use anychain_core::{libsecp256k1, Transaction, hex}; + use anychain_core::{hex, libsecp256k1, Transaction}; use serde_json::Value; use std::str::FromStr; @@ -321,7 +321,7 @@ mod tests { let sk = libsecp256k1::SecretKey::parse_slice(&sk).unwrap(); let sig = libsecp256k1::sign(&msg, &sk).0; let sig = sig.serialize().to_vec(); - + let signed_tx = tx.sign(sig, 0).unwrap(); let signed_tx = hex::encode(&signed_tx); From 7a00c5f95d01e9ff522ea44b6cf9ef2083b7186a Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Tue, 19 Dec 2023 16:10:29 +0800 Subject: [PATCH 14/16] feat: enable multisignature for polkadot --- anychain-polkadot/src/address.rs | 30 ++++++++++---------- anychain-polkadot/src/public_key.rs | 42 ++++++++++++++++++++++++---- anychain-polkadot/src/transaction.rs | 9 ++++-- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index be96dbb..162d16e 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, marker::PhantomData, str::FromStr}; use anychain_core::{hex, libsecp256k1, Address, AddressError, PublicKey, TransactionError}; -use crate::{PolkadotFormat, PolkadotNetwork, PolkadotPublicKey}; +use crate::{PolkadotFormat, PolkadotNetwork, PolkadotPublicKey, PolkadotSecretKey, PublicKeyContent}; use base58::{FromBase58, ToBase58}; use sp_core::hashing::{blake2_256, blake2_512}; @@ -13,7 +13,7 @@ pub struct PolkadotAddress { } impl Address for PolkadotAddress { - type SecretKey = libsecp256k1::SecretKey; + type SecretKey = PolkadotSecretKey; type PublicKey = PolkadotPublicKey; type Format = PolkadotFormat; @@ -28,15 +28,14 @@ impl Address for PolkadotAddress { public_key: &Self::PublicKey, _format: &Self::Format, ) -> Result { - let pk_hash = blake2_256(&public_key.serialize()).to_vec(); - Self::from_pk_hash(&hex::encode(&pk_hash)) + Self::from_payload(&hex::encode(&public_key.address_payload())) } } impl PolkadotAddress { - pub fn from_pk_hash(pk_hash: &str) -> Result { - let pk_hash = hex::decode(pk_hash).unwrap(); - let payload = [vec![N::version()], pk_hash].concat(); + pub fn from_payload(payload: &str) -> Result { + let payload = hex::decode(payload).unwrap(); + let payload = [vec![N::version()], payload].concat(); let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; @@ -49,7 +48,7 @@ impl PolkadotAddress { }) } - pub fn to_pk_hash(&self) -> Result, AddressError> { + pub fn to_payload(&self) -> Result, AddressError> { let bin = self.addr.as_str().from_base58()?; Ok(bin[1..33].to_vec()) } @@ -91,20 +90,21 @@ impl Display for PolkadotAddress { #[cfg(test)] mod tests { - use super::libsecp256k1::SecretKey; - use crate::{Polkadot, PolkadotAddress, PolkadotFormat}; + use ed25519_dalek_fiat::SecretKey; + use crate::{Polkadot, PolkadotAddress, PolkadotFormat, Substrate, PolkadotSecretKey}; use anychain_core::Address; #[test] fn test_address() { let sk = [ - 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ]; - let sk = SecretKey::parse_slice(&sk).unwrap(); + let sk = SecretKey::from_bytes(&sk).unwrap(); + let sk = PolkadotSecretKey::Ed25519(sk); let address = - PolkadotAddress::::from_secret_key(&sk, &PolkadotFormat::Standard).unwrap(); + PolkadotAddress::::from_secret_key(&sk, &PolkadotFormat::Standard).unwrap(); println!("address = {}", address); } @@ -112,7 +112,7 @@ mod tests { #[test] fn test_address_2() { let hash = "0c2f3c6dabb4a0600eccae87aeaa39242042f9a576aa8dca01e1b419cf17d7a2"; - let address = PolkadotAddress::::from_pk_hash(hash).unwrap(); + let address = PolkadotAddress::::from_payload(hash).unwrap(); println!("address = {}", address); } } diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index 0f9ae28..b689cae 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -1,22 +1,42 @@ use crate::{PolkadotAddress, PolkadotFormat, PolkadotNetwork}; use anychain_core::{libsecp256k1, Address, PublicKey, PublicKeyError}; +use sp_core::blake2_256; use std::{fmt::Display, marker::PhantomData, str::FromStr}; +pub enum PolkadotSecretKey { + Secp256k1(libsecp256k1::SecretKey), + Ed25519(ed25519_dalek_fiat::SecretKey), +} + +#[derive(Debug, Clone)] +pub enum PublicKeyContent { + Secp256k1(libsecp256k1::PublicKey), + Ed25519(ed25519_dalek_fiat::PublicKey), +} + #[derive(Debug, Clone)] pub struct PolkadotPublicKey { - key: libsecp256k1::PublicKey, + pub key: PublicKeyContent, _network: PhantomData, } impl PublicKey for PolkadotPublicKey { - type SecretKey = libsecp256k1::SecretKey; + type SecretKey = PolkadotSecretKey; type Address = PolkadotAddress; type Format = PolkadotFormat; fn from_secret_key(secret_key: &Self::SecretKey) -> Self { - Self { - key: libsecp256k1::PublicKey::from_secret_key(secret_key), - _network: PhantomData::, + match secret_key { + Self::SecretKey::Secp256k1(sk) => { + let pk = libsecp256k1::PublicKey::from_secret_key(sk); + let pk = PublicKeyContent::Secp256k1(pk); + Self { key: pk, _network: PhantomData } + } + Self::SecretKey::Ed25519(sk) => { + let pk = ed25519_dalek_fiat::PublicKey::from(sk); + let pk = PublicKeyContent::Ed25519(pk); + Self { key: pk, _network: PhantomData } + } } } @@ -30,7 +50,17 @@ impl PublicKey for PolkadotPublicKey { impl PolkadotPublicKey { pub fn serialize(&self) -> Vec { - self.key.serialize_compressed().to_vec() + match self.key { + PublicKeyContent::Secp256k1(pk) => pk.serialize_compressed().to_vec(), + PublicKeyContent::Ed25519(pk) => pk.to_bytes().to_vec(), + } + } + + pub fn address_payload(&self) -> Vec { + match self.key { + PublicKeyContent::Secp256k1(_) => blake2_256(&self.serialize()).to_vec(), + PublicKeyContent::Ed25519(_) => self.serialize(), + } } } diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index 6b98d77..d1c9e54 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -124,7 +124,7 @@ impl Transaction for PolkadotTransaction { Some(sig) => { let interim = self.to_interim()?; let version = hex::decode(&self.params.version)?; - let from = self.params.from.to_pk_hash()?; + let from = self.params.from.to_payload()?; let stream = [ version, @@ -173,7 +173,7 @@ impl PolkadotTransaction { let params = &self.params; let method = hex::decode(¶ms.module_method)?; - let to = params.to.to_pk_hash()?; + let to = params.to.to_payload()?; let amount = encode(params.amount); let era = get_era(params.block_height, params.era_height); @@ -221,7 +221,7 @@ impl Display for PolkadotTransaction { mod tests { use crate::{ PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotTransaction, - PolkadotTransactionParameters, Substrate, + PolkadotTransactionParameters, Substrate, PolkadotSecretKey, }; use anychain_core::Address; use anychain_core::{hex, libsecp256k1, Transaction}; @@ -285,6 +285,9 @@ mod tests { let sk_from = libsecp256k1::SecretKey::parse_slice(&sk_from).unwrap(); let sk_to = libsecp256k1::SecretKey::parse_slice(&sk_to).unwrap(); + let sk_from = PolkadotSecretKey::Secp256k1(sk_from); + let sk_to = PolkadotSecretKey::Secp256k1(sk_to); + let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); From fbfc6afc1022ddc123f17b4ca982a2b0f5bed774 Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Tue, 2 Jan 2024 15:39:06 +0800 Subject: [PATCH 15/16] feat: ed25519 and secp256k1 signing scheme for anychain-polkadot --- anychain-polkadot/Cargo.toml | 3 +- anychain-polkadot/src/address.rs | 38 +++++-- anychain-polkadot/src/public_key.rs | 10 +- anychain-polkadot/src/transaction.rs | 144 +++++++++++++-------------- 4 files changed, 107 insertions(+), 88 deletions(-) diff --git a/anychain-polkadot/Cargo.toml b/anychain-polkadot/Cargo.toml index 2ddb704..10c681e 100644 --- a/anychain-polkadot/Cargo.toml +++ b/anychain-polkadot/Cargo.toml @@ -9,4 +9,5 @@ sp-core = "24.0.0" base58 = { workspace = true } parity-scale-codec = { version = "3.6.5" } ed25519-dalek-fiat = "0.1.0" -serde_json = { workspace = true } \ No newline at end of file +serde_json = { workspace = true } +rand.workspace = true diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index 162d16e..d3d5bda 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -1,10 +1,10 @@ use std::{fmt::Display, marker::PhantomData, str::FromStr}; -use anychain_core::{hex, libsecp256k1, Address, AddressError, PublicKey, TransactionError}; +use anychain_core::{hex, Address, AddressError, PublicKey, TransactionError}; -use crate::{PolkadotFormat, PolkadotNetwork, PolkadotPublicKey, PolkadotSecretKey, PublicKeyContent}; +use crate::{PolkadotFormat, PolkadotNetwork, PolkadotPublicKey, PolkadotSecretKey}; use base58::{FromBase58, ToBase58}; -use sp_core::hashing::{blake2_256, blake2_512}; +use sp_core::hashing::blake2_512; #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct PolkadotAddress { @@ -90,16 +90,21 @@ impl Display for PolkadotAddress { #[cfg(test)] mod tests { + use std::str::FromStr; + + use crate::{Polkadot, PolkadotAddress, PolkadotFormat, PolkadotSecretKey, Substrate}; + use anychain_core::{hex, Address}; use ed25519_dalek_fiat::SecretKey; - use crate::{Polkadot, PolkadotAddress, PolkadotFormat, Substrate, PolkadotSecretKey}; - use anychain_core::Address; #[test] fn test_address() { let sk = [ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, ]; + let h = hex::encode(&sk); + println!("{}", h); + let sk = SecretKey::from_bytes(&sk).unwrap(); let sk = PolkadotSecretKey::Ed25519(sk); @@ -111,8 +116,23 @@ mod tests { #[test] fn test_address_2() { - let hash = "0c2f3c6dabb4a0600eccae87aeaa39242042f9a576aa8dca01e1b419cf17d7a2"; - let address = PolkadotAddress::::from_payload(hash).unwrap(); + let hash = "8ee504148e75c34e8f051899b3c6e4241ff18dc1c9211260b6a6a434bedb485f"; + let address = PolkadotAddress::::from_payload(hash).unwrap(); println!("address = {}", address); } + + #[test] + fn test_address_3() { + let addr = "5DoW9HHuqSfpf55Ux5pLdJbHFWvbngeg8Ynhub9DrdtxmZeV"; + let addr = PolkadotAddress::::from_str(addr).unwrap(); + let payload = addr.to_payload().unwrap(); + let payload = hex::encode(payload); + println!("{}", payload); + } + + #[test] + fn f() { + let s = "012eaaeadc3e26dcb6ce0479ff94b009fdb8f81d9c6cf43ba2a4595496564b7d10c8498f90139462d5ce300599a85335515ef970bf3645f7ced5e22181231d638c"; + println!("len = {}", s.len()); + } } diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index b689cae..ed0fc99 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -30,12 +30,18 @@ impl PublicKey for PolkadotPublicKey { Self::SecretKey::Secp256k1(sk) => { let pk = libsecp256k1::PublicKey::from_secret_key(sk); let pk = PublicKeyContent::Secp256k1(pk); - Self { key: pk, _network: PhantomData } + Self { + key: pk, + _network: PhantomData, + } } Self::SecretKey::Ed25519(sk) => { let pk = ed25519_dalek_fiat::PublicKey::from(sk); let pk = PublicKeyContent::Ed25519(pk); - Self { key: pk, _network: PhantomData } + Self { + key: pk, + _network: PhantomData, + } } } } diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index d1c9e54..abd6133 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -1,26 +1,19 @@ use crate::{PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotPublicKey}; -use anychain_core::{ - crypto::{blake2b_256, keccak256, sha256, sha512}, - hex, Transaction, TransactionError, TransactionId, -}; +use anychain_core::{crypto::blake2b_256, hex, Transaction, TransactionError, TransactionId}; use parity_scale_codec::{Decode, Encode, HasCompact}; use std::fmt::Display; #[derive(Clone)] pub struct PolkadotTransactionParameters { - pub module_method: String, - pub version: String, pub from: PolkadotAddress, pub to: PolkadotAddress, pub amount: u64, pub nonce: u64, pub tip: u64, - pub block_height: u64, pub block_hash: String, pub genesis_hash: String, pub spec_version: u32, pub tx_version: u32, - pub era_height: u64, } struct TxInterim { @@ -59,29 +52,6 @@ struct CompactWrapper { val: T, } -fn get_era(block_height: u64, mut era_height: u64) -> Vec { - if era_height == 0 { - era_height = 64 - } - let phase = block_height % era_height; - let index = 6u64; - let trailing_zero = index - 1; - - let mut encoded = if trailing_zero > 15 { - 15 - } else if trailing_zero < 1 { - 1 - } else { - trailing_zero - }; - - encoded += phase / 1 << 4; - let first = (encoded >> 8) as u8; - let second = (encoded & 0xff) as u8; - - vec![second, first] -} - fn encode(val: u64) -> Vec { if val == 0 { vec![0] @@ -104,14 +74,15 @@ impl Transaction for PolkadotTransaction { }) } - fn sign(&mut self, rs: Vec, _recid: u8) -> Result, TransactionError> { + fn sign(&mut self, rs: Vec, recid: u8) -> Result, TransactionError> { if rs.len() != 64 { return Err(TransactionError::Message(format!( "Invalid signature length {}", rs.len(), ))); } - self.signature = Some(rs); + // self.signature = Some([vec![recid], rs].concat()); + self.signature = Some([rs, vec![recid]].concat()); self.to_bytes() } @@ -123,14 +94,13 @@ impl Transaction for PolkadotTransaction { match &self.signature { Some(sig) => { let interim = self.to_interim()?; - let version = hex::decode(&self.params.version)?; let from = self.params.from.to_payload()?; let stream = [ - version, + vec![0x84], // version = 0x84 vec![0], from, - vec![2], // secp256k1 signature scheme = 2 + vec![2], // ed25519 = 0, sr25519 = 1, secp256k1 = 2 sig.clone(), interim.era, interim.nonce, @@ -163,7 +133,7 @@ impl Transaction for PolkadotTransaction { fn to_transaction_id(&self) -> Result { Ok(PolkadotTransactionId { - txid: self.digest(1)?, + txid: self.digest()?, }) } } @@ -172,10 +142,9 @@ impl PolkadotTransaction { fn to_interim(&self) -> Result { let params = &self.params; - let method = hex::decode(¶ms.module_method)?; let to = params.to.to_payload()?; let amount = encode(params.amount); - let era = get_era(params.block_height, params.era_height); + let era = vec![0]; let nonce = encode(params.nonce); let tip = encode(params.tip); @@ -186,8 +155,11 @@ impl PolkadotTransaction { let genesis_hash = hex::decode(¶ms.genesis_hash)?; let block_hash = hex::decode(¶ms.block_hash)?; + let pallet_index = 4; + let function_index = 3; + let interim = TxInterim { - method: [method, vec![0], to, amount].concat(), + method: [vec![pallet_index, function_index], vec![0], to, amount].concat(), era, nonce, tip, @@ -200,14 +172,8 @@ impl PolkadotTransaction { Ok(interim) } - pub fn digest(&self, index: u8) -> Result, TransactionError> { - match index { - 0 => Ok(blake2b_256(&self.to_bytes()?).to_vec()), - 1 => Ok(sha256(&self.to_bytes()?).to_vec()), - 2 => Ok(keccak256(&self.to_bytes()?).to_vec()), - 3 => Ok(sha512(&self.to_bytes()?)[..32].to_vec()), - _ => Err(TransactionError::Message("invalid digest code".to_string())), - } + pub fn digest(&self) -> Result, TransactionError> { + Ok(blake2b_256(&self.to_bytes()?).to_vec()) } } @@ -220,8 +186,8 @@ impl Display for PolkadotTransaction { #[cfg(test)] mod tests { use crate::{ - PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotTransaction, - PolkadotTransactionParameters, Substrate, PolkadotSecretKey, + PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotSecretKey, PolkadotTransaction, + PolkadotTransactionParameters, Substrate, }; use anychain_core::Address; use anychain_core::{hex, libsecp256k1, Transaction}; @@ -231,10 +197,6 @@ mod tests { fn tx_from_str(json: &str) -> PolkadotTransaction { let json = serde_json::from_str::(json).unwrap(); - let module_method = json["module_method"].as_str().unwrap().to_string(); - - let version = json["version"].as_str().unwrap().to_string(); - let from = PolkadotAddress::::from_str(json["from"].as_str().unwrap()).unwrap(); let to = PolkadotAddress::::from_str(json["to"].as_str().unwrap()).unwrap(); @@ -242,27 +204,21 @@ mod tests { let amount = json["amount"].as_u64().unwrap(); let nonce = json["nonce"].as_u64().unwrap(); let tip = json["tip"].as_u64().unwrap(); - let block_height = json["block_height"].as_u64().unwrap(); let block_hash = json["block_hash"].as_str().unwrap().to_string(); let genesis_hash = json["genesis_hash"].as_str().unwrap().to_string(); let spec_version = json["spec_version"].as_u64().unwrap() as u32; let tx_version = json["tx_version"].as_u64().unwrap() as u32; - let era_height = json["era_height"].as_u64().unwrap(); let params = PolkadotTransactionParameters:: { - module_method, - version, from, to, amount, nonce, tip, - block_height, block_hash, genesis_hash, spec_version, tx_version, - era_height, }; PolkadotTransaction::::new(¶ms).unwrap() @@ -273,8 +229,8 @@ mod tests { let format = &PolkadotFormat::Standard; let sk_from = [ - 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1u8, + 228u8, 121, 108, 167, 244, 6, 57, 61, 104, 68, 229, 88, 23, 16, 212, 157, 110, 171, 36, + 26, 232, 171, 144, 41, 109, 182, 148, 243, 20, 23, 29, 61, ]; let sk_to = [ @@ -297,19 +253,15 @@ mod tests { #[test] fn test_tx_gen() { let tx = r#"{ - "module_method": "", - "version": "84", - "from": "5GgTpADDzFUTBtjY6KcHHJ1mwVsFQbE38WWjc5TmaYY5b7zF", + "from": "5FnS6tYbCTAtK3QCfNnddwVR61ypLLM7APRrs98paFs7yMSY", "to": "5DoW9HHuqSfpf55Ux5pLdJbHFWvbngeg8Ynhub9DrdtxmZeV", - "amount": 50000000000000, + "amount": 1000000000000, "nonce": 0, - "tip": 1000000000000, - "block_height": 8117556, - "block_hash": "d268b9ef1c92dbaf68bd850ef65b3ea2764b9dabc41980c56d440848288f536c", - "genesis_hash": "e3777fa922cafbff200cadeaea1a76bd7898ad5b89f7848999058b50e715f636", - "spec_version": 104000, - "tx_version": 3, - "era_height": 88888 + "tip": 0, + "block_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", + "genesis_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", + "spec_version": 1005000, + "tx_version": 24 }"#; let mut tx = tx_from_str::(tx); @@ -317,13 +269,53 @@ mod tests { let msg = libsecp256k1::Message::parse_slice(&hash).unwrap(); let sk = [ - 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1u8, + 228u8, 121, 108, 167, 244, 6, 57, 61, 104, 68, 229, 88, 23, 16, 212, 157, 110, 171, 36, + 26, 232, 171, 144, 41, 109, 182, 148, 243, 20, 23, 29, 61, ]; let sk = libsecp256k1::SecretKey::parse_slice(&sk).unwrap(); - let sig = libsecp256k1::sign(&msg, &sk).0; + let (sig, rec) = libsecp256k1::sign(&msg, &sk); let sig = sig.serialize().to_vec(); + let rec = rec.serialize(); + + let signed_tx = tx.sign(sig, rec).unwrap(); + let signed_tx = hex::encode(&signed_tx); + + println!("signed tx = {}", signed_tx); + } + + #[test] + fn test_tx_gen_2() { + use ed25519_dalek_fiat::Signer; + + let tx = r#"{ + "from": "5DPaKszR7KpCbvNNtGCGTfrGdeDTUNRt1UdxwXp9G6iWvdk7", + "to": "5D1NKGqfc2Q8hw53icrX74YQryjb3MMySWwFBhM71afKbdad", + "amount": 1000000000000, + "nonce": 2, + "tip": 0, + "block_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", + "genesis_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", + "spec_version": 1005000, + "tx_version": 24 + }"#; + + let mut tx = tx_from_str::(tx); + let msg = tx.to_bytes().unwrap(); + + let sk = [ + 228u8, 121, 108, 167, 244, 6, 57, 61, 104, 68, 229, 88, 23, 16, 212, 157, 110, 171, 36, + 26, 232, 171, 144, 41, 109, 182, 148, 243, 20, 23, 29, 61, + ]; + + let sk = ed25519_dalek_fiat::SecretKey::from_bytes(&sk).unwrap(); + let pk = ed25519_dalek_fiat::PublicKey::from(&sk); + + let kp = ed25519_dalek_fiat::Keypair { + secret: sk, + public: pk, + }; + let sig = kp.sign(&msg).to_bytes().to_vec(); let signed_tx = tx.sign(sig, 0).unwrap(); let signed_tx = hex::encode(&signed_tx); From c946d46ae1934cfe0d246b96084080a4c96eba33 Mon Sep 17 00:00:00 2001 From: aya015757881 <2581015450@qq.com> Date: Tue, 2 Jan 2024 21:50:22 +0800 Subject: [PATCH 16/16] feat: polkadot support completion --- anychain-polkadot/src/address.rs | 22 ++-- anychain-polkadot/src/network/kusama.rs | 7 +- anychain-polkadot/src/network/mod.rs | 12 +- anychain-polkadot/src/network/polkadot.rs | 7 +- .../src/network/{substrate.rs => rococo.rs} | 19 +-- anychain-polkadot/src/network/westend.rs | 31 +++++ anychain-polkadot/src/public_key.rs | 2 +- anychain-polkadot/src/transaction.rs | 120 +++++++++++++++--- 8 files changed, 167 insertions(+), 53 deletions(-) rename anychain-polkadot/src/network/{substrate.rs => rococo.rs} (55%) create mode 100644 anychain-polkadot/src/network/westend.rs diff --git a/anychain-polkadot/src/address.rs b/anychain-polkadot/src/address.rs index d3d5bda..da28546 100644 --- a/anychain-polkadot/src/address.rs +++ b/anychain-polkadot/src/address.rs @@ -28,14 +28,14 @@ impl Address for PolkadotAddress { public_key: &Self::PublicKey, _format: &Self::Format, ) -> Result { - Self::from_payload(&hex::encode(&public_key.address_payload())) + Self::from_payload(&hex::encode(public_key.address_payload())) } } impl PolkadotAddress { pub fn from_payload(payload: &str) -> Result { let payload = hex::decode(payload).unwrap(); - let payload = [vec![N::version()], payload].concat(); + let payload = [vec![N::VERSION], payload].concat(); let ss_prefix = vec![0x53u8, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]; @@ -58,7 +58,7 @@ impl FromStr for PolkadotAddress { type Err = TransactionError; fn from_str(s: &str) -> Result { let bytes = s.from_base58()?; - if N::version() != bytes[0] { + if N::VERSION != bytes[0] { return Err(TransactionError::Message(format!( "Invalid version byte {} for polkadot network {}", bytes[0], @@ -92,7 +92,7 @@ impl Display for PolkadotAddress { mod tests { use std::str::FromStr; - use crate::{Polkadot, PolkadotAddress, PolkadotFormat, PolkadotSecretKey, Substrate}; + use crate::{PolkadotAddress, PolkadotFormat, PolkadotSecretKey, Westend}; use anychain_core::{hex, Address}; use ed25519_dalek_fiat::SecretKey; @@ -102,14 +102,14 @@ mod tests { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ]; - let h = hex::encode(&sk); + let h = hex::encode(sk); println!("{}", h); let sk = SecretKey::from_bytes(&sk).unwrap(); let sk = PolkadotSecretKey::Ed25519(sk); let address = - PolkadotAddress::::from_secret_key(&sk, &PolkadotFormat::Standard).unwrap(); + PolkadotAddress::::from_secret_key(&sk, &PolkadotFormat::Standard).unwrap(); println!("address = {}", address); } @@ -117,22 +117,16 @@ mod tests { #[test] fn test_address_2() { let hash = "8ee504148e75c34e8f051899b3c6e4241ff18dc1c9211260b6a6a434bedb485f"; - let address = PolkadotAddress::::from_payload(hash).unwrap(); + let address = PolkadotAddress::::from_payload(hash).unwrap(); println!("address = {}", address); } #[test] fn test_address_3() { let addr = "5DoW9HHuqSfpf55Ux5pLdJbHFWvbngeg8Ynhub9DrdtxmZeV"; - let addr = PolkadotAddress::::from_str(addr).unwrap(); + let addr = PolkadotAddress::::from_str(addr).unwrap(); let payload = addr.to_payload().unwrap(); let payload = hex::encode(payload); println!("{}", payload); } - - #[test] - fn f() { - let s = "012eaaeadc3e26dcb6ce0479ff94b009fdb8f81d9c6cf43ba2a4595496564b7d10c8498f90139462d5ce300599a85335515ef970bf3645f7ced5e22181231d638c"; - println!("len = {}", s.len()); - } } diff --git a/anychain-polkadot/src/network/kusama.rs b/anychain-polkadot/src/network/kusama.rs index 65c5cfe..d6b8a36 100644 --- a/anychain-polkadot/src/network/kusama.rs +++ b/anychain-polkadot/src/network/kusama.rs @@ -11,9 +11,10 @@ impl Network for Kusama { } impl PolkadotNetwork for Kusama { - fn version() -> u8 { - 0x02 - } + const VERSION: u8 = 0x02; + const PALLET_ASSET: u8 = 4; + const TRANSFER_ALLOW_DEATH: u8 = 0; + const TRANSFER_KEEP_ALIVE: u8 = 3; } impl FromStr for Kusama { diff --git a/anychain-polkadot/src/network/mod.rs b/anychain-polkadot/src/network/mod.rs index bf99515..950427f 100644 --- a/anychain-polkadot/src/network/mod.rs +++ b/anychain-polkadot/src/network/mod.rs @@ -4,11 +4,17 @@ pub use polkadot::*; mod kusama; pub use kusama::*; -mod substrate; -pub use substrate::*; +mod westend; +pub use westend::*; + +mod rococo; +pub use rococo::*; use anychain_core::Network; pub trait PolkadotNetwork: Network { - fn version() -> u8; + const VERSION: u8; + const PALLET_ASSET: u8; + const TRANSFER_ALLOW_DEATH: u8; + const TRANSFER_KEEP_ALIVE: u8; } diff --git a/anychain-polkadot/src/network/polkadot.rs b/anychain-polkadot/src/network/polkadot.rs index a3e6916..d89b989 100644 --- a/anychain-polkadot/src/network/polkadot.rs +++ b/anychain-polkadot/src/network/polkadot.rs @@ -11,9 +11,10 @@ impl Network for Polkadot { } impl PolkadotNetwork for Polkadot { - fn version() -> u8 { - 0x00 - } + const VERSION: u8 = 0x00; + const PALLET_ASSET: u8 = 5; + const TRANSFER_ALLOW_DEATH: u8 = 0; + const TRANSFER_KEEP_ALIVE: u8 = 3; } impl FromStr for Polkadot { diff --git a/anychain-polkadot/src/network/substrate.rs b/anychain-polkadot/src/network/rococo.rs similarity index 55% rename from anychain-polkadot/src/network/substrate.rs rename to anychain-polkadot/src/network/rococo.rs index bc4b6b6..d331af0 100644 --- a/anychain-polkadot/src/network/substrate.rs +++ b/anychain-polkadot/src/network/rococo.rs @@ -4,26 +4,27 @@ use crate::PolkadotNetwork; use anychain_core::{Network, NetworkError}; #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] -pub struct Substrate; +pub struct Rococo; -impl Network for Substrate { - const NAME: &'static str = "substrate"; +impl Network for Rococo { + const NAME: &'static str = "rococo"; } -impl PolkadotNetwork for Substrate { - fn version() -> u8 { - 0x2a - } +impl PolkadotNetwork for Rococo { + const VERSION: u8 = 0x2a; + const PALLET_ASSET: u8 = 4; + const TRANSFER_ALLOW_DEATH: u8 = 0; + const TRANSFER_KEEP_ALIVE: u8 = 3; } -impl FromStr for Substrate { +impl FromStr for Rococo { type Err = NetworkError; fn from_str(_s: &str) -> Result { todo!() } } -impl Display for Substrate { +impl Display for Rococo { fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { todo!() } diff --git a/anychain-polkadot/src/network/westend.rs b/anychain-polkadot/src/network/westend.rs new file mode 100644 index 0000000..d19df04 --- /dev/null +++ b/anychain-polkadot/src/network/westend.rs @@ -0,0 +1,31 @@ +use std::{fmt::Display, str::FromStr}; + +use crate::PolkadotNetwork; +use anychain_core::{Network, NetworkError}; + +#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] +pub struct Westend; + +impl Network for Westend { + const NAME: &'static str = "westend"; +} + +impl PolkadotNetwork for Westend { + const VERSION: u8 = 0x2a; + const PALLET_ASSET: u8 = 4; + const TRANSFER_ALLOW_DEATH: u8 = 0; + const TRANSFER_KEEP_ALIVE: u8 = 3; +} + +impl FromStr for Westend { + type Err = NetworkError; + fn from_str(_s: &str) -> Result { + todo!() + } +} + +impl Display for Westend { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} diff --git a/anychain-polkadot/src/public_key.rs b/anychain-polkadot/src/public_key.rs index ed0fc99..acb3ac9 100644 --- a/anychain-polkadot/src/public_key.rs +++ b/anychain-polkadot/src/public_key.rs @@ -50,7 +50,7 @@ impl PublicKey for PolkadotPublicKey { &self, format: &Self::Format, ) -> Result { - Ok(Self::Address::from_public_key(self, format)?) + Self::Address::from_public_key(self, format) } } diff --git a/anychain-polkadot/src/transaction.rs b/anychain-polkadot/src/transaction.rs index abd6133..0d52a40 100644 --- a/anychain-polkadot/src/transaction.rs +++ b/anychain-polkadot/src/transaction.rs @@ -74,6 +74,7 @@ impl Transaction for PolkadotTransaction { }) } + // Only used for secp256k1 signing scheme fn sign(&mut self, rs: Vec, recid: u8) -> Result, TransactionError> { if rs.len() != 64 { return Err(TransactionError::Message(format!( @@ -81,7 +82,6 @@ impl Transaction for PolkadotTransaction { rs.len(), ))); } - // self.signature = Some([vec![recid], rs].concat()); self.signature = Some([rs, vec![recid]].concat()); self.to_bytes() } @@ -90,6 +90,7 @@ impl Transaction for PolkadotTransaction { todo!() } + // Only used for secp256k1 signing scheme fn to_bytes(&self) -> Result, TransactionError> { match &self.signature { Some(sig) => { @@ -133,7 +134,7 @@ impl Transaction for PolkadotTransaction { fn to_transaction_id(&self) -> Result { Ok(PolkadotTransactionId { - txid: self.digest()?, + txid: blake2b_256(&self.to_bytes()?).to_vec(), }) } } @@ -155,11 +156,14 @@ impl PolkadotTransaction { let genesis_hash = hex::decode(¶ms.genesis_hash)?; let block_hash = hex::decode(¶ms.block_hash)?; - let pallet_index = 4; - let function_index = 3; - let interim = TxInterim { - method: [vec![pallet_index, function_index], vec![0], to, amount].concat(), + method: [ + vec![N::PALLET_ASSET, N::TRANSFER_ALLOW_DEATH], + vec![0], + to, + amount, + ] + .concat(), era, nonce, tip, @@ -172,8 +176,58 @@ impl PolkadotTransaction { Ok(interim) } - pub fn digest(&self) -> Result, TransactionError> { - Ok(blake2b_256(&self.to_bytes()?).to_vec()) + // Alternative to to_bytes() when using ed25519 signing scheme + fn to_bytes_ed25519(&self) -> Result, TransactionError> { + match &self.signature { + Some(sig) => { + let interim = self.to_interim()?; + let from = self.params.from.to_payload()?; + + let stream = [ + vec![0x84], // version = 0x84 + vec![0], + from, + vec![0], // ed25519 = 0, sr25519 = 1, secp256k1 = 2 + sig.clone(), + interim.era, + interim.nonce, + interim.tip, + interim.method, + ] + .concat(); + + let len = stream.len() as u64; + let len = encode(len); + + Ok([len, stream].concat()) + } + None => { + let interim = self.to_interim()?; + Ok([ + interim.method, + interim.era, + interim.nonce, + interim.tip, + interim.spec_version, + interim.tx_version, + interim.genesis_hash, + interim.block_hash, + ] + .concat()) + } + } + } + + // Alternative to sign() when using ed25519 signing scheme + pub fn sign_ed25519(&mut self, rs: Vec) -> Result, TransactionError> { + if rs.len() != 64 { + return Err(TransactionError::Message(format!( + "Invalid signature length {}", + rs.len(), + ))); + } + self.signature = Some(rs); + self.to_bytes_ed25519() } } @@ -187,7 +241,7 @@ impl Display for PolkadotTransaction { mod tests { use crate::{ PolkadotAddress, PolkadotFormat, PolkadotNetwork, PolkadotSecretKey, PolkadotTransaction, - PolkadotTransactionParameters, Substrate, + PolkadotTransactionParameters, Westend, }; use anychain_core::Address; use anychain_core::{hex, libsecp256k1, Transaction}; @@ -244,8 +298,34 @@ mod tests { let sk_from = PolkadotSecretKey::Secp256k1(sk_from); let sk_to = PolkadotSecretKey::Secp256k1(sk_to); - let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); - let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); + let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); + let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); + + println!("from = {}\nto = {}", from, to); + } + + #[test] + fn test_address_gen_2() { + let format = &PolkadotFormat::Standard; + + let sk_from = [ + 228u8, 121, 108, 167, 244, 6, 57, 61, 104, 68, 229, 88, 23, 16, 212, 157, 110, 171, 36, + 26, 232, 171, 144, 41, 109, 182, 148, 243, 20, 23, 29, 61, + ]; + + let sk_to = [ + 3, 1, 2, 5, 8, 1, 118, 203, 0, 1, 2, 1, 1, 2, 1, 1, 1, 103, 0, 0, 2, 2, 2, 2, 2, 2, 3, + 5, 8, 13, 17, 29, + ]; + + let sk_from = ed25519_dalek_fiat::SecretKey::from_bytes(&sk_from).unwrap(); + let sk_to = ed25519_dalek_fiat::SecretKey::from_bytes(&sk_to).unwrap(); + + let sk_from = PolkadotSecretKey::Ed25519(sk_from); + let sk_to = PolkadotSecretKey::Ed25519(sk_to); + + let from = PolkadotAddress::::from_secret_key(&sk_from, format).unwrap(); + let to = PolkadotAddress::::from_secret_key(&sk_to, format).unwrap(); println!("from = {}\nto = {}", from, to); } @@ -256,7 +336,7 @@ mod tests { "from": "5FnS6tYbCTAtK3QCfNnddwVR61ypLLM7APRrs98paFs7yMSY", "to": "5DoW9HHuqSfpf55Ux5pLdJbHFWvbngeg8Ynhub9DrdtxmZeV", "amount": 1000000000000, - "nonce": 0, + "nonce": 3, "tip": 0, "block_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", "genesis_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", @@ -264,7 +344,7 @@ mod tests { "tx_version": 24 }"#; - let mut tx = tx_from_str::(tx); + let mut tx = tx_from_str::(tx); let hash = tx.to_transaction_id().unwrap().txid; let msg = libsecp256k1::Message::parse_slice(&hash).unwrap(); @@ -279,7 +359,7 @@ mod tests { let rec = rec.serialize(); let signed_tx = tx.sign(sig, rec).unwrap(); - let signed_tx = hex::encode(&signed_tx); + let signed_tx = hex::encode(signed_tx); println!("signed tx = {}", signed_tx); } @@ -292,7 +372,7 @@ mod tests { "from": "5DPaKszR7KpCbvNNtGCGTfrGdeDTUNRt1UdxwXp9G6iWvdk7", "to": "5D1NKGqfc2Q8hw53icrX74YQryjb3MMySWwFBhM71afKbdad", "amount": 1000000000000, - "nonce": 2, + "nonce": 5, "tip": 0, "block_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", "genesis_hash": "e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e", @@ -300,8 +380,8 @@ mod tests { "tx_version": 24 }"#; - let mut tx = tx_from_str::(tx); - let msg = tx.to_bytes().unwrap(); + let mut tx = tx_from_str::(tx); + let msg = tx.to_bytes_ed25519().unwrap(); let sk = [ 228u8, 121, 108, 167, 244, 6, 57, 61, 104, 68, 229, 88, 23, 16, 212, 157, 110, 171, 36, @@ -310,15 +390,15 @@ mod tests { let sk = ed25519_dalek_fiat::SecretKey::from_bytes(&sk).unwrap(); let pk = ed25519_dalek_fiat::PublicKey::from(&sk); - let kp = ed25519_dalek_fiat::Keypair { secret: sk, public: pk, }; + let sig = kp.sign(&msg).to_bytes().to_vec(); - let signed_tx = tx.sign(sig, 0).unwrap(); - let signed_tx = hex::encode(&signed_tx); + let signed_tx = tx.sign_ed25519(sig).unwrap(); + let signed_tx = hex::encode(signed_tx); println!("signed tx = {}", signed_tx); }