Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9f64a7b
Spec - filter committee duties per slot validator duties (#467)
y0sher Jul 22, 2024
6921f58
Spec - check att and sync duties exist before submitting (#468)
y0sher Jul 22, 2024
96429fb
Meta - Update to go1.22 (#474)
MatheusFranco99 Aug 14, 2024
8edc50a
Meta - Update dependencies (#483)
MatheusFranco99 Aug 20, 2024
9bf4379
Meta - Fix static analysis issues (#480)
MatheusFranco99 Aug 20, 2024
642d9d2
Meta - Drop unnecessary nolint comments (#477)
MatheusFranco99 Aug 20, 2024
02beeb9
Spec - Share length validation (#478)
MatheusFranco99 Aug 20, 2024
5daa242
Meta - Drop redundant error (#475)
MatheusFranco99 Aug 20, 2024
b0f2b4d
Spec - Drop redundant validation for decided messages (#476)
MatheusFranco99 Aug 20, 2024
c61218a
Spec - Sort signers in decided message (#484)
MatheusFranco99 Aug 20, 2024
9abeeec
Spec - Stop processing after decided (#487)
MatheusFranco99 Aug 20, 2024
496d839
Spec - Drop leftover error check (#469)
MatheusFranco99 Aug 20, 2024
96fac27
Add documentation for the SSV module
MatheusFranco99 Aug 30, 2024
8a62e82
Add documentation for the QBFT module
MatheusFranco99 Aug 30, 2024
a42db96
Add README for types
MatheusFranco99 Aug 30, 2024
3316705
Rename documentation file in QBFT
MatheusFranco99 Sep 3, 2024
a636f0c
Rename documentation file in SSV
MatheusFranco99 Sep 3, 2024
0b9e4f7
Put types' module documentation in separate file (as in other modules)
MatheusFranco99 Sep 3, 2024
ec914af
Increase the size of images
MatheusFranco99 Sep 3, 2024
b1ae3e6
Add more details to the SSVMessage.MessageID
MatheusFranco99 Sep 3, 2024
8fcf27d
Update main README
MatheusFranco99 Sep 3, 2024
7060cac
Update p2p documentation
MatheusFranco99 Sep 3, 2024
770e204
Fix all committees with the same ID
MatheusFranco99 Sep 5, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.20.x
go-version: 1.22.x

- name: Get Dependencies
run: go get -v -t -d ./...
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.20.x
go-version: 1.22.x

- name: Get Dependencies
run: go get -v -t -d ./...
Expand Down
189 changes: 25 additions & 164 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,182 +5,43 @@

Secret Shared Validator ('SSV') is a unique technology that enables the distributed control and operation of an Ethereum validator.

SSV uses an MPC threshold scheme with a consensus layer on top ([Istanbul BFT](https://arxiv.org/pdf/2002.03613.pdf)),
that governs the network. \
Its core strength is in its robustness and fault tolerance which leads the way for an open network of staking operators
SSV uses an MPC threshold scheme with a consensus layer on top ([Istanbul BFT](https://arxiv.org/pdf/2002.03613.pdf)) to execute Ethereum duties in a secure way.

Its core strength is in its robustness and fault tolerance which leads the way for an open network of staking operators
to run validators in a decentralized and trustless way.

## SSV Spec
This repo contains the spec for SSV.Network node.

### SSVMessage
SSV network message is called SSVMessage, it includes a MessageID and MsgType to route messages within the SSV node code, and, data for the actual message (QBFT/ pre/ Post consensus messages for example).

Any message data struct must be signed and nested within a signed message struct which follows the MessageSignature interface.
A signed message structure includes the signature over the data structure, the signed root and signer list.

#### QBFT Message
This type of message is used for all consensus messages
```go
type Message struct {
MsgType MessageType
Height Height // QBFT instance Height
Round Round // QBFT round for which the msg is for
Identifier []byte // instance Identifier this msg belongs to
Data []byte
}
```
This repo contains the spec of the SSV protocol for the SSV.Network node.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the the SSV.Network node, perhaps just the SSV node (or the SSV network node) ?

Update: I see, it's called like that through the docs ... a redundant term to be honest, I'd change it to SSV network node if that's easy to do.


#### Partial Signature Message
Used for pre and post consensus sigantures for collecting partial BN signatures and then reconstructing them
```go
type PartialSignatureMessage struct {
Type PartialSigMsgType
PartialSignature []byte // The beacon chain partial Signature for a duty
SigningRoot []byte // the root signed in PartialSignature
Signers []types.OperatorID
}
```
## The Network

### Signing messages
The KeyManager interface has a function to sign roots, a slice of bytes.
The root is computed over the original data structure (which follows the MessageRoot interface), domain and signature type.

**Use ComputeSigningRoot and ComputeSignatureDomain functions for signing**
```go
func ComputeSigningRoot(data MessageRoot, domain SignatureDomain) ([]byte, error) {
dataRoot, err := data.GetRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get root from MessageRoot")
}

ret := sha256.Sum256(append(dataRoot[:], domain...))
return ret[:], nil
}
```
```go
func ComputeSignatureDomain(domain DomainType, sigType SignatureType) SignatureDomain {
return SignatureDomain(append(domain, sigType...))
}
```
The SSV network is composed of several `operators`. Each operator is identified by a unique [`OperatorID`](./types/docs/README.md#operatorid-and-committeeid) and holds a netwok key for message authentication.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

several -> many

holds a netwok key for message authentication. -> holds a network key for message authentication on SSV network.


Domain Constants:

| Domain | Value | Description |
|----------------|-------------------------------|-----------------------------------|
| Primus Testnet | DomainType ("primus_testnet") | Domain for the the Primus testnet |

Signature type Constants:

| Signature Type | Value | Description |
|----------------------|----------------------|------------------------------------------|
| QBFTSignatureType | [] byte {1, 0, 0, 0} | SignedMessage specific signatures |
| PartialSignatureType | [] byte {2, 0, 0, 0} | PostConsensusMessage specific signatures |
| DKGSignatureType | [] byte {3, 0, 0, 0} | PostConsensusMessage specific signatures |

## Validator and Runners
A validator instance is created for each validator independently, each validator will have multiple Runner for each beacon chain duty type (Attestations, Blocks, etc.)
Duty runners are responsible for processing incoming messages and act upon them, completing a full beacon chain duty cycle.

Each duty starts by calling the StartNewDuty func in the respective Runner.
StartNewDuty might return error if can't start a new duty, depending on the previous duty life cycle.
As a general rule, when a runner is executing a duty in the consensus phase, a new duty can't start.
Pre/ Post partial signature collection will not enable starting a new duty if not completed except if timed out.

**Attestation Duty Full Cycle:**\
-> Wait to slot 1/3\
   -> Received new beacon chain duty\
      -> Check can start a new consensus instance\
         -> Come to consensus on duty + attestation data\
            -> Broadcast and collect partial signature to reconstruct signature\
               -> Reconstruct signature, broadcast to BN

**Block Proposal Duty Full Cycle:**\
-> Received new beacon chain duty\
   -> Check can start a new consensus instance\
      -> Sign partial RANDAO and wait for other signatures\
         -> Come to consensus on duty + beacon block\
            -> Broadcast and collect partial signature to reconstruct signature\
               -> Reconstruct signature, broadcast to BN

**Attestation Aggregator Duty Full Cycle:**\
-> Received new beacon chain duty\
   -> Check can start a new consensus instance\
      -> Sign partial selection proof and wait for other signatures\
         -> Wait to slot 2/3\
            -> Come to consensus on duty + aggregated selection proof\
               -> Broadcast and collect partial signature to reconstruct signature\
                  -> Reconstruct signature, broadcast to BN

**Sync Committee Duty Full Cycle:**\
-> Wait to slot 1/3\
   -> Received new beacon chain duty\
      -> Check can start a new consensus instance\
         -> Come to consensus on duty + sync message\
            -> Broadcast and collect partial signature to reconstruct signature\
               -> Reconstruct signature, broadcast to BN

**Sync Committee Aggregator Duty Full Cycle:**\
-> Received new beacon chain duty\
   -> Check can start a new consensus instance\
      -> Locally get sync subcommittee indexes for slot\
         -> Partial sign contribution proofs (for each subcommittee) and wait for other signatures\
            -> wait to slot 2/3\
               -> Come to consensus on duty + contribution (for each subcommittee)\
                  -> Broadcast and collect partial signature to reconstruct signature\
                     -> Reconstruct signature, broadcast to BN

A runner holds a QBFT controller for processing QBFT messages and a State which keeps progress for all stages of duty execution: pre/ post consensus messages.
Partial signatures are collected and reconstructed (when threshold reached) to be broadcasted to the BN network.

## Validator Share
A share is generated and broadcasted publicly when a new SSV validator is registered to its operators.
Shares include:
- Node ID: The Operator ID the share belongs to
- Validator Public Key
- Committee: An array of Nodes that constitute the SSV validator committee. A node must include it's NodeID and share public key.
- Domain

```go
type Share struct {
OperatorID OperatorID
ValidatorPubKey ValidatorPK
SharePubKey []byte
Committee []*Operator
Quorum, PartialQuorum uint64
DomainType DomainType
Graffiti []byte
}
```
Every `validator` is registered to a unique committee of operators to execute its duties. When this happens, [`Share`](./types/docs/README.md#share--sharemember-and-committeemember--operator) objext are broadcasted publicly to the network.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

objext -> objects

are broadcasted publicly

perhaps worth mentioning what "broadcasted publicly" means, is it through writing those shared into Ethereum smart contract or just sending messages to be delivered through SSV network


## Node
A node represents a registered SSV operator, each node has a unique ID and encryption key which is used to encrypt assigned shares.
NodeIDs are extremely important as they are used when splitting a validator key via Shamir-Secret-Sharing, later on they are used to verify messages and reconstruct signatures.
A single `committee` of operators may run several validators at the same time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

run several validators at the same time -> run several validators (of independent users) at the same time


Shares use the Node data (for committee) to verify that incoming messages were signed by a committee member
The following image illustrates these relations.

```go
type Node struct {
NodeID NodeID
PubKey []byte
}
```
<p align="center",float="left">
<img src="./ssv/docs/network.drawio.png", width="45%" height="10%">
</p>

To execute the validators' duties, the operators exchange messages in the network. These messages are of type [`SignedSSVMessage`](./types/README.md#signedssvmessage-and-ssvmessage) which wraps either a consensus message ([`qbft.Message`](qbft/docs/README.md#message)) or a partial signature message ([`PartialSignatureMessages`](./types/README.md#partialsignaturemessages)).

To understand the protocol for executing duties, check out the [protocol explanation file](./ssv/README.md). The protocol is built upon the QBFT BFT consensus protocol. To understand our specification for the QBFT protocol, check the [QBFT module file](./qbft/README.md).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To understand the protocol for executing duties, check out the protocol explanation file. The protocol is built upon the QBFT BFT consensus protocol. To understand our specification for the QBFT protocol, check the QBFT module file.

->

To understand the protocol for executing duties check out protocol overview doc. Note, it's built around QBFT BFT consensus protocol.


### NodeID and share creation example
NodeID is unique to each node, starting from ID 1 and incrementally going froward.
Each ValidatorPK has a committee of nodes, each with a unique ID, share and share public key.
Also, for more details, check the documentation for the [`Operator`](./types/docs/README.md#share--sharemember-and-committeemember--operator), [`Validator`](./ssv/docs/README.md#validator), and [`Committee`](./ssv/docs/README.md#committee) structures.

f(x) = a0 + a1X + a2X^2+a3X^3 + ... + ak-1X^(k-1)\
f(0) = a0 = secret\
Share1 = f(NodeID1)\
Share1 = f(NodeID1)\
...
## Spec tests

### Spec tests
The [spec tests](ssv/spectest) are a generated as a json file that can be run in any implementation. They test the various flows within the SSV package, treating the consensus protocol as as black box.
The [spec tests](ssv/spectest) are generated as a json file that can be run in any implementation. They test the various flows within the SSV package, treating the consensus protocol as as black box.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can be run in any implementation -> can be run in against implementation

To generate all json spec tests, run:

```console
foo@bar:~$ go generate ./...
foo@bar:~$ make generate-jsons
```
Then run all tests with

```console
foo@bar:~$ make test
```
Then run all tests
46 changes: 23 additions & 23 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
module github.com/ssvlabs/ssv-spec

go 1.20
go 1.22

require (
github.com/attestantio/go-eth2-client v0.21.3
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
github.com/ethereum/go-ethereum v1.12.0
github.com/ethereum/go-ethereum v1.14.8
github.com/ferranbt/fastssz v0.1.3
github.com/goccy/go-yaml v1.11.3 // indirect
github.com/google/go-cmp v0.6.0
github.com/herumi/bls-eth-go-binary v1.29.1
github.com/libp2p/go-libp2p v0.27.4
github.com/libp2p/go-libp2p-pubsub v0.9.3
github.com/libp2p/go-libp2p v0.36.1
github.com/libp2p/go-libp2p-pubsub v0.11.0
github.com/pkg/errors v0.9.1
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
)

require github.com/google/go-cmp v0.5.9

require (
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/goccy/go-yaml v1.11.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/holiman/uint256 v1.3.1 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -37,22 +36,23 @@ require (
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.9.0 // indirect
github.com/multiformats/go-multiaddr v0.13.0 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.8.1 // indirect
github.com/multiformats/go-multihash v0.2.1 // indirect
github.com/multiformats/go-multistream v0.4.1 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/sys v0.19.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.30.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
)
Loading