Pass transaction source to validate_transaction (#5366)

* WiP

* Support source in the runtime API.

* Finish implementation in txpool.

* Fix warning.

* Fix tests.

* Apply suggestions from code review

Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-Authored-By: Nikolay Volf <nikvolf@gmail.com>

* Extra changes.

* Fix test and benches.

* fix test

* Fix test & benches again.

* Fix tests.

* Update bumpalo

* Fix doc test.

* Fix doctest.

* Fix doctest.

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
This commit is contained in:
Tomasz Drwięga
2020-03-25 14:09:23 +01:00
committed by GitHub
parent 601ac11e52
commit 04ccb179e9
37 changed files with 414 additions and 163 deletions
@@ -21,7 +21,7 @@ use crate::traits::{
self, Member, MaybeDisplay, SignedExtension, Dispatchable,
};
use crate::traits::ValidateUnsigned;
use crate::transaction_validity::TransactionValidity;
use crate::transaction_validity::{TransactionValidity, TransactionSource};
/// Definition of something that the external world might want to say; its
/// existence implies that it has been checked and is good, particularly with
@@ -50,6 +50,9 @@ where
fn validate<U: ValidateUnsigned<Call = Self::Call>>(
&self,
// TODO [#5006;ToDr] should source be passed to `SignedExtension`s?
// Perhaps a change for 2.0 to avoid breaking too much APIs?
source: TransactionSource,
info: Self::DispatchInfo,
len: usize,
) -> TransactionValidity {
@@ -57,7 +60,7 @@ where
Extra::validate(extra, id, &self.function, info.clone(), len)
} else {
let valid = Extra::validate_unsigned(&self.function, info, len)?;
let unsigned_validation = U::validate_unsigned(&self.function)?;
let unsigned_validation = U::validate_unsigned(source, &self.function)?;
Ok(valid.combine_with(unsigned_validation))
}
}
+2 -1
View File
@@ -27,7 +27,7 @@ use crate::traits::ValidateUnsigned;
use crate::{generic, KeyTypeId, ApplyExtrinsicResult};
pub use sp_core::{H256, sr25519};
use sp_core::{crypto::{CryptoType, Dummy, key_types, Public}, U256};
use crate::transaction_validity::{TransactionValidity, TransactionValidityError};
use crate::transaction_validity::{TransactionValidity, TransactionValidityError, TransactionSource};
/// Authority Id
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize, PartialOrd, Ord)]
@@ -357,6 +357,7 @@ impl<Origin, Call, Extra, Info> Applyable for TestXt<Call, Extra> where
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
fn validate<U: ValidateUnsigned<Call=Self::Call>>(
&self,
_source: TransactionSource,
_info: Self::DispatchInfo,
_len: usize,
) -> TransactionValidity {
+5 -3
View File
@@ -28,7 +28,8 @@ use serde::{Serialize, Deserialize, de::DeserializeOwned};
use sp_core::{self, Hasher, TypeId, RuntimeDebug};
use crate::codec::{Codec, Encode, Decode};
use crate::transaction_validity::{
ValidTransaction, TransactionValidity, TransactionValidityError, UnknownTransaction,
ValidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
UnknownTransaction,
};
use crate::generic::{Digest, DigestItem};
pub use sp_arithmetic::traits::{
@@ -851,6 +852,7 @@ pub trait Applyable: Sized + Send + Sync {
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
fn validate<V: ValidateUnsigned<Call=Self::Call>>(
&self,
source: TransactionSource,
info: Self::DispatchInfo,
len: usize,
) -> TransactionValidity;
@@ -897,7 +899,7 @@ pub trait ValidateUnsigned {
///
/// Changes made to storage WILL be persisted if the call returns `Ok`.
fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
Self::validate_unsigned(call)
Self::validate_unsigned(TransactionSource::InBlock, call)
.map(|_| ())
.map_err(Into::into)
}
@@ -908,7 +910,7 @@ pub trait ValidateUnsigned {
/// whether the transaction would panic if it were included or not.
///
/// Changes made to storage should be discarded by caller.
fn validate_unsigned(call: &Self::Call) -> TransactionValidity;
fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity;
}
/// Opaque data type that may be destructured into a series of raw byte slices (which represent
@@ -161,6 +161,35 @@ impl Into<TransactionValidity> for UnknownTransaction {
}
}
/// 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, parity_util_mem::MallocSizeOf)]
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)]
pub struct ValidTransaction {
@@ -29,5 +29,5 @@ mod pool;
pub use pool::*;
pub use sp_runtime::transaction_validity::{
TransactionLongevity, TransactionPriority, TransactionTag,
TransactionLongevity, TransactionPriority, TransactionTag, TransactionSource,
};
@@ -31,7 +31,7 @@ use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Member, NumberFor},
transaction_validity::{
TransactionLongevity, TransactionPriority, TransactionTag,
TransactionLongevity, TransactionPriority, TransactionTag, TransactionSource,
},
};
@@ -192,6 +192,7 @@ pub trait TransactionPool: Send + Sync {
fn submit_at(
&self,
at: &BlockId<Self::Block>,
source: TransactionSource,
xts: Vec<TransactionFor<Self>>,
) -> PoolFuture<Vec<Result<TxHash<Self>, Self::Error>>, Self::Error>;
@@ -199,6 +200,7 @@ pub trait TransactionPool: Send + Sync {
fn submit_one(
&self,
at: &BlockId<Self::Block>,
source: TransactionSource,
xt: TransactionFor<Self>,
) -> PoolFuture<TxHash<Self>, Self::Error>;
@@ -206,6 +208,7 @@ pub trait TransactionPool: Send + Sync {
fn submit_and_watch(
&self,
at: &BlockId<Self::Block>,
source: TransactionSource,
xt: TransactionFor<Self>,
) -> PoolFuture<Box<TransactionStatusStreamFor<Self>>, Self::Error>;
@@ -299,7 +302,9 @@ impl<TPool: TransactionPool> OffchainSubmitTransaction<TPool::Block> for TPool {
extrinsic
);
let result = futures::executor::block_on(self.submit_one(&at, extrinsic));
let result = futures::executor::block_on(self.submit_one(
&at, TransactionSource::Local, extrinsic,
));
result.map(|_| ())
.map_err(|e| log::warn!(
@@ -16,13 +16,27 @@
//! Tagged Transaction Queue Runtime API.
use sp_runtime::transaction_validity::TransactionValidity;
use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource};
use sp_runtime::traits::Block as BlockT;
sp_api::decl_runtime_apis! {
/// The `TaggedTransactionQueue` api trait for interfering with the transaction queue.
#[api_version(2)]
pub trait TaggedTransactionQueue {
/// Validate the given transaction.
/// Validate the transaction.
#[changed_in(2)]
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
/// Validate the transaction.
///
/// This method is invoked by the transaction pool to learn details about given transaction.
/// The implementation should make sure to verify the correctness of the transaction
/// against current state.
/// Note that this call may be performed by the pool multiple times and transactions
/// might be verified in any possible order.
fn validate_transaction(
source: TransactionSource,
tx: <Block as BlockT>::Extrinsic,
) -> TransactionValidity;
}
}