mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 18:37:59 +00:00
0e49ed72aa
* add serde_full feature flag add serde_full to sp_runtime add space to toml add serde_full to application-crypto add serde_full to arithmetic fix arithmetic add serde full to beefy add serde full to consensus add serde_full to core add serdefull to finality grandpa add serde_full to several primitives crates make rpc no_std compatible add scale info to runtime make serializer no_std compatible add serde full to storage add full serde to version add serde full to weights add all serde_full features add . to comment add missing impl-serde fix no-std build fix build add full_crypto to serde_full serde_full also implements crypto full_serde does not work with full_crytpo. needs std no no_std serde impl possible also for crypto std is necessary no serde full for application crypto fix arithmetic fix tomls fix some things impl fmt for Signature add serialize to Public add impl_maybe_marker_serde_full fix sp-application-crypto toml add serde feature flag fix clippy fix toml grandpa fix grandpa rename if_std to if_serde keystore is not no_std compatible make keystore vrf no_std compatible fix nopos-elections fix rpc fix serializer fix test-primitives fix version add comment add serde full only import for format string remove all(serde_full and full_crypot) as serde_full enforces full_crypto make comment better readable even better comment clean up rpc toml clean up toml clean up serializer toml clean up storage toml fix std build update .lock fix sp-version move sp_std import test extern crate alloc replace sp_std with core add missing core sp_core: serde feature do not enforce full crypto application-crypto: serde feature do not enforce full crypto rename serde_full to serde add dep:serde and alloc to default feature add full_crypto and remove unnecessary debu/fmt impls for serde update comment remove obolsete change in display AccountId32 remove extra changes minimize diff revert keystore changes remove std from keystore remove full-crypto feature fix serde import fix comment fix feature = serde * rename serde_full to serde * move #[doc(hidden)] back * remove feature = full crypto require frm MultiSigner * reorder serde and scale_info import * fix bs58 missing alloc import in serde feature * add `from_string` to serde feature and add unimplemented * remove serde feature from fixed_point display * Remove serde/alloc Co-authored-by: Davide Galassi <davxy@datawok.net> * Update primitives/consensus/babe/Cargo.toml Co-authored-by: Bastian Köcher <git@kchr.de> * Update primitives/arithmetic/src/fixed_point.rs Co-authored-by: Bastian Köcher <git@kchr.de> * revert `from_string`fixed impl back to std only * remove duplicate runtime string impl * use sp_std::alloc * remove no_std compatible rpc * remove no_std compatibility from serializer * rename mpl_maybe_marker_serde to std_or_serde * update .lock * add sp-std to executor * fix sp-std import * fix sp_std::format import * use crate import * add serde feature * Update primitives/core/src/lib.rs --------- Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: Bastian Köcher <git@kchr.de>
476 lines
16 KiB
Rust
476 lines
16 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Transaction validity interface.
|
|
|
|
use crate::{
|
|
codec::{Decode, Encode},
|
|
RuntimeDebug,
|
|
};
|
|
use scale_info::TypeInfo;
|
|
use sp_std::prelude::*;
|
|
|
|
/// Priority for a transaction. Additive. Higher is better.
|
|
pub type TransactionPriority = u64;
|
|
|
|
/// Minimum number of blocks a transaction will remain valid for.
|
|
/// `TransactionLongevity::max_value()` means "forever".
|
|
pub type TransactionLongevity = u64;
|
|
|
|
/// Tag for a transaction. No two transactions with the same tag should be placed on-chain.
|
|
pub type TransactionTag = Vec<u8>;
|
|
|
|
/// An invalid transaction validity.
|
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)]
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
pub enum InvalidTransaction {
|
|
/// The call of the transaction is not expected.
|
|
Call,
|
|
/// General error to do with the inability to pay some fees (e.g. account balance too low).
|
|
Payment,
|
|
/// General error to do with the transaction not yet being valid (e.g. nonce too high).
|
|
Future,
|
|
/// General error to do with the transaction being outdated (e.g. nonce too low).
|
|
Stale,
|
|
/// General error to do with the transaction's proofs (e.g. signature).
|
|
///
|
|
/// # Possible causes
|
|
///
|
|
/// When using a signed extension that provides additional data for signing, it is required
|
|
/// that the signing and the verifying side use the same additional data. Additional
|
|
/// data will only be used to generate the signature, but will not be part of the transaction
|
|
/// itself. As the verifying side does not know which additional data was used while signing
|
|
/// it will only be able to assume a bad signature and cannot express a more meaningful error.
|
|
BadProof,
|
|
/// The transaction birth block is ancient.
|
|
///
|
|
/// # Possible causes
|
|
///
|
|
/// For `FRAME`-based runtimes this would be caused by `current block number
|
|
/// - Era::birth block number > BlockHashCount`. (e.g. in Polkadot `BlockHashCount` = 2400, so
|
|
/// a
|
|
/// transaction with birth block number 1337 would be valid up until block number 1337 + 2400,
|
|
/// after which point the transaction would be considered to have an ancient birth block.)
|
|
AncientBirthBlock,
|
|
/// The transaction would exhaust the resources of current block.
|
|
///
|
|
/// The transaction might be valid, but there are not enough resources
|
|
/// left in the current block.
|
|
ExhaustsResources,
|
|
/// Any other custom invalid validity that is not covered by this enum.
|
|
Custom(u8),
|
|
/// An extrinsic with a Mandatory dispatch resulted in Error. This is indicative of either a
|
|
/// malicious validator or a buggy `provide_inherent`. In any case, it can result in
|
|
/// dangerously overweight blocks and therefore if found, invalidates the block.
|
|
BadMandatory,
|
|
/// An extrinsic with a mandatory dispatch tried to be validated.
|
|
/// This is invalid; only inherent extrinsics are allowed to have mandatory dispatches.
|
|
MandatoryValidation,
|
|
/// The sending address is disabled or known to be invalid.
|
|
BadSigner,
|
|
}
|
|
|
|
impl InvalidTransaction {
|
|
/// Returns if the reason for the invalidity was block resource exhaustion.
|
|
pub fn exhausted_resources(&self) -> bool {
|
|
matches!(self, Self::ExhaustsResources)
|
|
}
|
|
|
|
/// Returns if the reason for the invalidity was a mandatory call failing.
|
|
pub fn was_mandatory(&self) -> bool {
|
|
matches!(self, Self::BadMandatory)
|
|
}
|
|
}
|
|
|
|
impl From<InvalidTransaction> for &'static str {
|
|
fn from(invalid: InvalidTransaction) -> &'static str {
|
|
match invalid {
|
|
InvalidTransaction::Call => "Transaction call is not expected",
|
|
InvalidTransaction::Future => "Transaction will be valid in the future",
|
|
InvalidTransaction::Stale => "Transaction is outdated",
|
|
InvalidTransaction::BadProof => "Transaction has a bad signature",
|
|
InvalidTransaction::AncientBirthBlock => "Transaction has an ancient birth block",
|
|
InvalidTransaction::ExhaustsResources => "Transaction would exhaust the block limits",
|
|
InvalidTransaction::Payment =>
|
|
"Inability to pay some fees (e.g. account balance too low)",
|
|
InvalidTransaction::BadMandatory =>
|
|
"A call was labelled as mandatory, but resulted in an Error.",
|
|
InvalidTransaction::MandatoryValidation =>
|
|
"Transaction dispatch is mandatory; transactions must not be validated.",
|
|
InvalidTransaction::Custom(_) => "InvalidTransaction custom error",
|
|
InvalidTransaction::BadSigner => "Invalid signing address",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An unknown transaction validity.
|
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)]
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
pub enum UnknownTransaction {
|
|
/// Could not lookup some information that is required to validate the transaction.
|
|
CannotLookup,
|
|
/// No validator found for the given unsigned transaction.
|
|
NoUnsignedValidator,
|
|
/// Any other custom unknown validity that is not covered by this enum.
|
|
Custom(u8),
|
|
}
|
|
|
|
impl From<UnknownTransaction> for &'static str {
|
|
fn from(unknown: UnknownTransaction) -> &'static str {
|
|
match unknown {
|
|
UnknownTransaction::CannotLookup =>
|
|
"Could not lookup information required to validate the transaction",
|
|
UnknownTransaction::NoUnsignedValidator =>
|
|
"Could not find an unsigned validator for the unsigned transaction",
|
|
UnknownTransaction::Custom(_) => "UnknownTransaction custom error",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Errors that can occur while checking the validity of a transaction.
|
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)]
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
pub enum TransactionValidityError {
|
|
/// The transaction is invalid.
|
|
Invalid(InvalidTransaction),
|
|
/// Transaction validity can't be determined.
|
|
Unknown(UnknownTransaction),
|
|
}
|
|
|
|
impl TransactionValidityError {
|
|
/// Returns `true` if the reason for the error was block resource exhaustion.
|
|
pub fn exhausted_resources(&self) -> bool {
|
|
match self {
|
|
Self::Invalid(e) => e.exhausted_resources(),
|
|
Self::Unknown(_) => false,
|
|
}
|
|
}
|
|
|
|
/// Returns `true` if the reason for the error was it being a mandatory dispatch that could not
|
|
/// be completed successfully.
|
|
pub fn was_mandatory(&self) -> bool {
|
|
match self {
|
|
Self::Invalid(e) => e.was_mandatory(),
|
|
Self::Unknown(_) => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<TransactionValidityError> for &'static str {
|
|
fn from(err: TransactionValidityError) -> &'static str {
|
|
match err {
|
|
TransactionValidityError::Invalid(invalid) => invalid.into(),
|
|
TransactionValidityError::Unknown(unknown) => unknown.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<InvalidTransaction> for TransactionValidityError {
|
|
fn from(err: InvalidTransaction) -> Self {
|
|
TransactionValidityError::Invalid(err)
|
|
}
|
|
}
|
|
|
|
impl From<UnknownTransaction> for TransactionValidityError {
|
|
fn from(err: UnknownTransaction) -> Self {
|
|
TransactionValidityError::Unknown(err)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "std")]
|
|
impl std::error::Error for TransactionValidityError {
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "std")]
|
|
impl std::fmt::Display for TransactionValidityError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let s: &'static str = (*self).into();
|
|
write!(f, "{}", s)
|
|
}
|
|
}
|
|
|
|
/// Information on a transaction's validity and, if valid, on how it relates to other transactions.
|
|
pub type TransactionValidity = Result<ValidTransaction, TransactionValidityError>;
|
|
|
|
impl From<InvalidTransaction> for TransactionValidity {
|
|
fn from(invalid_transaction: InvalidTransaction) -> Self {
|
|
Err(TransactionValidityError::Invalid(invalid_transaction))
|
|
}
|
|
}
|
|
|
|
impl From<UnknownTransaction> for TransactionValidity {
|
|
fn from(unknown_transaction: UnknownTransaction) -> Self {
|
|
Err(TransactionValidityError::Unknown(unknown_transaction))
|
|
}
|
|
}
|
|
|
|
/// The source of the transaction.
|
|
///
|
|
/// Depending on the source we might apply different validation schemes.
|
|
/// For instance we can disallow specific kinds of transactions if they were not produced
|
|
/// by our local node (for instance off-chain workers).
|
|
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
|
|
pub enum TransactionSource {
|
|
/// Transaction is already included in block.
|
|
///
|
|
/// This means that we can't really tell where the transaction is coming from,
|
|
/// since it's already in the received block. Note that the custom validation logic
|
|
/// using either `Local` or `External` should most likely just allow `InBlock`
|
|
/// transactions as well.
|
|
InBlock,
|
|
|
|
/// Transaction is coming from a local source.
|
|
///
|
|
/// This means that the transaction was produced internally by the node
|
|
/// (for instance an Off-Chain Worker, or an Off-Chain Call), as opposed
|
|
/// to being received over the network.
|
|
Local,
|
|
|
|
/// Transaction has been received externally.
|
|
///
|
|
/// This means the transaction has been received from (usually) "untrusted" source,
|
|
/// for instance received over the network or RPC.
|
|
External,
|
|
}
|
|
|
|
/// Information concerning a valid transaction.
|
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
|
|
pub struct ValidTransaction {
|
|
/// Priority of the transaction.
|
|
///
|
|
/// Priority determines the ordering of two transactions that have all
|
|
/// their dependencies (required tags) satisfied.
|
|
pub priority: TransactionPriority,
|
|
/// Transaction dependencies
|
|
///
|
|
/// A non-empty list signifies that some other transactions which provide
|
|
/// given tags are required to be included before that one.
|
|
pub requires: Vec<TransactionTag>,
|
|
/// Provided tags
|
|
///
|
|
/// A list of tags this transaction provides. Successfully importing the transaction
|
|
/// will enable other transactions that depend on (require) those tags to be included as well.
|
|
/// Provided and required tags allow Substrate to build a dependency graph of transactions
|
|
/// and import them in the right (linear) order.
|
|
pub provides: Vec<TransactionTag>,
|
|
/// Transaction longevity
|
|
///
|
|
/// Longevity describes minimum number of blocks the validity is correct.
|
|
/// After this period transaction should be removed from the pool or revalidated.
|
|
pub longevity: TransactionLongevity,
|
|
/// A flag indicating if the transaction should be propagated to other peers.
|
|
///
|
|
/// By setting `false` here the transaction will still be considered for
|
|
/// including in blocks that are authored on the current node, but will
|
|
/// never be sent to other peers.
|
|
pub propagate: bool,
|
|
}
|
|
|
|
impl Default for ValidTransaction {
|
|
fn default() -> Self {
|
|
Self {
|
|
priority: 0,
|
|
requires: vec![],
|
|
provides: vec![],
|
|
longevity: TransactionLongevity::max_value(),
|
|
propagate: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ValidTransaction {
|
|
/// Initiate `ValidTransaction` builder object with a particular prefix for tags.
|
|
///
|
|
/// To avoid conflicts between different parts in runtime it's recommended to build `requires`
|
|
/// and `provides` tags with a unique prefix.
|
|
pub fn with_tag_prefix(prefix: &'static str) -> ValidTransactionBuilder {
|
|
ValidTransactionBuilder { prefix: Some(prefix), validity: Default::default() }
|
|
}
|
|
|
|
/// Combine two instances into one, as a best effort. This will take the superset of each of the
|
|
/// `provides` and `requires` tags, it will sum the priorities, take the minimum longevity and
|
|
/// the logic *And* of the propagate flags.
|
|
pub fn combine_with(mut self, mut other: ValidTransaction) -> Self {
|
|
Self {
|
|
priority: self.priority.saturating_add(other.priority),
|
|
requires: {
|
|
self.requires.append(&mut other.requires);
|
|
self.requires
|
|
},
|
|
provides: {
|
|
self.provides.append(&mut other.provides);
|
|
self.provides
|
|
},
|
|
longevity: self.longevity.min(other.longevity),
|
|
propagate: self.propagate && other.propagate,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// `ValidTransaction` builder.
|
|
///
|
|
///
|
|
/// Allows to easily construct `ValidTransaction` and most importantly takes care of
|
|
/// prefixing `requires` and `provides` tags to avoid conflicts.
|
|
#[derive(Default, Clone, RuntimeDebug)]
|
|
pub struct ValidTransactionBuilder {
|
|
prefix: Option<&'static str>,
|
|
validity: ValidTransaction,
|
|
}
|
|
|
|
impl ValidTransactionBuilder {
|
|
/// Set the priority of a transaction.
|
|
///
|
|
/// Note that the final priority for `FRAME` is combined from all `SignedExtension`s.
|
|
/// Most likely for unsigned transactions you want the priority to be higher
|
|
/// than for regular transactions. We recommend exposing a base priority for unsigned
|
|
/// transactions as a runtime module parameter, so that the runtime can tune inter-module
|
|
/// priorities.
|
|
pub fn priority(mut self, priority: TransactionPriority) -> Self {
|
|
self.validity.priority = priority;
|
|
self
|
|
}
|
|
|
|
/// Set the longevity of a transaction.
|
|
///
|
|
/// By default the transaction will be considered valid forever and will not be revalidated
|
|
/// by the transaction pool. It's recommended though to set the longevity to a finite value
|
|
/// though. If unsure, it's also reasonable to expose this parameter via module configuration
|
|
/// and let the runtime decide.
|
|
pub fn longevity(mut self, longevity: TransactionLongevity) -> Self {
|
|
self.validity.longevity = longevity;
|
|
self
|
|
}
|
|
|
|
/// Set the propagate flag.
|
|
///
|
|
/// Set to `false` if the transaction is not meant to be gossiped to peers. Combined with
|
|
/// `TransactionSource::Local` validation it can be used to have special kind of
|
|
/// transactions that are only produced and included by the validator nodes.
|
|
pub fn propagate(mut self, propagate: bool) -> Self {
|
|
self.validity.propagate = propagate;
|
|
self
|
|
}
|
|
|
|
/// Add a `TransactionTag` to the set of required tags.
|
|
///
|
|
/// The tag will be encoded and prefixed with module prefix (if any).
|
|
/// If you'd rather add a raw `require` tag, consider using `#combine_with` method.
|
|
pub fn and_requires(mut self, tag: impl Encode) -> Self {
|
|
self.validity.requires.push(match self.prefix.as_ref() {
|
|
Some(prefix) => (prefix, tag).encode(),
|
|
None => tag.encode(),
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Add a `TransactionTag` to the set of provided tags.
|
|
///
|
|
/// The tag will be encoded and prefixed with module prefix (if any).
|
|
/// If you'd rather add a raw `require` tag, consider using `#combine_with` method.
|
|
pub fn and_provides(mut self, tag: impl Encode) -> Self {
|
|
self.validity.provides.push(match self.prefix.as_ref() {
|
|
Some(prefix) => (prefix, tag).encode(),
|
|
None => tag.encode(),
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Augment the builder with existing `ValidTransaction`.
|
|
///
|
|
/// This method does add the prefix to `require` or `provides` tags.
|
|
pub fn combine_with(mut self, validity: ValidTransaction) -> Self {
|
|
self.validity = core::mem::take(&mut self.validity).combine_with(validity);
|
|
self
|
|
}
|
|
|
|
/// Finalize the builder and produce `TransactionValidity`.
|
|
///
|
|
/// Note the result will always be `Ok`. Use `Into` to produce `ValidTransaction`.
|
|
pub fn build(self) -> TransactionValidity {
|
|
self.into()
|
|
}
|
|
}
|
|
|
|
impl From<ValidTransactionBuilder> for TransactionValidity {
|
|
fn from(builder: ValidTransactionBuilder) -> Self {
|
|
Ok(builder.into())
|
|
}
|
|
}
|
|
|
|
impl From<ValidTransactionBuilder> for ValidTransaction {
|
|
fn from(builder: ValidTransactionBuilder) -> Self {
|
|
builder.validity
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn should_encode_and_decode() {
|
|
let v: TransactionValidity = Ok(ValidTransaction {
|
|
priority: 5,
|
|
requires: vec![vec![1, 2, 3, 4]],
|
|
provides: vec![vec![4, 5, 6]],
|
|
longevity: 42,
|
|
propagate: false,
|
|
});
|
|
|
|
let encoded = v.encode();
|
|
assert_eq!(
|
|
encoded,
|
|
vec![
|
|
0, 5, 0, 0, 0, 0, 0, 0, 0, 4, 16, 1, 2, 3, 4, 4, 12, 4, 5, 6, 42, 0, 0, 0, 0, 0, 0,
|
|
0, 0
|
|
]
|
|
);
|
|
|
|
// decode back
|
|
assert_eq!(TransactionValidity::decode(&mut &*encoded), Ok(v));
|
|
}
|
|
|
|
#[test]
|
|
fn builder_should_prefix_the_tags() {
|
|
const PREFIX: &str = "test";
|
|
let a: ValidTransaction = ValidTransaction::with_tag_prefix(PREFIX)
|
|
.and_requires(1)
|
|
.and_requires(2)
|
|
.and_provides(3)
|
|
.and_provides(4)
|
|
.propagate(false)
|
|
.longevity(5)
|
|
.priority(3)
|
|
.priority(6)
|
|
.into();
|
|
assert_eq!(
|
|
a,
|
|
ValidTransaction {
|
|
propagate: false,
|
|
longevity: 5,
|
|
priority: 6,
|
|
requires: vec![(PREFIX, 1).encode(), (PREFIX, 2).encode()],
|
|
provides: vec![(PREFIX, 3).encode(), (PREFIX, 4).encode()],
|
|
}
|
|
);
|
|
}
|
|
}
|