Unsigned Validation best practices (#5563)

* Configurable Unsigned Priority.

* Use the new builder.

* Fix tests.

* Fix benches.

* Remove unused import.

* Rename for_pallet
This commit is contained in:
Tomasz Drwięga
2020-04-08 11:17:21 +02:00
committed by GitHub
parent 571f1daa49
commit 762bcbab03
10 changed files with 194 additions and 26 deletions
@@ -53,9 +53,10 @@ use sp_runtime::{
traits::Zero,
transaction_validity::{
InvalidTransaction, ValidTransaction, TransactionValidity, TransactionSource,
TransactionPriority,
},
};
use sp_std::{vec, vec::Vec};
use sp_std::vec::Vec;
use lite_json::json::JsonValue;
#[cfg(test)]
@@ -106,6 +107,12 @@ pub trait Trait: frame_system::Trait {
///
/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval` blocks.
type UnsignedInterval: Get<Self::BlockNumber>;
/// A configuration for base priority of unsigned transactions.
///
/// This is exposed so that it can be tuned for particular runtime, when
/// multiple pallets send unsigned transactions.
type UnsignedPriority: Get<TransactionPriority>;
}
decl_storage! {
@@ -537,32 +544,33 @@ impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
.map(|price| if &price > new_price { price - new_price } else { new_price - price })
.unwrap_or(0);
Ok(ValidTransaction {
ValidTransaction::with_tag_prefix("ExampleOffchainWorker")
// We set base priority to 2**20 to make sure it's included before any other
// transactions in the pool. Next we tweak the priority depending on how much
// it differs from the current average. (the more it differs the more priority it
// has).
priority: (1 << 20) + avg_price as u64,
.priority(T::UnsignedPriority::get().saturating_add(avg_price as _))
// This transaction does not require anything else to go before into the pool.
// In theory we could require `previous_unsigned_at` transaction to go first,
// but it's not necessary in our case.
requires: vec![],
//.and_requires()
// We set the `provides` tag to be the same as `next_unsigned_at`. This makes
// sure only one transaction produced after `next_unsigned_at` will ever
// get to the transaction pool and will end up in the block.
// We can still have multiple transactions compete for the same "spot",
// and the one with higher priority will replace other one in the pool.
provides: vec![codec::Encode::encode(&(KEY_TYPE.0, next_unsigned_at))],
.and_provides(next_unsigned_at)
// The transaction is only valid for next 5 blocks. After that it's
// going to be revalidated by the pool.
longevity: 5,
.longevity(5)
// It's fine to propagate that transaction to other peers, which means it can be
// created even by nodes that don't produce blocks.
// Note that sometimes it's better to keep it for yourself (if you are the block
// producer), since for instance in some schemes others may copy your solution and
// claim a reward.
propagate: true,
})
.propagate(true)
.build()
} else {
InvalidTransaction::Call.into()
}