Various simplifications re: Serai transactions

Removes PairSigner for the pair directly.

Resets spec_version to 1.

Defines the extrinsic without its length prefix, only prefixing during publish.
This commit is contained in:
Luke Parker 2023-11-22 23:44:24 -05:00
parent c6cf33e370
commit 372149c2cc
No known key found for this signature in database
9 changed files with 36 additions and 67 deletions

View file

@ -40,6 +40,8 @@ impl<'a> SeraiInInstructions<'a> {
} }
pub fn execute_batch(batch: SignedBatch) -> Vec<u8> { pub fn execute_batch(batch: SignedBatch) -> Vec<u8> {
Serai::unsigned::<InInstructions, _>(&in_instructions::Call::<Runtime>::execute_batch { batch }) Serai::unsigned(&serai_runtime::RuntimeCall::InInstructions(
in_instructions::Call::<Runtime>::execute_batch { batch },
))
} }
} }

View file

@ -13,7 +13,6 @@ pub use sp_core::{
sr25519::{Public, Pair}, sr25519::{Public, Pair},
}; };
pub use subxt;
use subxt::{ use subxt::{
error::Error as SubxtError, error::Error as SubxtError,
config::{ config::{
@ -21,7 +20,6 @@ use subxt::{
substrate::{BlakeTwo256, SubstrateHeader}, substrate::{BlakeTwo256, SubstrateHeader},
extrinsic_params::BaseExtrinsicParams, extrinsic_params::BaseExtrinsicParams,
}, },
tx::Signer,
rpc::types::{ChainBlock, ChainBlockExtrinsic}, rpc::types::{ChainBlock, ChainBlockExtrinsic},
Config as SubxtConfig, OnlineClient, Config as SubxtConfig, OnlineClient,
}; };
@ -150,41 +148,32 @@ impl Serai {
Ok(Serai(OnlineClient::<SeraiConfig>::from_url(url).await.map_err(SeraiError::RpcError)?)) Ok(Serai(OnlineClient::<SeraiConfig>::from_url(url).await.map_err(SeraiError::RpcError)?))
} }
fn unsigned<P: 'static, C: Encode>(call: &C) -> Vec<u8> { fn unsigned(call: &serai_runtime::RuntimeCall) -> Vec<u8> {
// TODO: Should Serai purge the old transaction code AND set this to 0/1? // TODO: Should Serai purge the old transaction code AND set this to 0/1?
const TRANSACTION_VERSION: u8 = 4; const EXTRINSIC_FORMAT_VERSION: u8 = 4;
// Protocol version let mut bytes = vec![EXTRINSIC_FORMAT_VERSION];
let mut bytes = vec![TRANSACTION_VERSION];
// Pallet index
bytes.push(u8::try_from(PalletInfo::index::<P>().unwrap()).unwrap());
// Call
bytes.extend(call.encode()); bytes.extend(call.encode());
bytes
// Prefix the length
let mut complete_bytes = Compact(u32::try_from(bytes.len()).unwrap()).encode();
complete_bytes.extend(bytes);
complete_bytes
} }
pub fn sign<S: Send + Sync + Signer<SeraiConfig>>( pub fn sign(
&self, &self,
signer: &S, signer: &Pair,
call: &serai_runtime::RuntimeCall, call: &serai_runtime::RuntimeCall,
nonce: u32, nonce: u32,
tip: Tip, tip: Tip,
) -> Vec<u8> { ) -> Vec<u8> {
const SPEC_VERSION: u32 = 100; const SPEC_VERSION: u32 = 1;
const IMPL_VERSION: u32 = 1; const TX_VERSION: u32 = 1;
const TRANSACTION_VERSION: u8 = 4; const EXTRINSIC_FORMAT_VERSION: u8 = 4;
let era = subxt::config::substrate::Era::Immortal; let era = subxt::config::substrate::Era::Immortal;
let extra = (era, Compact(nonce), tip); let extra = (era, Compact(nonce), tip);
let genesis = self.0.genesis_hash(); let genesis = self.0.genesis_hash();
let mortality_checkpoint = genesis; let mortality_checkpoint = genesis;
let mut signature_payload = let mut signature_payload =
(call, extra, SPEC_VERSION, IMPL_VERSION, genesis, mortality_checkpoint).encode(); (call, extra, SPEC_VERSION, TX_VERSION, genesis, mortality_checkpoint).encode();
if signature_payload.len() > 256 { if signature_payload.len() > 256 {
use subxt::config::Hasher; use subxt::config::Hasher;
signature_payload = BlakeTwo256::hash(&signature_payload).0.to_vec(); signature_payload = BlakeTwo256::hash(&signature_payload).0.to_vec();
@ -192,19 +181,20 @@ impl Serai {
let signature = signer.sign(&signature_payload); let signature = signer.sign(&signature_payload);
let signed = 1 << 7; let signed = 1 << 7;
let extrinsic = (signed + EXTRINSIC_FORMAT_VERSION, signer.public(), signature, extra, call).encode()
(signed + TRANSACTION_VERSION, signer.address(), signature, extra, call).encode();
let mut res = Compact(u32::try_from(extrinsic.len()).unwrap()).encode();
res.extend(&extrinsic);
res
} }
pub async fn publish(&self, tx: &[u8]) -> Result<(), SeraiError> { pub async fn publish(&self, tx: &[u8]) -> Result<(), SeraiError> {
let mut length_prefixed = Compact(u32::try_from(tx.len()).unwrap()).encode();
length_prefixed.extend(tx);
self self
.0 .0
.rpc() .rpc()
.deref() .deref()
.request::<String>("author_submitExtrinsic", subxt::rpc::rpc_params![hex::encode(tx)]) .request::<String>(
"author_submitExtrinsic",
subxt::rpc::rpc_params![hex::encode(length_prefixed)],
)
.await .await
// Drop the hash, which is the hash of the raw extrinsic, as extrinsics are allowed to share // Drop the hash, which is the hash of the raw extrinsic, as extrinsics are allowed to share
// hashes and this hash is accordingly useless/unsafe // hashes and this hash is accordingly useless/unsafe
@ -386,23 +376,3 @@ impl<'a> TemporalSerai<'a> {
SeraiValidatorSets(self) SeraiValidatorSets(self)
} }
} }
#[derive(Clone)]
pub struct PairSigner(Pair, <SeraiConfig as SubxtConfig>::AccountId);
impl PairSigner {
pub fn new(pair: Pair) -> Self {
let id = pair.public();
PairSigner(pair, id)
}
}
impl Signer<SeraiConfig> for PairSigner {
fn account_id(&self) -> &<SeraiConfig as SubxtConfig>::AccountId {
&self.1
}
fn address(&self) -> <SeraiConfig as SubxtConfig>::Address {
self.1.into()
}
fn sign(&self, payload: &[u8]) -> <SeraiConfig as SubxtConfig>::Signature {
self.0.sign(payload)
}
}

View file

@ -81,10 +81,8 @@ impl<'a> SeraiValidatorSets<'a> {
} }
pub fn set_keys(network: NetworkId, key_pair: KeyPair, signature: Signature) -> Vec<u8> { pub fn set_keys(network: NetworkId, key_pair: KeyPair, signature: Signature) -> Vec<u8> {
Serai::unsigned::<ValidatorSets, _>(&validator_sets::Call::<Runtime>::set_keys { Serai::unsigned(&serai_runtime::RuntimeCall::ValidatorSets(
network, validator_sets::Call::<Runtime>::set_keys { network, key_pair, signature },
key_pair, ))
signature,
})
} }
} }

View file

@ -20,7 +20,7 @@ use serai_client::{
primitives::{InInstruction, InInstructionWithBalance, Batch}, primitives::{InInstruction, InInstructionWithBalance, Batch},
}, },
coins::{primitives::OutInstruction, CoinsEvent}, coins::{primitives::OutInstruction, CoinsEvent},
PairSigner, Serai, SeraiCoins, Serai, SeraiCoins,
}; };
mod common; mod common;
@ -91,7 +91,7 @@ serai_test!(
serai, serai,
&serai &serai
.sign( .sign(
&PairSigner::new(pair), &pair,
&SeraiCoins::burn_with_instruction(instruction.clone()), &SeraiCoins::burn_with_instruction(instruction.clone()),
0, 0,
Default::default(), Default::default(),

View file

@ -1,6 +1,6 @@
use serai_runtime::primitives::{Coin, Amount}; use serai_runtime::primitives::{Coin, Amount};
use serai_client::{Serai, SeraiDex, PairSigner}; use serai_client::{Serai, SeraiDex};
use sp_core::{sr25519::Pair, Pair as PairTrait}; use sp_core::{sr25519::Pair, Pair as PairTrait};
use crate::common::tx::publish_tx; use crate::common::tx::publish_tx;
@ -17,7 +17,7 @@ pub async fn add_liquidity(
let address = pair.public(); let address = pair.public();
let tx = serai.sign( let tx = serai.sign(
&PairSigner::new(pair), &pair,
&SeraiDex::add_liquidity(coin, coin_amount, sri_amount, Amount(1), Amount(1), address.into()), &SeraiDex::add_liquidity(coin, coin_amount, sri_amount, Amount(1), Amount(1), address.into()),
nonce, nonce,
Default::default(), Default::default(),
@ -39,7 +39,7 @@ pub async fn swap(
let address = pair.public(); let address = pair.public();
let tx = serai.sign( let tx = serai.sign(
&PairSigner::new(pair), &pair,
&SeraiDex::swap(from_coin, to_coin, amount_in, amount_out_min, address.into()), &SeraiDex::swap(from_coin, to_coin, amount_in, amount_out_min, address.into()),
nonce, nonce,
Default::default(), Default::default(),

View file

@ -34,7 +34,7 @@ pub async fn publish_tx(serai: &Serai, tx: &[u8]) -> [u8; 32] {
}; };
for transaction in block.transactions() { for transaction in block.transactions() {
if transaction.0 == tx[2 ..] { if transaction.0 == tx {
return block.hash(); return block.hash();
} }
} }

View file

@ -88,8 +88,7 @@ pub mod opaque {
pub const VERSION: RuntimeVersion = RuntimeVersion { pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("serai"), spec_name: create_runtime_str!("serai"),
impl_name: create_runtime_str!("core"), impl_name: create_runtime_str!("core"),
// TODO: 1? Do we prefer some level of compatibility or our own path? spec_version: 1,
spec_version: 100,
impl_version: 1, impl_version: 1,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
transaction_version: 1, transaction_version: 1,

View file

@ -12,7 +12,7 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Secp256k1};
use dkg::Participant; use dkg::Participant;
use serai_client::{ use serai_client::{
PairTrait, PairSigner, PairTrait,
primitives::{ primitives::{
NetworkId, Coin, Amount, Balance, BlockHash, SeraiAddress, ExternalAddress, NetworkId, Coin, Amount, Balance, BlockHash, SeraiAddress, ExternalAddress,
insecure_pair_from_name, insecure_pair_from_name,
@ -211,7 +211,7 @@ async fn sign_test() {
let balance = Balance { coin: Coin::Serai, amount: Amount(1_000_000_000) }; let balance = Balance { coin: Coin::Serai, amount: Amount(1_000_000_000) };
serai serai
.publish(&serai.sign( .publish(&serai.sign(
&PairSigner::new(insecure_pair_from_name("Ferdie")), &insecure_pair_from_name("Ferdie"),
&SeraiCoins::transfer(address, balance), &SeraiCoins::transfer(address, balance),
0, 0,
Default::default(), Default::default(),
@ -219,7 +219,7 @@ async fn sign_test() {
.await .await
.unwrap(); .unwrap();
(PairSigner::new(pair), address) (pair, address)
}; };
#[allow(clippy::inconsistent_digit_grouping)] #[allow(clippy::inconsistent_digit_grouping)]

View file

@ -16,7 +16,7 @@ use serai_client::{
validator_sets::primitives::{Session, ValidatorSet}, validator_sets::primitives::{Session, ValidatorSet},
in_instructions::primitives::Shorthand, in_instructions::primitives::Shorthand,
coins::primitives::{OutInstruction, OutInstructionWithBalance}, coins::primitives::{OutInstruction, OutInstructionWithBalance},
PairTrait, PairSigner, SeraiCoins, PairTrait, SeraiCoins,
}; };
use crate::tests::*; use crate::tests::*;
@ -249,7 +249,7 @@ async fn mint_and_burn_test() {
let balance = Balance { coin: Coin::Serai, amount: Amount(1_000_000_000) }; let balance = Balance { coin: Coin::Serai, amount: Amount(1_000_000_000) };
serai serai
.publish(&serai.sign( .publish(&serai.sign(
&PairSigner::new(insecure_pair_from_name("Ferdie")), &insecure_pair_from_name("Ferdie"),
&SeraiCoins::transfer(address, balance), &SeraiCoins::transfer(address, balance),
0, 0,
Default::default(), Default::default(),
@ -257,7 +257,7 @@ async fn mint_and_burn_test() {
.await .await
.unwrap(); .unwrap();
(PairSigner::new(pair), address) (pair, address)
}; };
// Send in BTC // Send in BTC