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] 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); }