-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Recover transaction pool on light client #3833
Conversation
srml/system/rpc/src/lib.rs
Outdated
fetcher.remote_call(RemoteCallRequest { | ||
block: best_hash, | ||
header: best_header, | ||
method: "AccountNonceApi_account_nonce".into(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that seems very fragile, can't we store that on the trait
level as consts to avoid harcoding strings like this in the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should at least add a test that this is the same as the runtime API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made a separate issue for that - #3875
core/transaction-pool/src/api.rs
Outdated
let remote_validation_request = self.fetcher.remote_call(RemoteCallRequest { | ||
block, | ||
header, | ||
method: "TaggedTransactionQueue_validate_transaction".into(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as with other grumble. We really need to derive these strings from the declaration/implementation.
(this pr was accidently linked in another one as being fixed) |
Co-Authored-By: Tomasz Drwięga <[email protected]>
So I've made a new Main changes are - tx pool clients are now generic over I had to wrap all the futures that After doing this, I'm not sure that traitifying |
@tomusdrw Thanks for merging with master! I've resolved another bunch of conflicts - mostly caused by #4145 . The main change is that now (note that corresponding PR in polkadot isn't opened until this PR is approved) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All issues should addressed now, it's ready for another review :)
(Pretty please 🙏 )
# This is the 1st commit message: # This is a combination of 3 commits. # This is the 1st commit message: # This is a combination of 2 commits. # This is the 1st commit message: # This is a combination of 4 commits. # This is the 1st commit message: Recover transaction pool on light client (paritytech#3833) * recover tx pool on light client * revert local tests fix * removed import renamings * futures03::Future -> std::future::Future * Update core/transaction-pool/graph/src/error.rs Co-Authored-By: Tomasz Drwięga <[email protected]> * replace remove_from_ready with remove_invalid * avoid excess hashing * debug -> warn * TransactionPool + BasicTransactionPool * pause future tx reject when resubmitting * bump impl_version to make CI happy * and revert back local test fixes * alter doc to restart CI * Transaction::clone() -> Transaction::duplicate() * transactions -> updated_tranasctions * remove explicit consensus-common ref * ::std:: -> std:: * manual set/unset flag -> calling clusore with given flag value * removed comments * removed force argument * BestIterator -> Box<Iterator> * separate crate for TxPool + Maintainer trait * long line fix * pos-merge fix * fix benches compilation * Rename txpoolapi to txpool_api * Clean up. * Finalize merge. * post-merge fix * Move transaction pool api to primitives directly. * Consistent naming for txpool-runtime-api * Warn about missing docs. * Move abstraction for offchain calls to tx-pool-api. * Merge RPC instantiation. * Update cargo.lock * Post merge fixes. * Avoid depending on client. * Fix build edit option environment block num - test metrics fn push and finalized listing best_block_num listing base-code(rebased) # This is the commit message #2: README.md add # This is the commit message #3: README.md add # This is the commit message #4: README.md # This is the commit message #2: README.md # This is the commit message #2: README.md update # This is the commit message #3: README.md update # This is the commit message #2: README.md update # This is the commit message #3: README.md # This is the commit message #4: README.md # This is the commit message #5: README.md # This is the commit message #6: translation of introduction
It has been broken since #3538
TLDR: this PR introduces 'generic' light tx pool, which should work on all chains. There's a way to override different parts of this 'generic' implementation with chain-specific implementations. The chain specific implementation could, sometimes, be better than generic.
PART 1. What needs to be implemented.
Basically, it is:
1.1) validation of transactions on light client;
1.2) removal of 'mined' transactions on light client;
1.3) removal of 'invalid' transactions on light client;
1.4) moving transactions between 'ready' and 'future' queues on light client.
PART 2. Validation of transactions on light client.
Options that I have considered:
2.1) do not validate transactions at all - just broadcast to full nodes
2.1.PROS) fastest option;
2.1.CONS) I assume the submitter wants to know if his transaction is valid asap + it is impossible to prune invalid transactions from the pool just by looking at the blocks (it will never be included);
2.2) require specific implementation for every chain:
2.1.PROS) chain-specific implementation could be simpler/faster than generic. Like we could use proof-of-read of account nonce instead of proof-of-call of
fn TaggedTransactionQueue::validate_transaction()
. Or we might have a chain where validation could be performed on full node, if all required information is available from block headers;2.2.CONS) it isn't always possible to write better than generic validation + writing specific implementation is an optimization task + we might want to get slow, but functional light client in the beginning;
2.3) provide generic implementation, but allow overriding it by chain-specific implementations:
2.3.PROS) easy-to-start + might be optimized later;
2.3.CONS) requires proof-of-call from remote nodes
So I've chose the option 2.3. In the code it is in the
LightChainApi
. The specific implementation could be provided when transaction pool is created.Part 3. Removal of 'mined' transactions on light client.
Options that I have considered:
3.1) chain-specific removal. E.g. we can fetch proof-of-read of account nonce from remote node and prune all transactions with nonce < than provided
3.1.PROS) may be faster if we could figure out whether tx has been included from the header
3.1.CONS) the same as in 2.2.CONS
3.2) generic removal by fetching proof-of-inclusion
3.2.PROS) -
3.2.CONS) should be fast enough for most of implementations
I've chose the option 3.2. But in this PR there's no proof-of-inclusion - instead we fetch bodies of all transactions for every block when txpool is not empty and prune these transactions from the pool. If PR will be accepted, I'll file an issue about this optimization.
Part 4 and 5. Moving transactions between 'future', 'ready' and 'invalid' states.
First of all, I've made a controversial decision that on light client we do not accept transactions to the 'future' queue. That's because it is impossible to know whether transaction should be moved to the 'ready' queue without revalidation. And I wanted to avoid much revalidaton calls, because they're quite heavy in 'generic' implementation. Also - 'ready'/'future' state depends on transactions that are in transaction pool. Like the same transaction could be moved to 'ready' queue if tags that it requires are satisfied by other transactions from the 'ready' queue. At the same time, on other node it could be moved to the 'future' queue if the 'satisfying' transaction is missing. That said, I'm not sure - whether this restriction makes sense, or not. So any opinion/advice is appreciated.
So after this restriction, we only have 'ready' and 'invalid' states. And the only possible transition is from 'ready' to 'invalid' state. Iiuc, on full client, this transition is detected when some of mined transactions are providing the same tags => then the 'ready' transaction is revalidated. On light client it isn't a good idea to revalidate every transaction from every block (just to receive tags that it provides). So the (not best, but functional) solution is to perform revalidation at some intervals. By default, all ready transactions are revalidated every 60 seconds or every 20 blocks (whatever happens first). These constants can be overrided. And the whole mechanism could be overrided by passing chain-specific 'TranasctionPoolMaintainer' implementation to
fn ServiceBuilder::with_transaction_pool_maintainer()
.Part 6, unrelated. Accounts RPC.
When I was testing this PR, I found that "Accounts RPC methods" from node are (now?) required to submit transaction to the pool. So I've also fixed it in this PR. The fix is localized in the
node/rpc/src/*
and additional argument is added to thefn ServiceBuilder::with_rpc_extensions()
. But if required, I could extract this fix to the separate PR.