mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-10 23:01:08 +00:00
Transaction eras (#758)
* Initial groundwork * A mess. * Integrate * Fix tests * Unit tests * Tests for unchecked_extrisnic * fix tab * Improve binary format. * fix tests * Rename extrinsic-pool -> transaction-pool Closes #770 * Implement unimplemented. * typo
This commit is contained in:
@@ -31,10 +31,9 @@ use client::backend::Backend;
|
||||
use client::block_builder::BlockBuilder as ClientBlockBuilder;
|
||||
use client::{Client, CallExecutor};
|
||||
use primitives::{
|
||||
AccountId, Block, BlockId, Hash, Index, InherentData,
|
||||
SessionKey, Timestamp, UncheckedExtrinsic
|
||||
AccountId, Block, BlockId, BlockNumber, Hash, Index, InherentData, SessionKey, Timestamp, UncheckedExtrinsic
|
||||
};
|
||||
use sr_primitives::transaction_validity::TransactionValidity;
|
||||
use sr_primitives::{transaction_validity::TransactionValidity, traits::{GetHeight, BlockNumberToHash}};
|
||||
use substrate_primitives::{Blake2Hasher, RlpCodec};
|
||||
|
||||
/// Build new blocks.
|
||||
@@ -49,7 +48,7 @@ pub trait BlockBuilder {
|
||||
/// Trait encapsulating the node API.
|
||||
///
|
||||
/// All calls should fail when the exact runtime is unknown.
|
||||
pub trait Api {
|
||||
pub trait Api: GetHeight<BlockNumber=BlockNumber> + BlockNumberToHash<BlockNumber=BlockNumber,Hash=Hash> {
|
||||
/// The block builder for this API type.
|
||||
type BlockBuilder: BlockBuilder;
|
||||
|
||||
@@ -91,7 +90,7 @@ pub trait Api {
|
||||
impl<B, E> BlockBuilder for ClientBlockBuilder<B, E, Block, Blake2Hasher, RlpCodec>
|
||||
where
|
||||
B: Backend<Block, Blake2Hasher, RlpCodec>,
|
||||
E: CallExecutor<Block, Blake2Hasher, RlpCodec>+ Clone,
|
||||
E: CallExecutor<Block, Blake2Hasher, RlpCodec> + Clone,
|
||||
{
|
||||
fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
|
||||
self.push(extrinsic).map_err(Into::into)
|
||||
|
||||
@@ -48,6 +48,7 @@ use std::time::{self, Duration, Instant};
|
||||
use codec::{Decode, Encode};
|
||||
use node_api::Api;
|
||||
use node_primitives::{AccountId, Hash, Block, BlockId, BlockNumber, Header, Timestamp, SessionKey};
|
||||
use runtime_primitives::generic::Era;
|
||||
use primitives::{AuthorityId, ed25519};
|
||||
use transaction_pool::TransactionPool;
|
||||
use tokio::runtime::TaskExecutor;
|
||||
@@ -400,14 +401,13 @@ impl<C> bft::Proposer<Block> for Proposer<C>
|
||||
=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)),
|
||||
}
|
||||
};
|
||||
let payload = (next_index, Call::Consensus(ConsensusCall::report_misbehavior(report)));
|
||||
let payload = (next_index, Call::Consensus(ConsensusCall::report_misbehavior(report)), self.client.genesis_hash());
|
||||
let signature = self.local_key.sign(&payload.encode()).into();
|
||||
next_index += 1;
|
||||
|
||||
let local_id = self.local_key.public().0.into();
|
||||
let extrinsic = UncheckedExtrinsic {
|
||||
signature: Some((node_runtime::RawAddress::Id(local_id), signature)),
|
||||
index: payload.0,
|
||||
signature: Some((node_runtime::RawAddress::Id(local_id), signature, payload.0, Era::immortal())),
|
||||
function: payload.1,
|
||||
};
|
||||
let uxt: GenericExtrinsic = Decode::decode(&mut extrinsic.encode().as_slice()).expect("Encoded extrinsic is valid");
|
||||
|
||||
@@ -54,7 +54,7 @@ mod tests {
|
||||
ed25519::{Public, Pair}};
|
||||
use node_primitives::{Hash, BlockNumber, AccountId};
|
||||
use runtime_primitives::traits::{Header as HeaderT, Digest as DigestT};
|
||||
use runtime_primitives::{generic, ApplyOutcome, ApplyError, ApplyResult};
|
||||
use runtime_primitives::{generic, generic::Era, ApplyOutcome, ApplyError, ApplyResult};
|
||||
use {balances, staking, session, system, consensus, timestamp, treasury};
|
||||
use system::{EventRecord, Phase};
|
||||
use node_runtime::{Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances,
|
||||
@@ -63,6 +63,7 @@ mod tests {
|
||||
|
||||
const BLOATY_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm");
|
||||
const COMPACT_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm");
|
||||
const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
||||
|
||||
// TODO: move into own crate.
|
||||
macro_rules! map {
|
||||
@@ -81,19 +82,17 @@ mod tests {
|
||||
|
||||
fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
|
||||
match xt.signed {
|
||||
Some(signed) => {
|
||||
let payload = (xt.index, xt.function);
|
||||
Some((signed, index)) => {
|
||||
let payload = (index, xt.function, GENESIS_HASH);
|
||||
let pair = Pair::from(Keyring::from_public(Public::from_raw(signed.clone().into())).unwrap());
|
||||
let signature = pair.sign(&payload.encode()).into();
|
||||
UncheckedExtrinsic {
|
||||
signature: Some((balances::address::Address::Id(signed), signature)),
|
||||
index: payload.0,
|
||||
signature: Some((balances::address::Address::Id(signed), signature, payload.0, Era::mortal(256, 0))),
|
||||
function: payload.1,
|
||||
}
|
||||
}
|
||||
None => UncheckedExtrinsic {
|
||||
signature: None,
|
||||
index: xt.index,
|
||||
function: xt.function,
|
||||
},
|
||||
}
|
||||
@@ -101,8 +100,7 @@ mod tests {
|
||||
|
||||
fn xt() -> UncheckedExtrinsic {
|
||||
sign(CheckedExtrinsic {
|
||||
signed: Some(alice()),
|
||||
index: 0,
|
||||
signed: Some((alice(), 0)),
|
||||
function: Call::Balances(balances::Call::transfer::<Runtime>(bob().into(), 69)),
|
||||
})
|
||||
}
|
||||
@@ -283,7 +281,7 @@ mod tests {
|
||||
fn block1(support_changes_trie: bool) -> (Vec<u8>, Hash) {
|
||||
construct_block(
|
||||
1,
|
||||
[69u8; 32].into(),
|
||||
GENESIS_HASH.into(),
|
||||
if support_changes_trie {
|
||||
hex!("1755be7303767b4d3855694b4f0ebd9d64b7011124d0ec1ad3e17c2a0d65e245").into()
|
||||
} else {
|
||||
@@ -297,12 +295,10 @@ mod tests {
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
signed: None,
|
||||
index: 0,
|
||||
function: Call::Timestamp(timestamp::Call::set(42)),
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
signed: Some(alice()),
|
||||
index: 0,
|
||||
signed: Some((alice(), 0)),
|
||||
function: Call::Balances(balances::Call::transfer(bob().into(), 69)),
|
||||
},
|
||||
]
|
||||
@@ -313,22 +309,19 @@ mod tests {
|
||||
construct_block(
|
||||
2,
|
||||
block1(false).1,
|
||||
hex!("29fa1d0aa83662c571315af54b106c73823a31f759793803bf8929960b67b138").into(),
|
||||
hex!("60efe1a65e7c79041b02e56ec122d6eaedfa476e0a9f6f1f68eb0c8f402c4514").into(),
|
||||
None,
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
signed: None,
|
||||
index: 0,
|
||||
function: Call::Timestamp(timestamp::Call::set(52)),
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
signed: Some(bob()),
|
||||
index: 0,
|
||||
signed: Some((bob(), 0)),
|
||||
function: Call::Balances(balances::Call::transfer(alice().into(), 5)),
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
signed: Some(alice()),
|
||||
index: 1,
|
||||
signed: Some((alice(), 1)),
|
||||
function: Call::Balances(balances::Call::transfer(bob().into(), 15)),
|
||||
}
|
||||
]
|
||||
@@ -338,18 +331,16 @@ mod tests {
|
||||
fn block1big() -> (Vec<u8>, Hash) {
|
||||
construct_block(
|
||||
1,
|
||||
[69u8; 32].into(),
|
||||
GENESIS_HASH.into(),
|
||||
hex!("fe0e07c7b054fe186387461d455d536860e9c71d6979fd9dbf755e96ce070d04").into(),
|
||||
None,
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
signed: None,
|
||||
index: 0,
|
||||
function: Call::Timestamp(timestamp::Call::set(42)),
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
signed: Some(alice()),
|
||||
index: 0,
|
||||
signed: Some((alice(), 0)),
|
||||
function: Call::Consensus(consensus::Call::remark(vec![0; 120000])),
|
||||
}
|
||||
]
|
||||
|
||||
@@ -223,11 +223,11 @@ pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
/// BlockId type as expected by this runtime.
|
||||
pub type BlockId = generic::BlockId<Block>;
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Index, Call, Signature>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedMortalExtrinsic<Address, Index, Call, Signature>;
|
||||
/// Extrinsic type that has already been checked.
|
||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
|
||||
/// Executive: handles dispatch to the various modules.
|
||||
pub type Executive = executive::Executive<Runtime, Block, Balances, Balances, AllModules>;
|
||||
pub type Executive = executive::Executive<Runtime, Block, balances::ChainContext<Runtime>, Balances, AllModules>;
|
||||
|
||||
pub mod api {
|
||||
impl_stubs!(
|
||||
@@ -251,19 +251,13 @@ pub mod api {
|
||||
|
||||
/// Produces the list of inherent extrinsics.
|
||||
fn inherent_extrinsics(data: InherentData) -> Vec<UncheckedExtrinsic> {
|
||||
let make_inherent = |function| UncheckedExtrinsic {
|
||||
signature: Default::default(),
|
||||
function,
|
||||
index: 0,
|
||||
};
|
||||
|
||||
let mut inherent = vec![
|
||||
make_inherent(Call::Timestamp(TimestampCall::set(data.timestamp))),
|
||||
];
|
||||
let mut inherent = vec![generic::UncheckedMortalExtrinsic::new_unsigned(
|
||||
Call::Timestamp(TimestampCall::set(data.timestamp))
|
||||
)];
|
||||
|
||||
if !data.offline_indices.is_empty() {
|
||||
inherent.push(make_inherent(
|
||||
Call::Consensus(ConsensusCall::note_offline(data.offline_indices))
|
||||
inherent.push(generic::UncheckedMortalExtrinsic::new_unsigned(
|
||||
Call::Consensus(ConsensusCall::note_offline(data.offline_indices))
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ use tokio::runtime::TaskExecutor;
|
||||
use service::FactoryFullConfiguration;
|
||||
use primitives::{Blake2Hasher, RlpCodec};
|
||||
|
||||
pub use service::{Roles, PruningMode, ExtrinsicPoolOptions,
|
||||
pub use service::{Roles, PruningMode, TransactionPoolOptions,
|
||||
ErrorKind, Error, ComponentBlock, LightComponents, FullComponents};
|
||||
pub use client::ExecutionStrategy;
|
||||
|
||||
@@ -97,20 +97,20 @@ impl service::ServiceFactory for Factory {
|
||||
type ExtrinsicHash = Hash;
|
||||
type NetworkProtocol = DemoProtocol;
|
||||
type RuntimeDispatch = node_executor::Executor;
|
||||
type FullExtrinsicPoolApi = transaction_pool::ChainApi<service::FullClient<Self>>;
|
||||
type LightExtrinsicPoolApi = transaction_pool::ChainApi<service::LightClient<Self>>;
|
||||
type FullTransactionPoolApi = transaction_pool::ChainApi<service::FullClient<Self>>;
|
||||
type LightTransactionPoolApi = transaction_pool::ChainApi<service::LightClient<Self>>;
|
||||
type Genesis = GenesisConfig;
|
||||
type Configuration = CustomConfiguration;
|
||||
|
||||
const NETWORK_PROTOCOL_ID: network::ProtocolId = ::node_network::PROTOCOL_ID;
|
||||
|
||||
fn build_full_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<service::FullClient<Self>>)
|
||||
fn build_full_transaction_pool(config: TransactionPoolOptions, client: Arc<service::FullClient<Self>>)
|
||||
-> Result<TransactionPool<service::FullClient<Self>>, Error>
|
||||
{
|
||||
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
|
||||
}
|
||||
|
||||
fn build_light_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<service::LightClient<Self>>)
|
||||
fn build_light_transaction_pool(config: TransactionPoolOptions, client: Arc<service::LightClient<Self>>)
|
||||
-> Result<TransactionPool<service::LightClient<Self>>, Error>
|
||||
{
|
||||
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
|
||||
@@ -180,7 +180,7 @@ pub fn new_full(config: Configuration, executor: TaskExecutor)
|
||||
client.clone(),
|
||||
client.clone(),
|
||||
consensus_net,
|
||||
service.extrinsic_pool(),
|
||||
service.transaction_pool(),
|
||||
executor,
|
||||
key,
|
||||
))
|
||||
|
||||
@@ -13,6 +13,6 @@ node-runtime = { path = "../runtime" }
|
||||
substrate-client = { path = "../../core/client" }
|
||||
parity-codec = { version = "1.1" }
|
||||
substrate-keyring = { path = "../../core/keyring" }
|
||||
substrate-extrinsic-pool = { path = "../../core/extrinsic-pool" }
|
||||
substrate-transaction-pool = { path = "../../core/transaction-pool" }
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use extrinsic_pool;
|
||||
use transaction_pool;
|
||||
use node_api;
|
||||
use primitives::Hash;
|
||||
use runtime::{Address, UncheckedExtrinsic};
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
Pool(extrinsic_pool::Error, extrinsic_pool::ErrorKind);
|
||||
Pool(transaction_pool::Error, transaction_pool::ErrorKind);
|
||||
Api(node_api::Error, node_api::ErrorKind);
|
||||
}
|
||||
errors {
|
||||
@@ -63,10 +63,10 @@ error_chain! {
|
||||
}
|
||||
}
|
||||
|
||||
impl extrinsic_pool::IntoPoolError for Error {
|
||||
fn into_pool_error(self) -> ::std::result::Result<extrinsic_pool::Error, Self> {
|
||||
impl transaction_pool::IntoPoolError for Error {
|
||||
fn into_pool_error(self) -> ::std::result::Result<transaction_pool::Error, Self> {
|
||||
match self {
|
||||
Error(ErrorKind::Pool(e), c) => Ok(extrinsic_pool::Error(e, c)),
|
||||
Error(ErrorKind::Pool(e), c) => Ok(transaction_pool::Error(e, c)),
|
||||
e => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
extern crate substrate_client as client;
|
||||
extern crate parity_codec as codec;
|
||||
extern crate substrate_extrinsic_pool as extrinsic_pool;
|
||||
extern crate substrate_transaction_pool as transaction_pool;
|
||||
extern crate substrate_primitives;
|
||||
extern crate sr_primitives;
|
||||
extern crate node_runtime as runtime;
|
||||
@@ -42,20 +42,20 @@ use std::{
|
||||
};
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use extrinsic_pool::{Readiness, scoring::{Change, Choice}, VerifiedFor, ExtrinsicFor};
|
||||
use transaction_pool::{Readiness, scoring::{Change, Choice}, VerifiedFor, ExtrinsicFor};
|
||||
use node_api::Api;
|
||||
use primitives::{AccountId, BlockId, Block, Hash, Index};
|
||||
use runtime::{UncheckedExtrinsic, RawAddress};
|
||||
use sr_primitives::traits::{Bounded, Checkable, Hash as HashT, BlakeTwo256};
|
||||
use primitives::{AccountId, BlockId, Block, Hash, Index, BlockNumber};
|
||||
use runtime::{Address, UncheckedExtrinsic};
|
||||
use sr_primitives::traits::{Bounded, Checkable, Hash as HashT, BlakeTwo256, Lookup, GetHeight, BlockNumberToHash};
|
||||
|
||||
pub use extrinsic_pool::{Options, Status, LightStatus, VerifiedTransaction as VerifiedTransactionOps};
|
||||
pub use transaction_pool::{Options, Status, LightStatus, VerifiedTransaction as VerifiedTransactionOps};
|
||||
pub use error::{Error, ErrorKind, Result};
|
||||
|
||||
/// Maximal size of a single encoded extrinsic.
|
||||
const MAX_TRANSACTION_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
/// Type alias for the transaction pool.
|
||||
pub type TransactionPool<A> = extrinsic_pool::Pool<ChainApi<A>>;
|
||||
pub type TransactionPool<A> = transaction_pool::Pool<ChainApi<A>>;
|
||||
|
||||
/// A verified transaction which should be includable and non-inherent.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -86,7 +86,7 @@ impl VerifiedTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
impl extrinsic_pool::VerifiedTransaction for VerifiedTransaction {
|
||||
impl transaction_pool::VerifiedTransaction for VerifiedTransaction {
|
||||
type Hash = Hash;
|
||||
type Sender = AccountId;
|
||||
|
||||
@@ -119,8 +119,32 @@ impl<A> ChainApi<A> where
|
||||
}
|
||||
}
|
||||
|
||||
/// "Chain" context (used for checking transactions) which uses data local to our node/transaction pool.
|
||||
///
|
||||
/// This is due for removal when #721 lands
|
||||
pub struct LocalContext<'a, A: 'a>(&'a Arc<A>);
|
||||
impl<'a, A: 'a + Api> GetHeight for LocalContext<'a, A> {
|
||||
type BlockNumber = BlockNumber;
|
||||
fn get_height(&self) -> BlockNumber {
|
||||
self.0.get_height()
|
||||
}
|
||||
}
|
||||
impl<'a, A: 'a + Api> BlockNumberToHash for LocalContext<'a, A> {
|
||||
type BlockNumber = BlockNumber;
|
||||
type Hash = Hash;
|
||||
fn block_number_to_hash(&self, n: BlockNumber) -> Option<Hash> {
|
||||
self.0.block_number_to_hash(n)
|
||||
}
|
||||
}
|
||||
impl<'a, A: 'a + Api> Lookup for LocalContext<'a, A> {
|
||||
type Source = Address;
|
||||
type Target = AccountId;
|
||||
fn lookup(&self, a: Address) -> ::std::result::Result<AccountId, &'static str> {
|
||||
self.0.lookup(&BlockId::number(self.get_height()), a).unwrap_or(None).ok_or("error with lookup")
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> extrinsic_pool::ChainApi for ChainApi<A> where
|
||||
impl<A> transaction_pool::ChainApi for ChainApi<A> where
|
||||
A: Api + Send + Sync,
|
||||
{
|
||||
type Block = Block;
|
||||
@@ -145,13 +169,8 @@ impl<A> extrinsic_pool::ChainApi for ChainApi<A> where
|
||||
}
|
||||
|
||||
debug!(target: "transaction-pool", "Transaction submitted: {}", ::substrate_primitives::hexdisplay::HexDisplay::from(&encoded));
|
||||
let checked = uxt.clone().check_with(|a| {
|
||||
match a {
|
||||
RawAddress::Id(id) => Ok(id),
|
||||
RawAddress::Index(_) => Err("Index based addresses are not supported".into()),// TODO: Make index addressing optional in substrate
|
||||
}
|
||||
})?;
|
||||
let sender = checked.signed.expect("Only signed extrinsics are allowed at this point");
|
||||
let checked = uxt.clone().check(&LocalContext(&self.api))?;
|
||||
let (sender, index) = checked.signed.expect("function previously bailed unless uxt.is_signed(); qed");
|
||||
|
||||
|
||||
if encoded_size < 1024 {
|
||||
@@ -161,7 +180,7 @@ impl<A> extrinsic_pool::ChainApi for ChainApi<A> where
|
||||
}
|
||||
|
||||
Ok(VerifiedTransaction {
|
||||
index: checked.index,
|
||||
index,
|
||||
sender,
|
||||
hash,
|
||||
encoded_size,
|
||||
@@ -214,7 +233,7 @@ impl<A> extrinsic_pool::ChainApi for ChainApi<A> where
|
||||
}
|
||||
|
||||
fn update_scores(
|
||||
xts: &[extrinsic_pool::Transaction<VerifiedFor<Self>>],
|
||||
xts: &[transaction_pool::Transaction<VerifiedFor<Self>>],
|
||||
scores: &mut [Self::Score],
|
||||
_change: Change<()>
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user