Skip to content

Commit

Permalink
aggregation test
Browse files Browse the repository at this point in the history
  • Loading branch information
ian-shim committed Mar 7, 2024
1 parent af73b4e commit 052e86f
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 155 deletions.
12 changes: 10 additions & 2 deletions clients/tests/retrieval_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,20 @@ var (
func setup(t *testing.T) {

var err error
chainState, err = coremock.MakeChainDataMock(core.OperatorIndex(numOperators))
chainState, err = coremock.MakeChainDataMock(map[uint8]int{
0: numOperators,
1: numOperators,
2: numOperators,
})
if err != nil {
t.Fatalf("failed to create new mocked chain data: %s", err)
}

indexedChainState, err = coremock.MakeChainDataMock(core.OperatorIndex(numOperators))
indexedChainState, err = coremock.MakeChainDataMock(map[uint8]int{
0: numOperators,
1: numOperators,
2: numOperators,
})
if err != nil {
t.Fatalf("failed to create new mocked indexed chain data: %s", err)
}
Expand Down
20 changes: 9 additions & 11 deletions core/aggregation.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,13 @@ func (a *StdSignatureAggregator) AggregateSignatures(ctx context.Context, state

a.Logger.Info("[AggregateSignatures] received signature from operator", "operatorID", operatorIDHex, "operatorAddress", operatorAddr, "socket", socket)

for ind, id := range quorumIDs {

for ind, quorumID := range quorumIDs {
// Get stake amounts for operator
ops := state.Operators[id]
ops := state.Operators[quorumID]
opInfo, ok := ops[r.Operator]

// If operator is not in quorum, skip
if !ok {
a.Logger.Error("Operator not found in quorum", "operatorID", operatorIDHex, "operatorAddress", operatorAddr, "socket", socket)
a.Logger.Error("Operator not found in quorum", "operatorID", operatorIDHex, "operatorAddress", operatorAddr, "socket", socket, "quorumID", quorumID)
continue
}

Expand Down Expand Up @@ -186,21 +184,21 @@ func (a *StdSignatureAggregator) AggregateSignatures(ctx context.Context, state
// Validate the amount signed and aggregate signatures for each quorum
quorumResults := make(map[QuorumID]*QuorumResult)

for ind, id := range quorumIDs {
for ind, quorumID := range quorumIDs {
// Check that quorum has sufficient stake
percent := GetSignedPercentage(state.OperatorState, id, stakeSigned[ind])
quorumResults[id] = &QuorumResult{
QuorumID: id,
percent := GetSignedPercentage(state.OperatorState, quorumID, stakeSigned[ind])
quorumResults[quorumID] = &QuorumResult{
QuorumID: quorumID,
PercentSigned: percent,
}

// Verify that the aggregated public key for the quorum matches the on-chain quorum aggregate public key sans non-signers of the quorum
quorumAggKey := state.AggKeys[id]
quorumAggKey := state.AggKeys[quorumID]
quorumAggPubKeys[ind] = quorumAggKey

signersAggKey := quorumAggKey.Deserialize(quorumAggKey.Serialize())
for opInd, nsk := range nonSignerKeys {
ops := state.Operators[id]
ops := state.Operators[quorumID]
if _, ok := ops[nonSignerOperatorIds[opInd]]; ok {
signersAggKey.Sub(nsk)
}
Expand Down
58 changes: 46 additions & 12 deletions core/aggregation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ var (

func TestMain(m *testing.M) {
var err error
dat, err = mock.MakeChainDataMock(10)
dat, err = mock.MakeChainDataMock(map[uint8]int{
0: 6,
1: 3,
})
if err != nil {
panic(err)
}
Expand All @@ -47,7 +50,7 @@ func simulateOperators(state mock.PrivateOperatorState, message [32]byte, update
// In real life, the ordering will be random, but we simulate the signing in a fixed order
// to simulate stakes deterministically
for i := 0; i < len(state.PrivateOperators); i++ {
id := makeOperatorId(i)
id := mock.MakeOperatorId(i)
op := state.PrivateOperators[id]
sig := op.KeyPair.SignMessage(message)
if count < len(state.IndexedOperators)-int(advCount) {
Expand Down Expand Up @@ -75,7 +78,7 @@ func TestAggregateSignaturesStatus(t *testing.T) {
quorums []core.QuorumResult
adversaryCount uint
expectedErr error
meetsQuorum bool
meetsQuorum []bool
}{
{
name: "Succeeds when all operators sign at quorum threshold 100",
Expand All @@ -87,19 +90,19 @@ func TestAggregateSignaturesStatus(t *testing.T) {
},
adversaryCount: 0,
expectedErr: nil,
meetsQuorum: true,
meetsQuorum: []bool{true},
},
{
name: "Succeeds when 9/10 operators sign at quorum threshold 80",
name: "Succeeds when 9/10 operators sign at quorum threshold 70",
quorums: []core.QuorumResult{
{
QuorumID: 0,
PercentSigned: 80,
PercentSigned: 70,
},
},
adversaryCount: 1,
expectedErr: nil,
meetsQuorum: true,
meetsQuorum: []bool{true},
},
{
name: "Fails when 8/10 operators sign at quorum threshold 90",
Expand All @@ -111,14 +114,45 @@ func TestAggregateSignaturesStatus(t *testing.T) {
},
adversaryCount: 2,
expectedErr: nil,
meetsQuorum: false,
meetsQuorum: []bool{false},
},
{
name: "Fails when 9/10 operators sign at quorum threshold 80 for 2 quorums",
quorums: []core.QuorumResult{
{
QuorumID: 0,
PercentSigned: 80,
},
{
QuorumID: 1,
PercentSigned: 80,
},
},
adversaryCount: 1,
expectedErr: nil,
meetsQuorum: []bool{false, true},
},
{
name: "Succeeds when 9/10 operators sign at quorum threshold 70 and 100",
quorums: []core.QuorumResult{
{
QuorumID: 0,
PercentSigned: 70,
},
{
QuorumID: 1,
PercentSigned: 100,
},
},
adversaryCount: 1,
expectedErr: nil,
meetsQuorum: []bool{true, true},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

state := dat.GetTotalOperatorState(context.Background(), 0)
state := dat.GetTotalOperatorStateWithQuorums(context.Background(), 0, []core.QuorumID{0, 1})

update := make(chan core.SignerMessage)
message := [32]byte{1, 2, 3, 4, 5, 6}
Expand All @@ -133,8 +167,8 @@ func TestAggregateSignaturesStatus(t *testing.T) {
sigAgg, err := agg.AggregateSignatures(context.Background(), state.IndexedOperatorState, quorumIDs, message, update)
assert.NoError(t, err)

for _, quorum := range tt.quorums {
if tt.meetsQuorum {
for i, quorum := range tt.quorums {
if tt.meetsQuorum[i] {
assert.GreaterOrEqual(t, sigAgg.QuorumResults[quorum.QuorumID].PercentSigned, quorum.PercentSigned)
} else {
assert.Less(t, sigAgg.QuorumResults[quorum.QuorumID].PercentSigned, quorum.PercentSigned)
Expand Down
6 changes: 6 additions & 0 deletions core/assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ func (c *StdAssignmentCoordinator) GetAssignments(state *OperatorState, blobLeng
num := new(big.Int).Mul(big.NewInt(int64(blobLength*percentMultiplier)), r.Stake)

gammaChunkLength := big.NewInt(int64(info.ChunkLength) * int64((info.QuorumThreshold - info.AdversaryThreshold)))
if gammaChunkLength.Cmp(big.NewInt(0)) == 0 {
return nil, AssignmentInfo{}, fmt.Errorf("gammaChunkLength must be greater than 0")
}
if totalStakes.Cmp(big.NewInt(0)) == 0 {
return nil, AssignmentInfo{}, fmt.Errorf("total stake in quorum %d must be greater than 0", quorum)
}
denom := new(big.Int).Mul(gammaChunkLength, totalStakes)
m := roundUpDivideBig(num, denom)

Expand Down
56 changes: 26 additions & 30 deletions core/assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ import (
"github.com/stretchr/testify/assert"
)

func makeOperatorId(id int) core.OperatorID {
data := [32]byte{}
copy(data[:], []byte(fmt.Sprintf("%d", id)))
return data
}

func TestOperatorAssignments(t *testing.T) {

state := dat.GetTotalOperatorState(context.Background(), 0)
Expand All @@ -38,49 +32,49 @@ func TestOperatorAssignments(t *testing.T) {
assignments, info, err := coordinator.GetAssignments(operatorState, blobLength, quorumInfo)
assert.NoError(t, err)
expectedAssignments := map[core.OperatorID]core.Assignment{
makeOperatorId(0): {
mock.MakeOperatorId(0): {
StartIndex: 0,
NumChunks: 1,
},
makeOperatorId(1): {
mock.MakeOperatorId(1): {
StartIndex: 1,
NumChunks: 1,
},
makeOperatorId(2): {
StartIndex: 2,
NumChunks: 2,
},
makeOperatorId(3): {
StartIndex: 4,
NumChunks: 2,
mock.MakeOperatorId(2): {
StartIndex: 3,
NumChunks: 3,
},
makeOperatorId(4): {
mock.MakeOperatorId(3): {
StartIndex: 6,
NumChunks: 2,
NumChunks: 4,
},
makeOperatorId(5): {
StartIndex: 8,
NumChunks: 3,
mock.MakeOperatorId(4): {
StartIndex: 10,
NumChunks: 5,
},
makeOperatorId(6): {
StartIndex: 11,
mock.MakeOperatorId(5): {
StartIndex: 15,
NumChunks: 6,
},
mock.MakeOperatorId(6): {
StartIndex: 21,
NumChunks: 3,
},
makeOperatorId(7): {
mock.MakeOperatorId(7): {
StartIndex: 14,
NumChunks: 3,
},
makeOperatorId(8): {
mock.MakeOperatorId(8): {
StartIndex: 17,
NumChunks: 4,
},
makeOperatorId(9): {
mock.MakeOperatorId(9): {
StartIndex: 21,
NumChunks: 4,
},
}
expectedInfo := core.AssignmentInfo{
TotalChunks: 25,
TotalChunks: 21,
}

assert.Equal(t, expectedInfo, info)
Expand Down Expand Up @@ -119,16 +113,18 @@ func FuzzOperatorAssignments(f *testing.F) {
}

for i := 0; i < 100; i++ {
f.Add(rand.Intn(1000)+1, rand.Intn(2) == 0)
f.Add(rand.Intn(254)+1, rand.Intn(2) == 0)
}

f.Fuzz(func(t *testing.T, numOperators int, useTargetNumChunks bool) {

// Generate a random slice of integers of length n

stakes := make([]int, numOperators)
for i := range stakes {
stakes[i] = rand.Intn(100)
stakes := map[core.QuorumID]map[core.OperatorID]int{
0: {},
}
for i := 0; i < numOperators; i++ {
stakes[0][mock.MakeOperatorId(i)] = rand.Intn(100) + 1
}

advThreshold := rand.Intn(99)
Expand Down
Loading

0 comments on commit 052e86f

Please sign in to comment.