rpc: Implement transaction RPC API (#12328)

* rpc/tx: Add transaction structures for serialization

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Add public facing `TransactionEvent`

To circumvent the fact that serde does not allow mixing
`#[serde(tag = "event")]` with
`#[serde(tag = "event", content = "block")]`
the public facing subscription structure is serialized
and deserialized to an intermmediate representation.

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Add trait for the `transaction` API

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Convert RPC errors to transaction events

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Implement `transaction` RPC methods

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tx-pool: Propagate tx index to events

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tx-pool: Adjust testing to reflect tx index in events

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Convert tx-pool events for the new RPC spec

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Convert tx-pool `FinalityTimeout` event to `Dropped`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* service: Enable the `transaction` API

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Add tests for tx event encoding and decoding

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tx: Add indentation for subscriptions

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Fix documentation

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Serialize usize to hex

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tx-pool: Rename closure parameters

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* service: Separate RPC spec versions

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Use `H256` for testing block's hash

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Serialize numbers as string

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tx-pool: Backward compatibility with RPC v1

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update client/rpc-spec-v2/src/transaction/transaction.rs

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>

* rpc/tx: Remove comment about serde clone

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* rpc/tx: Use RPC custom error code for invalid tx format

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update client/rpc-spec-v2/src/transaction/event.rs

Co-authored-by: James Wilson <james@jsdw.me>

* rpc/tx: Adjust internal structures for serialization/deserialization

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
Co-authored-by: James Wilson <james@jsdw.me>
This commit is contained in:
Alexandru Vasile
2022-10-11 11:49:12 +03:00
committed by GitHub
parent 896a9fc7cb
commit 5f18aaadcd
16 changed files with 873 additions and 36 deletions
@@ -104,13 +104,18 @@ impl<H: hash::Hash + traits::Member + Serialize, C: ChainApi> Listener<H, C> {
/// Transaction was pruned from the pool.
pub fn pruned(&mut self, block_hash: BlockHash<C>, tx: &H) {
debug!(target: "txpool", "[{:?}] Pruned at {:?}", tx, block_hash);
self.fire(tx, |s| s.in_block(block_hash));
self.finality_watchers.entry(block_hash).or_insert(vec![]).push(tx.clone());
// Get the transactions included in the given block hash.
let txs = self.finality_watchers.entry(block_hash).or_insert(vec![]);
txs.push(tx.clone());
// Current transaction is the last one included.
let tx_index = txs.len() - 1;
self.fire(tx, |watcher| watcher.in_block(block_hash, tx_index));
while self.finality_watchers.len() > MAX_FINALITY_WATCHERS {
if let Some((hash, txs)) = self.finality_watchers.pop_front() {
for tx in txs {
self.fire(&tx, |s| s.finality_timeout(hash));
self.fire(&tx, |watcher| watcher.finality_timeout(hash));
}
}
}
@@ -120,7 +125,7 @@ impl<H: hash::Hash + traits::Member + Serialize, C: ChainApi> Listener<H, C> {
pub fn retracted(&mut self, block_hash: BlockHash<C>) {
if let Some(hashes) = self.finality_watchers.remove(&block_hash) {
for hash in hashes {
self.fire(&hash, |s| s.retracted(block_hash))
self.fire(&hash, |watcher| watcher.retracted(block_hash))
}
}
}
@@ -128,9 +133,9 @@ impl<H: hash::Hash + traits::Member + Serialize, C: ChainApi> Listener<H, C> {
/// Notify all watchers that transactions have been finalized
pub fn finalized(&mut self, block_hash: BlockHash<C>) {
if let Some(hashes) = self.finality_watchers.remove(&block_hash) {
for hash in hashes {
for (tx_index, hash) in hashes.into_iter().enumerate() {
log::debug!(target: "txpool", "[{:?}] Sent finalization event (block {:?})", hash, block_hash);
self.fire(&hash, |s| s.finalized(block_hash))
self.fire(&hash, |watcher| watcher.finalized(block_hash, tx_index))
}
}
}
@@ -770,7 +770,7 @@ mod tests {
assert_eq!(stream.next(), Some(TransactionStatus::Ready));
assert_eq!(
stream.next(),
Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())),
Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))),
);
}
@@ -803,7 +803,7 @@ mod tests {
assert_eq!(stream.next(), Some(TransactionStatus::Ready));
assert_eq!(
stream.next(),
Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())),
Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))),
);
}
@@ -84,13 +84,13 @@ impl<H: Clone, BH: Clone> Sender<H, BH> {
}
/// Extrinsic has been included in block with given hash.
pub fn in_block(&mut self, hash: BH) {
self.send(TransactionStatus::InBlock(hash));
pub fn in_block(&mut self, hash: BH, index: usize) {
self.send(TransactionStatus::InBlock((hash, index)));
}
/// Extrinsic has been finalized by a finality gadget.
pub fn finalized(&mut self, hash: BH) {
self.send(TransactionStatus::Finalized(hash));
pub fn finalized(&mut self, hash: BH, index: usize) {
self.send(TransactionStatus::Finalized((hash, index)));
self.is_finalized = true;
}