Skip to content

Improve mempool graph replacement API #1439

@Mirko-von-Leipzig

Description

@Mirko-von-Leipzig

Some initial context here #1396 (comment).

Overview

The mempool is a DAG with nodes representing transactions, batches and blocks. Edges represent a parent/child dependency between the nodes e.g. a depends on b if it consumes a note created by b, or a's account update follows on from bs.

High level graph operations include

  • adding new transaction nodes
  • replacing a set of nodes with a single node
    • e.g. transforming a set of transaction nodes into a batch node
  • replacing a single node with a set of nodes
    • e.g. reverting a batch node and re-inserting its transactions

This is currently facilitated by having no continuity enforcement within an account's state tracking. We allow this so that at the high level node replacements can be implemented by simply removing the old node(s) and inserting the new node(s). This is simple but means the graph state is allowed to be in an invalid, disconnected state while this shuffling happens and there is no check or enforcement in place to double-check for bugs.

The high level code is responsible for maintaining the invariants which at the very least will be prone to refactoring bugs. It also makes the low-level code look suspicious in isolation.

We want to improve this by changing the API slightly to account for the different use cases. There will be some possible sharp edges so this should begin as an experiment - we do want some flexibility so that adding and removing nodes isn't that difficult.

Potential API

/// Adds a new transition.
fn push(&mut self, node: NodeId, from: Word, to: Word) { ... }

/// Replaces `target` node with a contiguous series of updates
fn unfold(&mut self, target: &NodeId, to: &[(NodeId, Word)]) {...}

/// Replaces a contiguous range of updates with a single new NodeId
fn fold(&mut self, range: Range<NodeId>, to: NodeId) { ... }

/// Removes a node transition.
fn remove(&mut, node: NodeId) { ... }

The above is an example of the new account state API. This would replace the current insert/remove API. The idea is simply that each operation must leave the account transitions in a valid, continuous state. The caller is therefore responsible for ensuring e.g. that unfolds target node is equivalent to the set of NodeIds its replacing. Or that the node being removed is either at the top or bottom of the stack.

There will be some friction here since we must also allow for pass-through transactions but it should be doable.

Something else to consider is that when reverting graph subtrees we often want to re-insert the transactions if we are able to. Currently we can just re-insert them in any order since the order isn't checked. But once we move to such an API, each call must be valid in isolation and therefore we would want to ensure we re-insert nodes following the original chronological order. We can facilitate this by tracking an additional auto-incrementing number for each submitted transaction which we can then use in the re-insertion.

Metadata

Metadata

Labels

mempoolRelates to the mempool

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions