Skip to content

Commit

Permalink
added PartialSigContainer wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
AKorpusenko committed Jul 25, 2024
1 parent b171973 commit d313a28
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 27 deletions.
4 changes: 2 additions & 2 deletions protocol/v2/ssv/runner/pre_consensus_justification.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
specqbft "github.com/ssvlabs/ssv-spec/qbft"
"github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"
"github.com/ssvlabs/ssv/protocol/v2/types"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -59,7 +59,7 @@ func (b *BaseRunner) validatePreConsensusJustifications(data *spectypes.Consensu
signers := make(map[spectypes.OperatorID]bool)
roots := make(map[[32]byte]bool)
rootCount := 0
partialSigContainer := ssv.NewPartialSigContainer(b.State.PreConsensusContainer.Quorum)
partialSigContainer := types.NewPartialSigContainer(b.State.PreConsensusContainer.Quorum)
for i, msg := range data.PreConsensusJustifications {
if err := msg.Validate(); err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions protocol/v2/ssv/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (

"github.com/ssvlabs/ssv/networkconfig"
"github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon"
"github.com/ssvlabs/ssv/protocol/v2/types"

"github.com/attestantio/go-eth2-client/spec/phase0"
ssz "github.com/ferranbt/fastssz"
specqbft "github.com/ssvlabs/ssv-spec/qbft"
specssv "github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"

"github.com/pkg/errors"
Expand Down Expand Up @@ -261,7 +261,7 @@ func (b *BaseRunner) basePostConsensusMsgProcessing(logger *zap.Logger, runner R
// basePartialSigMsgProcessing adds a validated (without signature verification) validated partial msg to the container, checks for quorum and returns true (and roots) if quorum exists
func (b *BaseRunner) basePartialSigMsgProcessing(
signedMsg *spectypes.PartialSignatureMessages,
container *specssv.PartialSigContainer,
container *types.PartialSigContainer,
) (bool, [][32]byte, error) {
roots := make([][32]byte, 0)
anyQuorum := false
Expand Down
3 changes: 1 addition & 2 deletions protocol/v2/ssv/runner/runner_signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
ssz "github.com/ferranbt/fastssz"
"github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
specssv "github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"

"github.com/ssvlabs/ssv/protocol/v2/types"
Expand Down Expand Up @@ -116,7 +115,7 @@ func (b *BaseRunner) verifyBeaconPartialSignature(signer spectypes.OperatorID, s
}

// Stores the container's existing signature or the new one, depending on their validity. If both are invalid, remove the existing one
func (b *BaseRunner) resolveDuplicateSignature(container *specssv.PartialSigContainer, msg *spectypes.PartialSignatureMessage) {
func (b *BaseRunner) resolveDuplicateSignature(container *types.PartialSigContainer, msg *spectypes.PartialSignatureMessage) {

// Check previous signature validity
previousSignature, err := container.GetSignature(msg.ValidatorIndex, msg.Signer, msg.SigningRoot)
Expand Down
21 changes: 10 additions & 11 deletions protocol/v2/ssv/runner/runner_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
specssv "github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"

"github.com/ssvlabs/ssv/protocol/v2/qbft/instance"
Expand All @@ -15,8 +14,8 @@ import (

// State holds all the relevant progress the duty execution progress
type State struct {
PreConsensusContainer *specssv.PartialSigContainer
PostConsensusContainer *specssv.PartialSigContainer
PreConsensusContainer *types.PartialSigContainer
PostConsensusContainer *types.PartialSigContainer
RunningInstance *instance.Instance
DecidedValue []byte //spectypes.Encoder
// CurrentDuty is the duty the node pulled locally from the beacon node, might be different from decided duty
Expand All @@ -27,16 +26,16 @@ type State struct {

func NewRunnerState(quorum uint64, duty spectypes.Duty) *State {
return &State{
PreConsensusContainer: specssv.NewPartialSigContainer(quorum),
PostConsensusContainer: specssv.NewPartialSigContainer(quorum),
PreConsensusContainer: types.NewPartialSigContainer(quorum),
PostConsensusContainer: types.NewPartialSigContainer(quorum),

StartingDuty: duty,
Finished: false,
}
}

// ReconstructBeaconSig aggregates collected partial beacon sigs
func (pcs *State) ReconstructBeaconSig(container *specssv.PartialSigContainer, root [32]byte, validatorPubKey []byte, validatorIndex phase0.ValidatorIndex) ([]byte, error) {
func (pcs *State) ReconstructBeaconSig(container *types.PartialSigContainer, root [32]byte, validatorPubKey []byte, validatorIndex phase0.ValidatorIndex) ([]byte, error) {
// Reconstruct signatures
signature, err := types.ReconstructSignature(container, root, validatorPubKey[:], validatorIndex)
if err != nil {
Expand Down Expand Up @@ -68,8 +67,8 @@ func (pcs *State) Decode(data []byte) error {
func (pcs *State) MarshalJSON() ([]byte, error) {
// Create alias without duty
type StateAlias struct {
PreConsensusContainer *specssv.PartialSigContainer
PostConsensusContainer *specssv.PartialSigContainer
PreConsensusContainer *types.PartialSigContainer
PostConsensusContainer *types.PartialSigContainer
RunningInstance *instance.Instance
DecidedValue []byte
Finished bool
Expand All @@ -91,7 +90,7 @@ func (pcs *State) MarshalJSON() ([]byte, error) {
} else if committeeDuty, ok := pcs.StartingDuty.(*spectypes.CommitteeDuty); ok {
alias.CommitteeDuty = committeeDuty
} else {
return nil, errors.New("can't marshal because BaseRunner.State.StartingDuty isn't BeaconDuty or CommitteeDuty")
return nil, errors.New("can't marshal because BaseState.StartingDuty isn't BeaconDuty or CommitteeDuty")
}
}
byts, err := json.Marshal(alias)
Expand All @@ -103,8 +102,8 @@ func (pcs *State) UnmarshalJSON(data []byte) error {

// Create alias without duty
type StateAlias struct {
PreConsensusContainer *specssv.PartialSigContainer
PostConsensusContainer *specssv.PartialSigContainer
PreConsensusContainer *types.PartialSigContainer
PostConsensusContainer *types.PartialSigContainer
RunningInstance *instance.Instance
DecidedValue []byte
Finished bool
Expand Down
4 changes: 2 additions & 2 deletions protocol/v2/ssv/runner/runner_validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
spec "github.com/attestantio/go-eth2-client/spec/phase0"
ssz "github.com/ferranbt/fastssz"
"github.com/pkg/errors"
specssv "github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"
"github.com/ssvlabs/ssv/protocol/v2/types"
)

func (b *BaseRunner) ValidatePreConsensusMsg(runner Runner, signedMsg *spectypes.PartialSignatureMessages) error {
Expand All @@ -29,7 +29,7 @@ func (b *BaseRunner) ValidatePreConsensusMsg(runner Runner, signedMsg *spectypes
}

// Verify each signature in container removing the invalid ones
func (b *BaseRunner) FallBackAndVerifyEachSignature(container *specssv.PartialSigContainer, root [32]byte,
func (b *BaseRunner) FallBackAndVerifyEachSignature(container *types.PartialSigContainer, root [32]byte,
committee []*spectypes.ShareMember, validatorIndex spec.ValidatorIndex) {
signatures := container.GetSignatures(validatorIndex, root)

Expand Down
9 changes: 4 additions & 5 deletions protocol/v2/ssv/validator/non_committee_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/herumi/bls-eth-go-binary/bls"
specqbft "github.com/ssvlabs/ssv-spec/qbft"
specssv "github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"
"github.com/ssvlabs/ssv/exporter/convert"
"github.com/ssvlabs/ssv/ibft/storage"
Expand All @@ -32,7 +31,7 @@ type CommitteeObserver struct {
ValidatorStore registrystorage.ValidatorStore
newDecidedHandler qbftcontroller.NewDecidedHandler
Roots map[[32]byte]spectypes.BeaconRole
postConsensusContainer map[phase0.ValidatorIndex]*specssv.PartialSigContainer
postConsensusContainer map[phase0.ValidatorIndex]*types.PartialSigContainer
}

type CommitteeObserverOptions struct {
Expand Down Expand Up @@ -70,7 +69,7 @@ func NewCommitteeObserver(identifier convert.MessageID, opts CommitteeObserverOp
ValidatorStore: opts.ValidatorStore,
newDecidedHandler: opts.NewDecidedHandler,
Roots: make(map[[32]byte]spectypes.BeaconRole),
postConsensusContainer: make(map[phase0.ValidatorIndex]*specssv.PartialSigContainer),
postConsensusContainer: make(map[phase0.ValidatorIndex]*types.PartialSigContainer),
}
}

Expand Down Expand Up @@ -166,7 +165,7 @@ func (ncv *CommitteeObserver) processMessage(
validator := ncv.ValidatorStore.ValidatorByIndex(msg.ValidatorIndex)
container, ok := ncv.postConsensusContainer[msg.ValidatorIndex]
if !ok {
container = specssv.NewPartialSigContainer(validator.Quorum())
container = types.NewPartialSigContainer(validator.Quorum())
ncv.postConsensusContainer[msg.ValidatorIndex] = container
}
if container.HasSigner(msg.ValidatorIndex, msg.Signer, msg.SigningRoot) {
Expand Down Expand Up @@ -194,7 +193,7 @@ func (ncv *CommitteeObserver) processMessage(

// Stores the container's existing signature or the new one, depending on their validity. If both are invalid, remove the existing one
// copied from BaseRunner
func (ncv *CommitteeObserver) resolveDuplicateSignature(container *specssv.PartialSigContainer, msg *spectypes.PartialSignatureMessage, share *types.SSVShare) {
func (ncv *CommitteeObserver) resolveDuplicateSignature(container *types.PartialSigContainer, msg *spectypes.PartialSignatureMessage, share *types.SSVShare) {
// Check previous signature validity
previousSignature, err := container.GetSignature(msg.ValidatorIndex, msg.Signer, msg.SigningRoot)
if err == nil {
Expand Down
9 changes: 6 additions & 3 deletions protocol/v2/types/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import (
"encoding/hex"

"github.com/attestantio/go-eth2-client/spec/phase0"

"github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
specssv "github.com/ssvlabs/ssv-spec/ssv"
spectypes "github.com/ssvlabs/ssv-spec/types"
"go.uber.org/zap"
)
Expand All @@ -28,7 +26,12 @@ func init() {
}
}

func ReconstructSignature(ps *specssv.PartialSigContainer, root [32]byte, validatorPubKey []byte, validatorIndex phase0.ValidatorIndex) ([]byte, error) {
func ReconstructSignature(
ps *PartialSigContainer,
root [32]byte,
validatorPubKey []byte,
validatorIndex phase0.ValidatorIndex,
) ([]byte, error) {
// Reconstruct signatures
signature, err := spectypes.ReconstructSignatures(ps.Signatures[validatorIndex][rootHex(root)])
if err != nil {
Expand Down
110 changes: 110 additions & 0 deletions protocol/v2/types/partial_sig_container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package types

import (
"github.com/attestantio/go-eth2-client/spec/phase0"

"github.com/pkg/errors"
"github.com/ssvlabs/ssv-spec/types"
)

type PartialSigContainer struct {
Signatures map[phase0.ValidatorIndex]map[string]map[types.OperatorID][]byte
// Quorum is the number of min signatures needed for quorum
Quorum uint64
}

func NewPartialSigContainer(quorum uint64) *PartialSigContainer {
return &PartialSigContainer{
Quorum: quorum,
Signatures: make(map[phase0.ValidatorIndex]map[string]map[types.OperatorID][]byte),
}
}

func (ps *PartialSigContainer) AddSignature(sigMsg *types.PartialSignatureMessage) {
if ps.Signatures[sigMsg.ValidatorIndex] == nil {
ps.Signatures[sigMsg.ValidatorIndex] = make(map[string]map[uint64][]byte)
}
if ps.Signatures[sigMsg.ValidatorIndex][rootHex(sigMsg.SigningRoot)] == nil {
ps.Signatures[sigMsg.ValidatorIndex][rootHex(sigMsg.SigningRoot)] = make(map[types.OperatorID][]byte)
}
m := ps.Signatures[sigMsg.ValidatorIndex][rootHex(sigMsg.SigningRoot)]

if m[sigMsg.Signer] == nil {
m[sigMsg.Signer] = make([]byte, 96)
copy(m[sigMsg.Signer], sigMsg.PartialSignature)
}
}

// Returns if container has signature for signer and signing root
func (ps *PartialSigContainer) HasSigner(validatorIndex phase0.ValidatorIndex, signer types.OperatorID, signingRoot [32]byte) bool {
if ps.Signatures[validatorIndex] == nil {
return false
}
if ps.Signatures[validatorIndex][rootHex(signingRoot)] == nil {
return false
}
return ps.Signatures[validatorIndex][rootHex(signingRoot)][signer] != nil
}

// Return signature for given root and signer
func (ps *PartialSigContainer) GetSignature(validatorIndex phase0.ValidatorIndex, signer types.OperatorID, signingRoot [32]byte) (types.Signature, error) {
if ps.Signatures[validatorIndex] == nil {
return nil, errors.New("Dont have signature for the given validator index")
}
if ps.Signatures[validatorIndex][rootHex(signingRoot)] == nil {
return nil, errors.New("Dont have signature for the given signing root")
}
if ps.Signatures[validatorIndex][rootHex(signingRoot)][signer] == nil {
return nil, errors.New("Dont have signature on signing root for the given signer")
}
return ps.Signatures[validatorIndex][rootHex(signingRoot)][signer], nil
}

// Return signature map for given root
func (ps *PartialSigContainer) GetSignatures(validatorIndex phase0.ValidatorIndex, signingRoot [32]byte) map[types.OperatorID][]byte {
if ps.Signatures[validatorIndex] == nil {
return nil
}
return ps.Signatures[validatorIndex][rootHex(signingRoot)]
}

// Remove signer from signature map
func (ps *PartialSigContainer) Remove(validatorIndex phase0.ValidatorIndex, signer uint64, signingRoot [32]byte) {
if ps.Signatures[validatorIndex] == nil {
return
}
if ps.Signatures[validatorIndex][rootHex(signingRoot)] == nil {
return
}
if ps.Signatures[validatorIndex][rootHex(signingRoot)][signer] == nil {
return
}
delete(ps.Signatures[validatorIndex][rootHex(signingRoot)], signer)
}

func (ps *PartialSigContainer) ReconstructSignature(root [32]byte, validatorPubKey []byte, validatorIndex phase0.ValidatorIndex) ([]byte, error) {
// Reconstruct signatures
if ps.Signatures[validatorIndex] == nil {
return nil, errors.New("no signatures for the given validator index")
}
if ps.Signatures[validatorIndex][rootHex(root)] == nil {
return nil, errors.New("no signatures for the given signing root")
}
signature, err := types.ReconstructSignatures(ps.Signatures[validatorIndex][rootHex(root)])
if err != nil {
return nil, errors.Wrap(err, "failed to reconstruct signatures")
}

// Get validator pub key copy (This avoids cgo Go pointer to Go pointer issue)
validatorPubKeyCopy := make([]byte, len(validatorPubKey))
copy(validatorPubKeyCopy, validatorPubKey)

if err := types.VerifyReconstructedSignature(signature, validatorPubKeyCopy, root); err != nil {
return nil, errors.Wrap(err, "failed to verify reconstruct signature")
}
return signature.Serialize(), nil
}

func (ps *PartialSigContainer) HasQuorum(validatorIndex phase0.ValidatorIndex, root [32]byte) bool {
return uint64(len(ps.Signatures[validatorIndex][rootHex(root)])) >= ps.Quorum
}

0 comments on commit d313a28

Please sign in to comment.