Skip to content

Commit

Permalink
finished first working implementation of bls aggregation service
Browse files Browse the repository at this point in the history
tested and working with inc-sq, but still probably needs good brutal review and some more tests (multiquorum for eg)
  • Loading branch information
samlaf committed Oct 10, 2023
1 parent 4cfac13 commit 52fff37
Show file tree
Hide file tree
Showing 13 changed files with 754 additions and 247 deletions.
15 changes: 10 additions & 5 deletions crypto/bls/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ func NewZeroG1Point() *G1Point {
}

// Add another G1 point to this one
func (p *G1Point) Add(p2 *G1Point) {
func (p *G1Point) Add(p2 *G1Point) *G1Point {
p.G1Affine.Add(p.G1Affine, p2.G1Affine)
return p
}

// Sub another G1 point from this one
func (p *G1Point) Sub(p2 *G1Point) {
func (p *G1Point) Sub(p2 *G1Point) *G1Point {
p.G1Affine.Sub(p.G1Affine, p2.G1Affine)
return p
}

// VerifyEquivalence verifies G1Point is equivalent the G2Point
Expand Down Expand Up @@ -99,13 +101,15 @@ func NewZeroG2Point() *G2Point {
}

// Add another G2 point to this one
func (p *G2Point) Add(p2 *G2Point) {
func (p *G2Point) Add(p2 *G2Point) *G2Point {
p.G2Affine.Add(p.G2Affine, p2.G2Affine)
return p
}

// Sub another G2 point from this one
func (p *G2Point) Sub(p2 *G2Point) {
func (p *G2Point) Sub(p2 *G2Point) *G2Point {
p.G2Affine.Sub(p.G2Affine, p2.G2Affine)
return p
}

func (p *G2Point) Serialize() []byte {
Expand All @@ -124,8 +128,9 @@ func NewZeroSignature() *Signature {
return &Signature{NewZeroG1Point()}
}

func (s *Signature) Add(otherS *Signature) {
func (s *Signature) Add(otherS *Signature) *Signature {
s.G1Point.Add(otherS.G1Point)
return s
}

// Verify a message against a public key
Expand Down
7 changes: 5 additions & 2 deletions services/avsregistry/avsregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package avsregistry
import (
"context"

blsoperatorstateretrievar "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSOperatorStateRetriever"
"github.com/Layr-Labs/eigensdk-go/types"
)

Expand All @@ -11,9 +12,11 @@ import (
type AvsRegistryService interface {
// GetOperatorsAvsState returns the state of an avs wrt to a list of quorums at a certain block.
// The state includes the operatorId, pubkey, and staking amount in each quorum.
GetOperatorsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNumber) (map[types.OperatorId]types.OperatorAvsState, error)
GetOperatorsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNum) (map[types.OperatorId]types.OperatorAvsState, error)
// GetQuorumsAvsStateAtBlock returns the aggregated data for a list of quorums at a certain block.
// The aggregated data includes the aggregated pubkey and total stake in each quorum.
// This information is derivable from the Operators Avs State (returned from GetOperatorsAvsStateAtBlock), but this function is provided for convenience.
GetQuorumsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNumber) (map[types.QuorumNum]types.QuorumAvsState, error)
GetQuorumsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNum) (map[types.QuorumNum]types.QuorumAvsState, error)
// GetCheckSignaturesIndices returns the registry indices of the nonsigner operators specified by nonSignerOperatorIds who were registered at referenceBlockNumber.
GetCheckSignaturesIndices(ctx context.Context, referenceBlockNumber types.BlockNum, quorumNumbers []types.QuorumNum, nonSignerOperatorIds []types.OperatorId) (blsoperatorstateretrievar.BLSOperatorStateRetrieverCheckSignaturesIndices, error)
}
12 changes: 7 additions & 5 deletions services/avsregistry/avsregistry_chaincaller.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import (
"github.com/Layr-Labs/eigensdk-go/types"
)

// AvsRegistryService is a wrapper around AvsRegistryReader that transforms the data into
// nicer golang types that are easier to work with
type AvsRegistryServiceChainCaller struct {
avsregistry.AvsRegistryReader
elReader elcontracts.ELReader
avsRegistryReader avsregistry.AvsRegistryReader
pubkeyCompendiumService pcservice.PubkeyCompendiumService
logger logging.Logger
}
Expand All @@ -24,16 +26,16 @@ var _ AvsRegistryService = (*AvsRegistryServiceChainCaller)(nil)
func NewAvsRegistryServiceChainCaller(avsRegistryReader avsregistry.AvsRegistryReader, elReader elcontracts.ELReader, pubkeyCompendiumService pcservice.PubkeyCompendiumService, logger logging.Logger) *AvsRegistryServiceChainCaller {
return &AvsRegistryServiceChainCaller{
elReader: elReader,
avsRegistryReader: avsRegistryReader,
AvsRegistryReader: avsRegistryReader,
pubkeyCompendiumService: pubkeyCompendiumService,
logger: logger,
}
}

func (ar *AvsRegistryServiceChainCaller) GetOperatorsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNumber) (map[types.OperatorId]types.OperatorAvsState, error) {
func (ar *AvsRegistryServiceChainCaller) GetOperatorsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNum) (map[types.OperatorId]types.OperatorAvsState, error) {
operatorsAvsState := make(map[types.OperatorId]types.OperatorAvsState)
// Get operator state for each quorum by querying BLSOperatorStateRetriever (this call is why this service implementation is called ChainCaller)
operatorsStakesInQuorums, err := ar.avsRegistryReader.GetOperatorsStakeInQuorumsAtBlock(ctx, quorumNumbers, blockNumber)
operatorsStakesInQuorums, err := ar.AvsRegistryReader.GetOperatorsStakeInQuorumsAtBlock(ctx, quorumNumbers, blockNumber)
if err != nil {
ar.logger.Error("Failed to get operator state", "err", err, "service", "AvsRegistryServiceChainCaller")
return nil, err
Expand Down Expand Up @@ -69,7 +71,7 @@ func (ar *AvsRegistryServiceChainCaller) GetOperatorsAvsStateAtBlock(ctx context
return operatorsAvsState, nil
}

func (ar *AvsRegistryServiceChainCaller) GetQuorumsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNumber) (map[types.QuorumNum]types.QuorumAvsState, error) {
func (ar *AvsRegistryServiceChainCaller) GetQuorumsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNum) (map[types.QuorumNum]types.QuorumAvsState, error) {
operatorsAvsState, err := ar.GetOperatorsAvsStateAtBlock(ctx, quorumNumbers, blockNumber)
if err != nil {
ar.logger.Error("Failed to get operator state", "err", err, "service", "AvsRegistryServiceChainCaller")
Expand Down
8 changes: 4 additions & 4 deletions services/avsregistry/avsregistry_chaincaller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,14 @@ func TestAvsRegistryServiceChainCaller_GetOperatorsAvsState(t *testing.T) {
name string
mocksInitializationFunc func(*chainiomocks.MockAvsRegistryReader, *chainiomocks.MockELReader, *servicemocks.MockPubkeyCompendiumService)
queryQuorumNumbers []types.QuorumNum
queryBlockNum types.BlockNumber
queryBlockNum types.BlockNum
wantErr error
wantOperatorsAvsStateDict map[types.OperatorId]types.OperatorAvsState
}{
{
name: "should return operatorsAvsState",
mocksInitializationFunc: func(mockAvsRegistryReader *chainiomocks.MockAvsRegistryReader, mockElReader *chainiomocks.MockELReader, mockPubkeyCompendiumService *servicemocks.MockPubkeyCompendiumService) {
mockAvsRegistryReader.EXPECT().GetOperatorsStakeInQuorumsAtBlock(context.Background(), []types.QuorumNum{1}, types.BlockNumber(1)).Return([][]blsoperatorstateretrievar.BLSOperatorStateRetrieverOperator{
mockAvsRegistryReader.EXPECT().GetOperatorsStakeInQuorumsAtBlock(context.Background(), []types.QuorumNum{1}, types.BlockNum(1)).Return([][]blsoperatorstateretrievar.BLSOperatorStateRetrieverOperator{
{
{
OperatorId: testOperator.operatorId,
Expand Down Expand Up @@ -166,14 +166,14 @@ func TestAvsRegistryServiceChainCaller_GetQuorumsAvsState(t *testing.T) {
name string
mocksInitializationFunc func(*chainiomocks.MockAvsRegistryReader, *chainiomocks.MockELReader, *servicemocks.MockPubkeyCompendiumService)
queryQuorumNumbers []types.QuorumNum
queryBlockNum types.BlockNumber
queryBlockNum types.BlockNum
wantErr error
wantQuorumsAvsStateDict map[types.QuorumNum]types.QuorumAvsState
}{
{
name: "should return operatorsAvsState",
mocksInitializationFunc: func(mockAvsRegistryReader *chainiomocks.MockAvsRegistryReader, mockElReader *chainiomocks.MockELReader, mockPubkeyCompendiumService *servicemocks.MockPubkeyCompendiumService) {
mockAvsRegistryReader.EXPECT().GetOperatorsStakeInQuorumsAtBlock(context.Background(), []types.QuorumNum{1}, types.BlockNumber(1)).Return([][]blsoperatorstateretrievar.BLSOperatorStateRetrieverOperator{
mockAvsRegistryReader.EXPECT().GetOperatorsStakeInQuorumsAtBlock(context.Background(), []types.QuorumNum{1}, types.BlockNum(1)).Return([][]blsoperatorstateretrievar.BLSOperatorStateRetrieverOperator{
{
{
OperatorId: testOperator.operatorId,
Expand Down
72 changes: 72 additions & 0 deletions services/avsregistry/avsregistry_fake.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package avsregistry

import (
"context"
"errors"
"math/big"

blsoperatorstateretrievar "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSOperatorStateRetriever"
"github.com/Layr-Labs/eigensdk-go/crypto/bls"
"github.com/Layr-Labs/eigensdk-go/types"
)

type FakeAvsRegistryService struct {
operators map[types.BlockNum]map[types.OperatorId]types.OperatorAvsState
}

func NewFakeAvsRegistryService(blockNum types.BlockNum, operators []types.TestOperator) *FakeAvsRegistryService {
fakeAvsRegistryService := &FakeAvsRegistryService{
operators: map[types.BlockNum]map[types.OperatorId]types.OperatorAvsState{
blockNum: {},
},
}
for _, operator := range operators {
fakeAvsRegistryService.operators[blockNum][operator.OperatorId] = types.OperatorAvsState{
OperatorId: operator.OperatorId,
Pubkeys: types.OperatorPubkeys{G1Pubkey: operator.BlsKeypair.GetPubKeyG1(), G2Pubkey: operator.BlsKeypair.GetPubKeyG2()},
StakePerQuorum: operator.StakePerQuorum,
BlockNumber: blockNum,
}
}
return fakeAvsRegistryService
}

var _ AvsRegistryService = (*FakeAvsRegistryService)(nil)

func (f *FakeAvsRegistryService) GetOperatorsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNum) (map[types.OperatorId]types.OperatorAvsState, error) {
operatorsAvsState, ok := f.operators[blockNumber]
if !ok {
return nil, errors.New("block number not found")
}
return operatorsAvsState, nil
}

func (f *FakeAvsRegistryService) GetQuorumsAvsStateAtBlock(ctx context.Context, quorumNumbers []types.QuorumNum, blockNumber types.BlockNum) (map[types.QuorumNum]types.QuorumAvsState, error) {
operatorsAvsState, ok := f.operators[blockNumber]
if !ok {
return nil, errors.New("block number not found")
}
quorumsAvsState := make(map[types.QuorumNum]types.QuorumAvsState)
for _, quorumNum := range quorumNumbers {
aggPubkeyG1 := bls.NewG1Point(big.NewInt(0), big.NewInt(0))
totalStake := big.NewInt(0)
for _, operator := range operatorsAvsState {
// only include operators that have a stake in this quorum
if stake, ok := operator.StakePerQuorum[quorumNum]; ok {
aggPubkeyG1.Add(operator.Pubkeys.G1Pubkey)
totalStake.Add(totalStake, stake)
}
}
quorumsAvsState[quorumNum] = types.QuorumAvsState{
QuorumNumber: quorumNum,
AggPubkeyG1: aggPubkeyG1,
TotalStake: totalStake,
BlockNumber: blockNumber,
}
}
return quorumsAvsState, nil
}

func (f *FakeAvsRegistryService) GetCheckSignaturesIndices(ctx context.Context, referenceBlockNumber types.BlockNum, quorumNumbers []types.QuorumNum, nonSignerOperatorIds []types.OperatorId) (blsoperatorstateretrievar.BLSOperatorStateRetrieverCheckSignaturesIndices, error) {
return blsoperatorstateretrievar.BLSOperatorStateRetrieverCheckSignaturesIndices{}, nil
}
Loading

0 comments on commit 52fff37

Please sign in to comment.