Skip to content
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

Add missing block and receipt message fields #9

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions p2p/proto/block.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
syntax = "proto3";
import "p2p/proto/common.proto";
import "p2p/proto/state.proto";
import "p2p/proto/transaction.proto";
import "p2p/proto/receipt.proto";
import "google/protobuf/timestamp.proto";

// for now, we assume a small consensus, so this fits in 1M. Else, these will be repeated
Expand All @@ -14,21 +16,25 @@ message Signatures {
// Note: commitments may change to be for the previous blocks like comet/tendermint
// hash of block header sent to L1
message BlockHeader {
Hash parent_header = 1;
uint64 number = 2;
google.protobuf.Timestamp time = 3; // TODO: see if this needs to be Felt252 or can be converted
Address sequencer_address = 4;
Merkle state_diffs = 5; // By order of (contract, key), taking last in case of duplicates.
Hash hash = 1;
IronGauntlets marked this conversation as resolved.
Show resolved Hide resolved
Hash parent_hash = 2;
uint64 number = 3;
google.protobuf.Timestamp time = 4; // TODO: see if this needs to be Felt252 or can be converted
Address sequencer_address = 5;
Merkle state_diffs = 6; // By order of (contract, key), taking last in case of duplicates.
// This means the proposer needs to sort after finishing the block (TBD: patricia? )
// State is optional and appears every X blocks for the last block. This is to support
// snapshot sync and also so that light nodes can sync on state without state diffs.
Patricia state = 6; // hash of contract and class patricia tries. Same as in L1. Later more trees will be included
Hash proof_fact = 7; // for Kth block behind. A hash of the output of the proof
Patricia state = 7; // hash of contract and class patricia tries. Same as in L1. Later more trees will be included
Hash proof_fact = 8; // for Kth block behind. A hash of the output of the proof

// The following merkles can be built on the fly while sequencing/validating txs.
Merkle transactions = 8; // By order of execution. TBD: required? the client can execute (powerful machine) and match state diff
Merkle events = 9; // By order of issuance. TBD: in receipts?
Merkle receipts = 10; // By order of issuance.
Merkle transactions = 9; // By order of execution. TBD: required? the client can execute (powerful machine) and match state diff
Merkle events = 10; // By order of issuance. TBD: in receipts?
Merkle receipts = 11; // By order of issuance.
string protocol_version = 12; // Starknet version
Felt252 extra_data = 13;
IronGauntlets marked this conversation as resolved.
Show resolved Hide resolved
Felt252 gas_price = 14;
}

message BlockProof {
Expand All @@ -45,6 +51,8 @@ message NewBlock {
}
}

// Requests a peer's CurrentBlockHeader
message CurrentBlockHeaderRequest {}
IronGauntlets marked this conversation as resolved.
Show resolved Hide resolved

// result is (BlockHeader, Signature?)* in order of creation (incr/dec)
message BlockHeadersRequest {
Expand Down Expand Up @@ -72,10 +80,12 @@ message BlockBodiesResponse {
optional BlockID id = 1; // may not appear if Fin is sent to end the whole response

oneof body_message {
StateDiff diff = 2;
Classes classes = 3;
BlockProof proof = 4;
Fin fin = 5;
StateDiff diff = 2;
Classes classes = 3;
BlockProof proof = 4;
Transactions transactions = 6;
Copy link
Collaborator

Choose a reason for hiding this comment

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

transactoins and events were not supposed to be part of the block body. this can be discussed. the idea was that with stark proofs we don't need to validate transactions by executing them. This is when there's proof which is K blocks behind. Until then the idea was to rely on the consensus (similarly to how Ethereum has block times and epochs).
The protocol can be defined so that txs are mandatory until K and then are optional.
Similarly for receipts & events (which were separated).

minor comment: numbering jumps from 4 to 6

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Are all forms of nodes expected to serve the RPC spec? If so, then having transactions and receipts as optional until after K blocks seems unnecessary because all nodes would be fetching them separately to serve the RPC requests. And since block bodies are chunked I don't see any benefit in fetching them separately as that would increase network overhead.

minor comment: numbering jumps from 4 to 6

I will update

Copy link
Collaborator

Choose a reason for hiding this comment

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

It means that to have the data needed to sync with the chain, a node doesn't need to keep transactions before the block with the proof. They can clean their DB. If a node wants to, it can of course keep whatever it wants.
As mentioned, they are not part of the block body, so no need for a client to fetch them. Even if they are included for new blocks, they would be optional and with a separate endpoint to fetch them (from those nodes that keep them beyond the optional point)

Copy link
Collaborator Author

@IronGauntlets IronGauntlets Nov 16, 2023

Choose a reason for hiding this comment

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

What defines whether something should be a part of the block body?

We don't need State Diff or Classes to be part of the block body because State Diff has a commitment which includes the Classes declared in the blocks, therefore, a peer can fetch them separately and verify the state diff commitment with the signature which is over the block hash and state diff commitment.

Note we will have to add BlockID and possibly Classes to State Diff. Also State diff commitment is over the state diff defined by feeder gateway not p2p state diff.

Why can't we include the BlockProof in the BlockHeader? Given other fields are so small 142KB+ other fields' size < 1MB.

If we make the above changes the block bodies can be removed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right, they can fetch them separately. So the thought was what will peers have to fetch in order to be an operational node. They need the current state, they don't need past transactions.

I agree the proof may be part of the header, as optional. Note that we can think of returning many headers in one message (and then it makes sense to have the proof outside)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So the thought was what will peers have to fetch in order to be an operational node.

Can you please elaborate on what you mean by an operational node and fetch which messages?

Also, fetching can be done in order but there is no guarantee the messages will arrive in order. So I am not sure what you mean.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was replying to "... includes the Classes declared in the blocks, therefore, a peer can fetch them separately". Operational means a node that can follow the chain. Such a node doesn't need transactions. If a client wants to check transactions state, they will enable that in a node, if they just want to track events, they will enable that. If they want to check state, they can do that.

What messages won't arrive in order? If we support out of order messages in a stream then each will have a reference to be able to order them, if needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Operational means a node that can follow the chain. Such a node doesn't need transactions. If a client wants to check transactions state, they will enable that in a node, if they just want to track events, they will enable that. If they want to check state, they can do that.

Why is the RPC spec not sufficient to serve this? I don't see the need to replicate this behaviour on the p2p side. Also, how does a peer verify that the events (or any other date) received are correct?

What messages won't arrive in order? If we support out of order messages in a stream then each will have a reference to be able to order them, if needed.

Messages from a single peer will indeed come in order over a stream but libp2p doesn't allow for ordered messages from multiple peers on a single stream without further multiplexing. If a peer requests information for a block from multiple peers that peer will have multiple streams open, per peer, and thus there is no guarantee block messages part will arrive in order.

Receipts receipts = 7;
Fin fin = 8;
}
}

Expand Down
5 changes: 4 additions & 1 deletion p2p/proto/receipt.proto
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
syntax = "proto3";
import "p2p/proto/common.proto";
import "p2p/proto/event.proto";
IronGauntlets marked this conversation as resolved.
Show resolved Hide resolved

message MessageToL1 {
Felt252 from_address = 1;
Expand Down Expand Up @@ -29,6 +30,7 @@ message Receipt {
uint32 range_check = 5;
uint32 poseidon = 6;
uint32 keccak = 7;
uint32 output = 8;
}

BuiltinCounter builtins = 1;
Expand All @@ -42,6 +44,7 @@ message Receipt {
repeated MessageToL1 messages_sent = 3;
ExecutionResources execution_resources = 4;
string revert_reason = 5;
Events events = 6;
IronGauntlets marked this conversation as resolved.
Show resolved Hide resolved
IronGauntlets marked this conversation as resolved.
Show resolved Hide resolved
}


Expand All @@ -68,7 +71,7 @@ message Receipt {
Felt252 contract_address = 2;
}

oneof receipt {
oneof type {
Invoke invoke = 1;
L1Handler l1_handler = 2;
Declare declare = 3;
Expand Down