8000 mempool: formal specs in Quint and TLA+ of mempool with cache by hvanz · Pull Request #800 · cometbft/cometbft · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

mempool: formal specs in Quint and TLA+ of mempool with cache #800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 40 commits into from

Conversation

hvanz
Copy link
Member
@hvanz hvanz commented May 5, 2023

Contributes to #614

PR checklist

  • Changelog entry added in .changelog (we use unclog to manage our changelog)
  • Updated relevant documentation (docs/ or spec/) and code comments

@hvanz hvanz added mempool spec Specification-related labels May 5, 2023
@hvanz hvanz added this to the 2023-Q2 milestone May 5, 2023
@hvanz hvanz self-assigned this May 5, 2023
@hvanz hvanz added the wip Work in progress label May 8, 2023
@hvanz hvanz changed the title mempool: first formal spec mempool: formal specs (WIP) May 8, 2023
Copy link
Contributor
@otrack otrack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Quint specification is accurately following the golang codebase (mempool/reactor.go, mempool/clist_mempool.go) in a very nice and elegant manner.

In the few things, I would recommend to amend/add:

  • asynchronous ABCI calls
  • the behavior of consensus upon commit as in state/execution.go
  • differentiate txs and txsMap (although this one is not really mandatory imho because tx in txs iff tx in txsMap)

Would it be also possible to relate this specification to the high-level one which is in the knowledge base? (See here and PR#7.) There is also a refined version that includes caching.

// block it created and rechecks outstanding txs.

// This node is not the proposer: take the block from the chain.
action BlockExecutor_MempoolUpdate_nonProposer(node) = all {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, upon commit the following logic is applied: mempool.Lock, mempool.FlushAppConn, proxyApp.Commit, mempool.Update then mempool.Unlock. (See state/execution.go#Commit.) I wonder if it would be possible to follow exactly these steps.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I will add the following to the update actions, to make sure all ABCI requests are processed before updating.

        require(node.ABCI::checkTxRequests().isEmpty()),
        require(node.ABCI::recheckTxRequests().isEmpty()),

This won't make the flush-commit-update steps atomic, as when they are hold by the lock, but it will work.

// Auxiliary variables
//--------------------------------------------------------------------------
type Step = str
var _step: { node: NodeId, name: Step, args: str -> str }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracking which step was taken during a run is really nice (e.g., to understand why an invariant got broken). I wonder if this could be included as a feature in Quint.


val noMempoolTx = { tx: "", height: 0, senders: Set() }

var mempool: NodeId -> Set[MempoolTx]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we follow to the letter the codebase, then maybe add both txs and txsMap there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a deeper level of abstraction. We would need also to refine Set[MempoolTx] to List[MempoolTx]. We will need to do it if we want to find if txs and txsMap are implemented correctly.


/* The reactor sends at once a tx in the mempool to all its peers. */
// [Reactor.broadcastTxRoutine]: https://github.com/CometBFT/cometbft/blob/5049f2cc6cf519554d6cd90bcca0abe39ce4c9df/mempool/reactor.go#L132
action P2P_BroadcastTx(node: NodeId): bool = all {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, there is no such atomic action in mempool/reactor.go.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I had a P2P_SendTx action but it introduced a lot of additional, unnecessary steps to the trace, one for each peer. Since each peer process the received message when they need to, it doesn't make any real difference to put the message in the peer's inbox all at once.


val __Txs = Set("tx1", "tx2", "tx3", "tx4")

def __isValidAt(tx, h) = or {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat idea which permits to introduce some complexity in the execution of transactions at low cost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, though now that we agreed that CheckTx is not deterministic, this is not correct anymore 😅

(rs) => rs.put(req, (senderId, h, resp)))

// For "Recheck" we send multiple requests at once.
action sendRequestRecheckTxs(nodeId, txs, h) =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the end goal is to model the golang implementation, then I would go for asynchronous ABCI calls.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another case that can be specified with a deeper level of abstraction.

@hvanz
Copy link
Member Author
hvanz commented Jun 14, 2023

Closing this PR as this work is moved to another repo and PR: cometbft/knowledge-base#11. Comments by @otrack are addressed there.

Though this spec is certainly useful for eventually applying model-based testing, it's too tied to the v0 implementation, so we would need to keep it up to date with the changes in the code if we maintain it in this repo.

@hvanz hvanz closed this Jun 14, 2023
@hvanz hvanz changed the title mempool: formal specs (WIP) mempool: formal specs in Quint and TLA+ Jun 14, 2023
@hvanz hvanz changed the title mempool: formal specs in Quint and TLA+ mempool: formal specs in Quint and TLA+ of mempool with cache Jun 14, 2023
@hvanz hvanz removed the wip Work in progress label Jun 14, 2023
@hvanz hvanz deleted the hernan/mempool-spec branch July 26, 2023 14:09
@hvanz hvanz restored the hernan/mempool-spec branch July 26, 2023 14:09
@hvanz hvanz deleted the hernan/mempool-spec branch December 20, 2024 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mempool spec Specification-related
Projects
No open projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants
0