mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 15:47:58 +00:00
Offchain signing (#5182)
* New approach to offchain signing. * Use in im-online * Rewrite to use Account<T> * DRY signing. * Implement send_raw_unsigned_transaction * WiP * Expunge LocalCall * Expunge LocalCall * Fix compilation. * Solve call. * Make it compile again. * Finalize implementation. * Change CreateTransaction * Clear CreateTransaction. * Add price payload * Send raw transaction * Submit signed payload / unsigned transaction (WIP) * Supertrait requirements on T::Signature * Validate signature of payload on an unsigned transaction * Fix encoding - part 1 * Make it compile. * Fix compilation of unsigned validator. * Pass price payload to the transaction * Make block number part of the signed payload * Send signed transaction * Implement all_accounts, any_account * Fix formatting * Implement submit_transaction * Submit signed transaction (ForAll, ForAny) * Fix formatting * Implement CreateSignedTransaction * Move sign and verify to AppCrypto * Sign transaction * Call `use_encoded` * Remove SubmitAndSignTransaction * Implement runtime using new SigningTypes * Adapt offchain example to changes * Fix im-online pallet * Quick fix: rename AuthorityId2 * Fix offchain example tests * Add a comment on why keystore is required in unsigned transaction test * Use UintAuthorityId instead of u64 * WIP * Remove IdentifyAccount from UintAuthorityId * Implement PublicWrapper type * Fix im-online tests * Fix runtime test * Bump spec version * Fix executor tests * Rename ImOnlineAuthId -> ImOnlineAuthorityId and formatting * Fix merge * Documentation * Revert u64 -> UintAuthorityId conversion * Fix string errors * Document public members in offchain module * Introduce SubmitTransaction * Update pallets to use SubmitTransaction * WIP * Use SubmitTransaction in offchain * Use `submit_unsigned_transaction` * Fix tests * Update docs * Remove SigningTypes requirement from `SendTransactionTypes` * Fix tests * Update frame/system/src/offchain.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/system/src/offchain.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/example-offchain-worker/src/tests.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/system/src/offchain.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/system/src/offchain.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Remove leftover from previous iterations * Change enum to struct * Remove public * Move mock to node/executor/tests * Cleanup test-helpers * Make `application-crypto` `std` feature internal The macros should not generate code that requires that the calling crate has a feature with the name `std` defined. * Revert cargo lock update * Use TestAuthorityId from common * Restore members of account to public * Tidy up imports * Fix benchmarking pallet * Add tests demonstrating ForAll, ForAny on signer * Move definition of AppCrypto in example-offchain-worker from tests to mod::crypto * Cleanup stray comment * Fix ValidTransaction * Re-fix CreateSignedTransaction * Address PR feedback * Add can_sign method to signer * Propagate error * Improve documentation * Fix vec! macro not available * Document SendTransactiontypes * Add some docs. * Split signing examples * Add tests for signing examples * WIP can_sign - PR feedback * WIP * Split for_any / for_all into different calls * Verify payload and signature in test * Fix can_sign implementation * Fix impl_version * Import Box from sp_std * Create issues for TODOs * Ignore doctest. * Add test directly to system. Adjust UintTypes. * Add some tests to account filtering. * Remove code samples and point to example offchain worker * Fix doc links * Fix im-online tests using signatures. Co-authored-by: Tomasz Drwięga <tomasz@parity.io> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -46,11 +46,10 @@ use sp_version::NativeVersion;
|
||||
use sp_core::OpaqueMetadata;
|
||||
use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
|
||||
use pallet_grandpa::fg_primitives;
|
||||
use pallet_im_online::sr25519::{AuthorityId as ImOnlineId};
|
||||
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
|
||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
|
||||
use pallet_contracts_rpc_runtime_api::ContractExecResult;
|
||||
use frame_system::offchain::TransactionSubmitter;
|
||||
use sp_inherents::{InherentData, CheckInherentsResult};
|
||||
|
||||
#[cfg(any(feature = "std", test))]
|
||||
@@ -60,6 +59,7 @@ pub use pallet_balances::Call as BalancesCall;
|
||||
pub use pallet_contracts::Gas;
|
||||
pub use frame_support::StorageValue;
|
||||
pub use pallet_staking::StakerStatus;
|
||||
use codec::Encode;
|
||||
|
||||
/// Implementations of some helper traits passed into runtime modules as associated types.
|
||||
pub mod impls;
|
||||
@@ -73,50 +73,6 @@ use constants::{time::*, currency::*};
|
||||
#[cfg(feature = "std")]
|
||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
|
||||
/// A transaction submitter with the given key type.
|
||||
pub type TransactionSubmitterOf<KeyType> = TransactionSubmitter<KeyType, Runtime, UncheckedExtrinsic>;
|
||||
|
||||
/// Submits transaction with the node's public and signature type. Adheres to the signed extension
|
||||
/// format of the chain.
|
||||
impl frame_system::offchain::CreateTransaction<Runtime, UncheckedExtrinsic> for Runtime {
|
||||
type Public = <Signature as traits::Verify>::Signer;
|
||||
type Signature = Signature;
|
||||
|
||||
fn create_transaction<TSigner: frame_system::offchain::Signer<Self::Public, Self::Signature>>(
|
||||
call: Call,
|
||||
public: Self::Public,
|
||||
account: AccountId,
|
||||
index: Index,
|
||||
) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
|
||||
// take the biggest period possible.
|
||||
let period = BlockHashCount::get()
|
||||
.checked_next_power_of_two()
|
||||
.map(|c| c / 2)
|
||||
.unwrap_or(2) as u64;
|
||||
let current_block = System::block_number()
|
||||
.saturated_into::<u64>()
|
||||
// The `System::block_number` is initialized with `n+1`,
|
||||
// so the actual block number is `n`.
|
||||
.saturating_sub(1);
|
||||
let tip = 0;
|
||||
let extra: SignedExtra = (
|
||||
frame_system::CheckVersion::<Runtime>::new(),
|
||||
frame_system::CheckGenesis::<Runtime>::new(),
|
||||
frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
|
||||
frame_system::CheckNonce::<Runtime>::from(index),
|
||||
frame_system::CheckWeight::<Runtime>::new(),
|
||||
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
|
||||
Default::default(),
|
||||
);
|
||||
let raw_payload = SignedPayload::new(call, extra).map_err(|e| {
|
||||
debug::warn!("Unable to create signed payload: {:?}", e);
|
||||
}).ok()?;
|
||||
let signature = TSigner::sign(public, &raw_payload)?;
|
||||
let address = Indices::unlookup(account);
|
||||
let (call, extra, _) = raw_payload.deconstruct();
|
||||
Some((call, (address, signature, extra)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime version.
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
@@ -127,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
// and set impl_version to 0. If only runtime
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 243,
|
||||
spec_version: 244,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
@@ -362,7 +318,6 @@ impl pallet_staking::Trait for Runtime {
|
||||
type NextNewSession = Session;
|
||||
type ElectionLookahead = ElectionLookahead;
|
||||
type Call = Call;
|
||||
type SubmitTransaction = TransactionSubmitterOf<()>;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type UnsignedPriority = StakingUnsignedPriority;
|
||||
}
|
||||
@@ -549,11 +504,63 @@ parameter_types! {
|
||||
pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2;
|
||||
}
|
||||
|
||||
|
||||
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime where
|
||||
Call: From<LocalCall>,
|
||||
{
|
||||
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
|
||||
call: Call,
|
||||
public: <Signature as traits::Verify>::Signer,
|
||||
account: AccountId,
|
||||
nonce: Index,
|
||||
) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
|
||||
// take the biggest period possible.
|
||||
let period = BlockHashCount::get()
|
||||
.checked_next_power_of_two()
|
||||
.map(|c| c / 2)
|
||||
.unwrap_or(2) as u64;
|
||||
let current_block = System::block_number()
|
||||
.saturated_into::<u64>()
|
||||
// The `System::block_number` is initialized with `n+1`,
|
||||
// so the actual block number is `n`.
|
||||
.saturating_sub(1);
|
||||
let tip = 0;
|
||||
let extra: SignedExtra = (
|
||||
frame_system::CheckVersion::<Runtime>::new(),
|
||||
frame_system::CheckGenesis::<Runtime>::new(),
|
||||
frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
|
||||
frame_system::CheckNonce::<Runtime>::from(nonce),
|
||||
frame_system::CheckWeight::<Runtime>::new(),
|
||||
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
|
||||
Default::default(),
|
||||
);
|
||||
let raw_payload = SignedPayload::new(call, extra).map_err(|e| {
|
||||
debug::warn!("Unable to create signed payload: {:?}", e);
|
||||
}).ok()?;
|
||||
let signature = raw_payload.using_encoded(|payload| {
|
||||
C::sign(payload, public)
|
||||
})?;
|
||||
let address = Indices::unlookup(account);
|
||||
let (call, extra, _) = raw_payload.deconstruct();
|
||||
Some((call, (address, signature.into(), extra)))
|
||||
}
|
||||
}
|
||||
|
||||
impl frame_system::offchain::SigningTypes for Runtime {
|
||||
type Public = <Signature as traits::Verify>::Signer;
|
||||
type Signature = Signature;
|
||||
}
|
||||
|
||||
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime where
|
||||
Call: From<C>,
|
||||
{
|
||||
type OverarchingCall = Call;
|
||||
type Extrinsic = UncheckedExtrinsic;
|
||||
}
|
||||
|
||||
impl pallet_im_online::Trait for Runtime {
|
||||
type AuthorityId = ImOnlineId;
|
||||
type Event = Event;
|
||||
type Call = Call;
|
||||
type SubmitTransaction = TransactionSubmitterOf<Self::AuthorityId>;
|
||||
type SessionDuration = SessionDuration;
|
||||
type ReportUnresponsiveness = Offences;
|
||||
type UnsignedPriority = ImOnlineUnsignedPriority;
|
||||
@@ -924,28 +931,14 @@ impl_runtime_apis! {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use frame_system::offchain::{SignAndSubmitTransaction, SubmitSignedTransaction};
|
||||
use frame_system::offchain::CreateSignedTransaction;
|
||||
|
||||
#[test]
|
||||
fn validate_transaction_submitter_bounds() {
|
||||
fn is_submit_signed_transaction<T>() where
|
||||
T: SubmitSignedTransaction<
|
||||
Runtime,
|
||||
Call,
|
||||
>,
|
||||
T: CreateSignedTransaction<Call>,
|
||||
{}
|
||||
|
||||
fn is_sign_and_submit_transaction<T>() where
|
||||
T: SignAndSubmitTransaction<
|
||||
Runtime,
|
||||
Call,
|
||||
Extrinsic=UncheckedExtrinsic,
|
||||
CreateTransaction=Runtime,
|
||||
Signer=ImOnlineId,
|
||||
>,
|
||||
{}
|
||||
|
||||
is_submit_signed_transaction::<TransactionSubmitterOf<ImOnlineId>>();
|
||||
is_sign_and_submit_transaction::<TransactionSubmitterOf<ImOnlineId>>();
|
||||
is_submit_signed_transaction::<Runtime>();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user