Handle AccountIndices in transaction pool (#225)

* Merge remote-tracking branch 'origin/master' into gav-xts-dont-panic

* Update wasm.

* consensus, session and staking all panic-safe.

* Democracy doesn't panic in apply.

* Fix tests.

* Extra helper macro, council depanicked.

* Fix one test.

* Fix up all council tests. No panics!

* Council voting depanicked.

* Dispatch returns result.

* session & staking tests updated

* Fix democracy tests.

* Fix council tests.

* Fix up polkadot parachains in runtime

* Fix borked merge

* More Slicable support

Support general `Option` and array types.

* Basic storage types.

* Existential deposit for contract creation

* Basic implemnetation along with removals

* Fix tests.

* externalities builder fix.

* Tests.

* Fix up the runtime.

* Fix tests.

* Add generic `Address` type.

* Initial function integration of Address into Extrinsic.

* Fix build

* All tests compile.

* Fix (some) tests.

* Fix signing.

* Push error.

* transfer can accept Address

* Make Address generic over AccountIndex

* Fix test

* Make Council use Address for dispatch.

* Fix build

* Bend over backwards to support braindead derive.

* Repot some files.

* Fix tests.

* Fix grumbles

* Remove Default bound

* Fix build for new nightly.

* Make `apply_extrinsic` never panic, return useful Result.

* More merge hell

* Doesn't build, but might do soon

* Serde woes

* get substrate-runtime-staking compiling

* Polkadot builds again!

* Fix all build.

* Fix tests & binaries.

* Reserve some extra initial byte values of address for future format changes

* Make semantic of `ReservedBalance` clear.

* Fix panic handler.

* Integrate other balance transformations into the new model

Fix up staking tests.

* Fix runtime tests.

* Fix panic build.

* Tests for demonstrating interaction between balance types.

* Repot some runtime code

* Fix checkedblock in non-std builds

* Get rid of `DoLookup` phantom.

* Attempt to make transaction_pool work with lookups.

* Remove vscode settings

* New attempt at making transaction pool work.

* It builds again!

* --all builds

* Fix tests.

* New build.

* Test account nonce reset.

* polkadot transaction pool tests/framework.

* Address grumbles.

* Pool support non-verified transactions.

* Revert bad `map_or`

* Rebuild binaries, workaround.

* Avoid casting to usize early.

* Make verification use provided block_id.

* Fix tests.

* Alter tests to use retry.

* Fix tests & add call to re-verify.

* Semi-refactor.

* Integrate new queue with the rest of the code.

* Fix tests.

* Add reverify_transaction method.

* Use result.
This commit is contained in:
Tomasz Drwięga
2018-06-26 11:45:57 +02:00
committed by Gav Wood
parent ede447e139
commit 5d4dafb8c0
8 changed files with 402 additions and 282 deletions
+34 -27
View File
@@ -55,11 +55,11 @@ pub trait Components {
fn build_api(&self, client: Arc<Client<Self::Backend, Self::Executor, Block>>) -> Arc<Self::Api>;
/// Create network transaction pool adapter.
fn build_network_tx_pool(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, api: Arc<Self::Api>, tx_pool: Arc<TransactionPool>)
fn build_network_tx_pool(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, tx_pool: Arc<TransactionPool<Self::Api>>)
-> Arc<network::TransactionPool<Block>>;
/// Create consensus service.
fn build_consensus(&self, client: Arc<Client<Self::Backend, Self::Executor, Block>>, network: Arc<network::Service<Block>>, tx_pool: Arc<TransactionPool>, keystore: &Keystore)
fn build_consensus(&self, client: Arc<Client<Self::Backend, Self::Executor, Block>>, network: Arc<network::Service<Block>>, tx_pool: Arc<TransactionPool<Self::Api>>, keystore: &Keystore)
-> Result<Option<consensus::Service>, error::Error>;
}
@@ -83,17 +83,16 @@ impl Components for FullComponents {
client
}
fn build_network_tx_pool(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, api: Arc<Self::Api>, pool: Arc<TransactionPool>)
fn build_network_tx_pool(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, pool: Arc<TransactionPool<Self::Api>>)
-> Arc<network::TransactionPool<Block>> {
Arc::new(TransactionPoolAdapter {
imports_external_transactions: true,
pool,
client,
api,
})
}
fn build_consensus(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, network: Arc<network::Service<Block>>, tx_pool: Arc<TransactionPool>, keystore: &Keystore)
fn build_consensus(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, network: Arc<network::Service<Block>>, tx_pool: Arc<TransactionPool<Self::Api>>, keystore: &Keystore)
-> Result<Option<consensus::Service>, error::Error> {
if !self.is_validator {
return Ok(None);
@@ -134,17 +133,16 @@ impl Components for LightComponents {
Arc::new(polkadot_api::light::RemotePolkadotApiWrapper(client.clone()))
}
fn build_network_tx_pool(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, api: Arc<Self::Api>, pool: Arc<TransactionPool>)
fn build_network_tx_pool(&self, client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, pool: Arc<TransactionPool<Self::Api>>)
-> Arc<network::TransactionPool<Block>> {
Arc::new(TransactionPoolAdapter {
imports_external_transactions: false,
pool,
client,
api,
})
}
fn build_consensus(&self, _client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, _network: Arc<network::Service<Block>>, _tx_pool: Arc<TransactionPool>, _keystore: &Keystore)
fn build_consensus(&self, _client: Arc<client::Client<Self::Backend, Self::Executor, Block>>, _network: Arc<network::Service<Block>>, _tx_pool: Arc<TransactionPool<Self::Api>>, _keystore: &Keystore)
-> Result<Option<consensus::Service>, error::Error> {
Ok(None)
}
@@ -153,9 +151,25 @@ impl Components for LightComponents {
/// Transaction pool adapter.
pub struct TransactionPoolAdapter<B, E, A> where A: Send + Sync, E: Send + Sync {
imports_external_transactions: bool,
pool: Arc<TransactionPool>,
pool: Arc<TransactionPool<A>>,
client: Arc<Client<B, E, Block>>,
api: Arc<A>,
}
impl<B, E, A> TransactionPoolAdapter<B, E, A>
where
A: Send + Sync,
B: client::backend::Backend<Block> + Send + Sync,
E: client::CallExecutor<Block> + Send + Sync,
client::error::Error: From<<<B as client::backend::Backend<Block>>::State as state_machine::backend::Backend>::Error>,
{
fn best_block_id(&self) -> Option<BlockId> {
self.client.info()
.map(|info| BlockId::hash(info.chain.best_hash))
.map_err(|e| {
debug!("Error getting best block: {:?}", e);
})
.ok()
}
}
impl<B, E, A> network::TransactionPool<Block> for TransactionPoolAdapter<B, E, A>
@@ -166,28 +180,20 @@ impl<B, E, A> network::TransactionPool<Block> for TransactionPoolAdapter<B, E, A
A: polkadot_api::PolkadotApi + Send + Sync,
{
fn transactions(&self) -> Vec<(Hash, Vec<u8>)> {
let best_block = match self.client.info() {
Ok(info) => info.chain.best_hash,
Err(e) => {
debug!("Error getting best block: {:?}", e);
return Vec::new();
}
let best_block_id = match self.best_block_id() {
Some(id) => id,
None => return vec![],
};
let id = match self.api.check_id(BlockId::hash(best_block)) {
Ok(id) => id,
Err(_) => return Vec::new(),
};
let ready = transaction_pool::Ready::create(id, &*self.api);
self.pool.cull_and_get_pending(ready, |pending| pending
self.pool.cull_and_get_pending(best_block_id, |pending| pending
.map(|t| {
let hash = t.hash().clone();
(hash, t.primitive_extrinsic())
})
.collect()
)
).unwrap_or_else(|e| {
warn!("Error retrieving pending set: {}", e);
vec![]
})
}
fn import(&self, transaction: &Vec<u8>) -> Option<Hash> {
@@ -197,7 +203,8 @@ impl<B, E, A> network::TransactionPool<Block> for TransactionPoolAdapter<B, E, A
let encoded = transaction.encode();
if let Some(uxt) = codec::Slicable::decode(&mut &encoded[..]) {
match self.pool.import_unchecked_extrinsic(uxt) {
let best_block_id = self.best_block_id()?;
match self.pool.import_unchecked_extrinsic(best_block_id, uxt) {
Ok(xt) => Some(*xt.hash()),
Err(e) => match *e.kind() {
transaction_pool::ErrorKind::AlreadyImported(hash) => Some(hash[..].into()),
+15 -14
View File
@@ -75,7 +75,7 @@ pub struct Service<Components: components::Components> {
thread: Option<thread::JoinHandle<()>>,
client: Arc<Client<Components::Backend, Components::Executor, Block>>,
network: Arc<network::Service<Block>>,
transaction_pool: Arc<TransactionPool>,
transaction_pool: Arc<TransactionPool<Components::Api>>,
signal: Option<Signal>,
_consensus: Option<consensus::Service>,
}
@@ -127,8 +127,8 @@ impl<Components> Service<Components>
info!("Best block is #{}", best_header.number);
telemetry!("node.start"; "height" => best_header.number, "best" => ?best_header.hash());
let transaction_pool = Arc::new(TransactionPool::new(config.transaction_pool));
let transaction_pool_adapter = components.build_network_tx_pool(client.clone(), api.clone(), transaction_pool.clone());
let transaction_pool = Arc::new(TransactionPool::new(config.transaction_pool, api.clone()));
let transaction_pool_adapter = components.build_network_tx_pool(client.clone(), transaction_pool.clone());
let network_params = network::Params {
config: network::ProtocolConfig {
roles: config.roles,
@@ -161,7 +161,8 @@ impl<Components> Service<Components>
let events = client.import_notification_stream()
.for_each(move |notification| {
network1.on_block_imported(notification.hash, &notification.header);
prune_imported(&*api, &*txpool1, notification.hash);
prune_imported(&*txpool1, notification.hash);
Ok(())
});
core.handle().spawn(events);
@@ -210,22 +211,22 @@ impl<Components> Service<Components>
}
/// Get shared transaction pool instance.
pub fn transaction_pool(&self) -> Arc<TransactionPool> {
pub fn transaction_pool(&self) -> Arc<TransactionPool<Components::Api>> {
self.transaction_pool.clone()
}
}
/// Produce a task which prunes any finalized transactions from the pool.
pub fn prune_imported<A>(api: &A, pool: &TransactionPool, hash: Hash)
where
A: PolkadotApi,
pub fn prune_imported<A>(pool: &TransactionPool<A>, hash: Hash)
where A: PolkadotApi,
{
match api.check_id(BlockId::hash(hash)) {
Ok(id) => {
let ready = transaction_pool::Ready::create(id, api);
pool.cull(None, ready);
},
Err(e) => warn!("Failed to check block id: {:?}", e),
let block = BlockId::hash(hash);
if let Err(e) = pool.cull(block) {
warn!("Culling error: {:?}", e);
}
if let Err(e) = pool.retry_verification(block) {
warn!("Re-verifying error: {:?}", e);
}
}