mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-07 03:47:22 +00:00
8d0ae856b0
* Some initial work on RPC and client * Rephrase as params * More work on traitifying substrate. * Traitify in_mem.rs * traitify client.rs * Make new primitives (mainly traits) build again. * Many (superficial) build fixes throughout. * Fix remaining build issues up to bft interface. * Make bft primitives be generic. * Switch out MisBehaviorReport for generic version. * Merge Hashing into Header. * Update runtime for new generics (with Hashing). * Update demo runtime. * Make runtime compile. * Build fixes for runtime * Remove old modules. * port substrate-bft to use generic substrate types * port client * port substrate-test-runtime * mostly port test-runtime to get compiling for std * Ensure `AccountId` has a `Default`. * Fix type deps. * finish porting * initialize test_runtime from genesis correctly * remove commented code * maybe unsigned signatures * runtimes compile * port over most of network * serialization for generic types * fix comment * remove some unnecessary trait bounds * network compiles * tests compile for sync * fix deserialization * temporarily remove deserialize derives * workarounds for serde issues for deriving deserialization * get demo-runtime compiling on std * port extrinsic-pool * primitives reshuffling * get network compiling again * remove debugging file * runtime tests now passing * port client-db * start to port over substrate-rpc * mostly port over PolkadotApi * test_runtime follows normal conventions * substrate runtime tests pass * deal with inherent extrinsics correctly in polkadot-api * port transaction-pool * port polkadot-consensus * port substrate-rpc * everything compiles * tests compile * fix grumbles * test-runtime uses its own transfer type * switch to master branch of jsonrpc * fix network tests and some warnings * all tests pass locally * [ci-skip] add another comment about issue * remove some curlies
282 lines
7.8 KiB
Rust
282 lines
7.8 KiB
Rust
// Copyright 2018 Parity Technologies (UK) Ltd.
|
|
// This file is part of Polkadot.
|
|
|
|
// Polkadot is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Polkadot is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
extern crate ed25519;
|
|
extern crate substrate_codec as codec;
|
|
extern crate substrate_extrinsic_pool as extrinsic_pool;
|
|
extern crate substrate_primitives as substrate_primitives;
|
|
extern crate substrate_runtime_primitives;
|
|
extern crate polkadot_runtime as runtime;
|
|
extern crate polkadot_primitives as primitives;
|
|
extern crate polkadot_api;
|
|
|
|
#[macro_use]
|
|
extern crate error_chain;
|
|
|
|
#[macro_use]
|
|
extern crate log;
|
|
|
|
mod error;
|
|
|
|
use std::{
|
|
cmp::Ordering,
|
|
collections::HashMap,
|
|
ops::Deref,
|
|
sync::Arc,
|
|
};
|
|
|
|
use codec::Slicable;
|
|
use extrinsic_pool::{Pool, txpool::{self, Readiness, scoring::{Change, Choice}}};
|
|
use extrinsic_pool::api::ExtrinsicPool;
|
|
use polkadot_api::PolkadotApi;
|
|
use primitives::{AccountId, Hash, UncheckedExtrinsic as FutureProofUncheckedExtrinsic};
|
|
use runtime::UncheckedExtrinsic;
|
|
use substrate_runtime_primitives::traits::{Bounded, Checkable, BlakeTwo256, Hashing};
|
|
|
|
pub use extrinsic_pool::txpool::{Options, Status, LightStatus, VerifiedTransaction as VerifiedTransactionOps};
|
|
pub use error::{Error, ErrorKind, Result};
|
|
|
|
/// Type alias for convenience.
|
|
pub type CheckedExtrinsic = <UncheckedExtrinsic as Checkable>::Checked;
|
|
|
|
/// A verified transaction which should be includable and non-inherent.
|
|
#[derive(Debug, Clone)]
|
|
pub struct VerifiedTransaction {
|
|
inner: CheckedExtrinsic,
|
|
hash: Hash,
|
|
encoded_size: usize,
|
|
}
|
|
|
|
impl VerifiedTransaction {
|
|
/// Attempt to verify a transaction.
|
|
fn create(xt: UncheckedExtrinsic) -> Result<Self> {
|
|
if !xt.is_signed() {
|
|
bail!(ErrorKind::IsInherent(xt))
|
|
}
|
|
|
|
let message = Slicable::encode(&xt);
|
|
match xt.check() {
|
|
Ok(xt) => {
|
|
let hash = BlakeTwo256::hash(&message);
|
|
Ok(VerifiedTransaction {
|
|
inner: xt,
|
|
hash: hash.into(),
|
|
encoded_size: message.len(),
|
|
})
|
|
}
|
|
Err(xt) => Err(ErrorKind::BadSignature(xt).into()),
|
|
}
|
|
}
|
|
|
|
/// Access the underlying transaction.
|
|
pub fn as_transaction(&self) -> &UncheckedExtrinsic {
|
|
self.as_ref().as_unchecked()
|
|
}
|
|
|
|
/// Convert to primitive unchecked extrinsic.
|
|
pub fn primitive_extrinsic(&self) -> ::primitives::UncheckedExtrinsic {
|
|
Slicable::decode(&mut self.as_transaction().encode().as_slice())
|
|
.expect("UncheckedExtrinsic shares repr with Vec<u8>; qed")
|
|
}
|
|
|
|
/// Consume the verified transaciton, yielding the unchecked counterpart.
|
|
pub fn into_inner(self) -> CheckedExtrinsic {
|
|
self.inner
|
|
}
|
|
|
|
/// Get the 256-bit hash of this transaction.
|
|
pub fn hash(&self) -> &Hash {
|
|
&self.hash
|
|
}
|
|
|
|
/// Get the account ID of the sender of this transaction.
|
|
pub fn sender(&self) -> &AccountId {
|
|
&self.inner.signed
|
|
}
|
|
|
|
/// Get encoded size of the transaction.
|
|
pub fn encoded_size(&self) -> usize {
|
|
self.encoded_size
|
|
}
|
|
}
|
|
|
|
impl AsRef<CheckedExtrinsic> for VerifiedTransaction {
|
|
fn as_ref(&self) -> &CheckedExtrinsic {
|
|
&self.inner
|
|
}
|
|
}
|
|
|
|
impl txpool::VerifiedTransaction for VerifiedTransaction {
|
|
type Hash = Hash;
|
|
type Sender = AccountId;
|
|
|
|
fn hash(&self) -> &Self::Hash {
|
|
&self.hash
|
|
}
|
|
|
|
fn sender(&self) -> &Self::Sender {
|
|
&self.inner.signed
|
|
}
|
|
|
|
fn mem_usage(&self) -> usize {
|
|
1 // TODO
|
|
}
|
|
}
|
|
|
|
/// Scoring implementation for polkadot transactions.
|
|
#[derive(Debug)]
|
|
pub struct Scoring;
|
|
|
|
impl txpool::Scoring<VerifiedTransaction> for Scoring {
|
|
type Score = u64;
|
|
type Event = ();
|
|
|
|
fn compare(&self, old: &VerifiedTransaction, other: &VerifiedTransaction) -> Ordering {
|
|
old.inner.index.cmp(&other.inner.index)
|
|
}
|
|
|
|
fn choose(&self, _old: &VerifiedTransaction, _new: &VerifiedTransaction) -> Choice {
|
|
Choice::InsertNew
|
|
}
|
|
|
|
fn update_scores(
|
|
&self,
|
|
xts: &[txpool::Transaction<VerifiedTransaction>],
|
|
scores: &mut [Self::Score],
|
|
_change: Change<()>
|
|
) {
|
|
for i in 0..xts.len() {
|
|
// all the same score since there are no fees.
|
|
// TODO: prioritize things like misbehavior or fishermen reports
|
|
scores[i] = 1;
|
|
}
|
|
}
|
|
fn should_replace(&self, _old: &VerifiedTransaction, _new: &VerifiedTransaction) -> bool {
|
|
false // no fees to determine which is better.
|
|
}
|
|
}
|
|
|
|
/// Readiness evaluator for polkadot transactions.
|
|
pub struct Ready<'a, T: 'a + PolkadotApi> {
|
|
at_block: T::CheckedBlockId,
|
|
api: &'a T,
|
|
known_indices: HashMap<AccountId, ::primitives::Index>,
|
|
}
|
|
|
|
impl<'a, T: 'a + PolkadotApi> Clone for Ready<'a, T> {
|
|
fn clone(&self) -> Self {
|
|
Ready {
|
|
at_block: self.at_block.clone(),
|
|
api: self.api,
|
|
known_indices: self.known_indices.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T: 'a + PolkadotApi> Ready<'a, T> {
|
|
/// Create a new readiness evaluator at the given block. Requires that
|
|
/// the ID has already been checked for local corresponding and available state.
|
|
pub fn create(at: T::CheckedBlockId, api: &'a T) -> Self {
|
|
Ready {
|
|
at_block: at,
|
|
api,
|
|
known_indices: HashMap::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T: 'a + PolkadotApi> txpool::Ready<VerifiedTransaction> for Ready<'a, T> {
|
|
fn is_ready(&mut self, xt: &VerifiedTransaction) -> Readiness {
|
|
let sender = xt.inner.signed;
|
|
trace!(target: "transaction-pool", "Checking readiness of {} (from {})", xt.hash, Hash::from(sender));
|
|
|
|
// TODO: find a way to handle index error properly -- will need changes to
|
|
// transaction-pool trait.
|
|
let (api, at_block) = (&self.api, &self.at_block);
|
|
let next_index = self.known_indices.entry(sender)
|
|
.or_insert_with(|| api.index(at_block, sender).ok().unwrap_or_else(Bounded::max_value));
|
|
|
|
trace!(target: "transaction-pool", "Next index for sender is {}; xt index is {}", next_index, xt.inner.index);
|
|
|
|
let result = match xt.inner.index.cmp(&next_index) {
|
|
Ordering::Greater => Readiness::Future,
|
|
Ordering::Equal => Readiness::Ready,
|
|
Ordering::Less => Readiness::Stale,
|
|
};
|
|
|
|
// remember to increment `next_index`
|
|
*next_index = next_index.saturating_add(1);
|
|
|
|
result
|
|
}
|
|
}
|
|
|
|
pub struct Verifier;
|
|
|
|
impl txpool::Verifier<UncheckedExtrinsic> for Verifier {
|
|
type VerifiedTransaction = VerifiedTransaction;
|
|
type Error = Error;
|
|
|
|
fn verify_transaction(&self, uxt: UncheckedExtrinsic) -> Result<Self::VerifiedTransaction> {
|
|
info!("Extrinsic Submitted: {:?}", uxt);
|
|
VerifiedTransaction::create(uxt)
|
|
}
|
|
}
|
|
|
|
/// The polkadot transaction pool.
|
|
///
|
|
/// Wraps a `extrinsic_pool::Pool`.
|
|
pub struct TransactionPool {
|
|
inner: Pool<UncheckedExtrinsic, Hash, Verifier, Scoring, Error>,
|
|
}
|
|
|
|
impl TransactionPool {
|
|
/// Create a new transaction pool.
|
|
pub fn new(options: Options) -> Self {
|
|
TransactionPool {
|
|
inner: Pool::new(options, Verifier, Scoring),
|
|
}
|
|
}
|
|
|
|
pub fn import_unchecked_extrinsic(&self, uxt: UncheckedExtrinsic) -> Result<Arc<VerifiedTransaction>> {
|
|
Ok(self.inner.import(VerifiedTransaction::create(uxt)?)?)
|
|
}
|
|
}
|
|
|
|
impl Deref for TransactionPool {
|
|
type Target = Pool<UncheckedExtrinsic, Hash, Verifier, Scoring, Error>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.inner
|
|
}
|
|
}
|
|
|
|
impl ExtrinsicPool<FutureProofUncheckedExtrinsic, Hash> for TransactionPool {
|
|
type Error = Error;
|
|
|
|
fn submit(&self, xts: Vec<FutureProofUncheckedExtrinsic>) -> Result<Vec<Hash>> {
|
|
// TODO: more general transaction pool, which can handle more kinds of vec-encoded transactions,
|
|
// even when runtime is out of date.
|
|
xts.into_iter()
|
|
.map(|xt| xt.encode())
|
|
.map(|encoded| UncheckedExtrinsic::decode(&mut &encoded[..]))
|
|
.map(|maybe_decoded| maybe_decoded.ok_or_else(|| ErrorKind::InvalidExtrinsicFormat.into()))
|
|
.map(|x| x.and_then(|x| self.import_unchecked_extrinsic(x)))
|
|
.map(|x| x.map(|x| x.hash().clone()))
|
|
.collect()
|
|
}
|
|
}
|