Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

Abstract common consensus functions #8

Closed
wants to merge 5 commits into from

Conversation

adlrocha
Copy link
Contributor

@adlrocha adlrocha commented Sep 27, 2022

Related Issues

#1

Proposed Changes

This PR extends the consensus interface in order to prepare it for the implementation of other consensus algorithms, and it extracts from FilecoinEC common logic that will be shared by all consensus implementations.

  • Extracted block checks and validation to common functions.
  • Extracted ValidatedPubSub as a common function.
  • Abstracted block signature and verification, and the validation of blocks and their headers.
  • Extracted compute_state as common code for all consensus algorithms.
  • Abstracted the application of rewards.

Integration of the interface

To illustrate how can this interface be integrated for the implementation of alternative consensus algorithm, I will share how I imagine it to work and be implemented for Mir:

  • CreateBlock runs the block proposal logic for Mir in Lotus. In CreateBlock Lotus validators pull unverified messages from the mempool, and send them to Mir for ordering. Once the ordered batch is output by Mir, a new Filecoin block is assembled and broadcast through GossipSub to the network. CreateBlock calls SignBlock if the block needs to be signed.
  • Validators are not subscribed to the block gossipsub topic, as they already receive all the information about new blocks through Mir.
  • Other Lotus nodes in the network will receive updates about new blocks being proposed by Mir through the Gossipsub block topic. When a new block is received, GossipSub triggers ValidateBlockHeader before delivering the block to the node. If the validation succeeds, the block is passed to the syncer which runs ValidateBlock to perform a full block validation to determine if the block is valid and can be executed. As part of these verifications, VerifyBlockSignature may be called.
  • Finally, the execution of the block triggers the consensus-specific RewardFunc that parametrized how should block rewards be distributed among validators.

Copy link
Contributor

@dnkolegov dnkolegov left a comment

Choose a reason for hiding this comment

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

LGTM!
I added a comment regarding panicking but then I found the code handling the panics. Removed.

@adlrocha
Copy link
Contributor Author

adlrocha commented Sep 27, 2022

@dnkolegov, do you mind having a look at the last commit also? I parametrized the block reward so we can use alternative approaches for Mir.

We should also figure out what to do with CI (Testground keeps hiding the important checks)

Copy link
Contributor

@matejpavlovic matejpavlovic left a comment

Choose a reason for hiding this comment

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

Having looked through the code, I feel quite unable to say almost anything about it. It would really help me to have some description of the interface (in English) either in form of comments in the code or in some other document. Currently I only see the function signatures defined in the Consensus interface in chain/consensus/iface.go, but I'm pretty clueless about their semantics. I assume that each of those functions is called by Lotus at some point when it needs to communicate with the consensus layer. But when does this happen and what is the meaning of the parameters?

@adlrocha
Copy link
Contributor Author

@matejpavlovic, I added comments to the interface and a brief description of how I imagine the integration to work in the description of the PR. @dnkolegov, please also jump in if you don't agree with something. Let me know if you think it would be useful to discuss this sync. Thanks 🙏

chain/consensus/iface.go Show resolved Hide resolved
chain/consensus/iface.go Show resolved Hide resolved
Copy link
Contributor

@matejpavlovic matejpavlovic left a comment

Choose a reason for hiding this comment

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

Thanks for the clarifications @adlrocha , they really helped a lot!
Now I was able to formulate some more concrete questions around the interface. Some of them are rather broad and open, so I suggest a quick sync call today to answer them together, if you guys are free.

Comment on lines +39 to +43
// CreateBlock implements all the logic required to propose and assemble a new Filecoin block.
//
// This function encapsulate all the consensus-specific actions to propose a new block
// such as the ordering of transactions, the inclusion of consensus proofs, the signature
// of the block, etc.
Copy link
Contributor

Choose a reason for hiding this comment

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

Who calls CreateBlock and when? Can the consensus layer count on this being called by Lotus code, the contract being that on each call of CreateBlock a new block has to be proposed (and (much later) delivered and returned from CreateBlock)? Is the returned block supposed to be ready for execution?

Currently we're working with the idea that the consensus algorithm chooses itself when it proposes new blocks. I.e., it has access to the mempool and pulls requests ("messages") from it whenever it wants. It then "announces" the delivered blocks to Lotus (still Eudico in our case) through an API, and Lotus (Eudico) then takes care of the execution.

I don't have a principal problem if the triggers for proposing the block came from outside (from the point of view of the consensus protocol) instead, I'd just like to know from where and how. I guess it's the miner that calls CreateBlock, right? In this case the miner will also need to run consensus-specific logic (as we do in Eudico now), and maybe it will even end up completely circumventing this function...

Comment on lines +21 to +26
// ValidateBlockHeader is called by peers when they receive a new block through the network.
//
// This is a fast sanity-check validation performed by the PubSub protocol before delivering
// it to the syncer. It checks that the block has the right format and it performs
// other consensus-specific light verifications like ensuring that the block is signed by
// a valid miner, or that it includes all the data required for a full verification.
Copy link
Contributor

Choose a reason for hiding this comment

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

By "through the network" you mean through gossipsub, right?
If I understood your PR description correctly, nodes that participate in the BFT protocol itself would not use this. That makes sense, since for a BFT-style protocol like the Mir-based one we have, this only seems meaningful (possibly) a part of some state synchronization sub-protocol (or for "learner" nodes, if we introduce such a thing within the protocol).

For this to be useful, we need to define what exactly a block header must look like, how it will be validated, by whom, and what information is necessary to validate the block (e.g. the membership?).

Comment on lines +29 to +32
// ValidateBlock is called by the syncer to determine if to accept a block or not.
//
// It performs all the checks needed by the syncer to accept
// the block (signature verifications, VRF checks, message validity, etc.)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is just a more heavy-weight version of ValidateBlockHeader, but I assume it is performed by the same nodes for the same purpose, and is just separated for performance optimization purposes. Please correct me if I'm wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct. The first one needs to be really light because it is done by the network protocol to prevent DDoS attacks (so it shouldn't be computationally expensive). ValidateBlock is the one you do to fully verify the block before executing it.

Choose a reason for hiding this comment

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

Can the implementation assume that b's header was already validated with ValidateBlockHeader?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, not. GossipSub is not the only way in which you can be receiving a new block. The syncer may also request blocks directly from known peers, in which case you will want to also do first the header (light) verification and then the full-block validation.

Comment on lines 45 to 47

// SignBlock determines how should blocks be signed for them to be considered valid by the consensus
// engine.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't quite understand how the signing works here, especially since only an error is returned. Is SignBlock supposed to modify next in place and add the local node's signature to it?
I find it rather unlikely that the Mir-based ordering subsystem would need an explicit trigger from the outside to know when to sign blocks, so probably SignBlock (and VerifyBlockSignature) won't really be used by us. If we do need to produce and verify signatures, we'd probably produce them somewhere deep within the protocol and verify them in ValidateBlock[Header]. Does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Total sense, in that case we can remove those. I will do that and remove those two.

@adlrocha
Copy link
Contributor Author

@matejpavlovic, I removed the two functions that we mentioned. If we are happy with this I will start the PR to the experimental fvm-m2 branch.

@adlrocha
Copy link
Contributor Author

adlrocha commented Oct 3, 2022

PR superseded by the one done to the experimental/fvm-m2: filecoin-project/lotus#9405

As long as no one strongly opposes, I suggest following this approach for BuilderNet:

  1. PR to consensus-shipyard for internal discussion.
  2. Supersede 1 with a PR to experimental/fvm-m2 when we feel is ready to merge.
  3. Rebase our consensus-shipyard/experimental/fvm-m2 when 2 is merged.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants