Skip to content

Commit

Permalink
refactor: storing medians concurrently (razor-network#1172)
Browse files Browse the repository at this point in the history
* refactor: Calculated medians concurrently

* Revert refactor: Calculated medians concurrently

* refactor: concurrent implementation of MakeBlock

* refactor: corrected benchmarks
  • Loading branch information
Yashk767 authored Dec 19, 2023
1 parent ef41b96 commit 230a971
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 33 deletions.
70 changes: 51 additions & 19 deletions cmd/propose.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,31 +445,42 @@ func (*UtilsStruct) MakeBlock(client *ethclient.Client, blockNumber *big.Int, ep
}
log.Debug("MakeBlock: Active collections: ", activeCollections)

var (
medians []*big.Int
idsRevealedInThisEpoch []uint16
)
resultsChan := make(chan types.MedianResult, len(activeCollections))
var wg sync.WaitGroup

log.Debug("Iterating over all the active collections for medians calculation....")
for leafId := uint16(0); leafId < uint16(len(activeCollections)); leafId++ {
influenceSum := revealedDataMaps.InfluenceSum[leafId]
if influenceSum != nil && influenceSum.Cmp(big.NewInt(0)) != 0 {
idsRevealedInThisEpoch = append(idsRevealedInThisEpoch, activeCollections[leafId])
if rogueData.IsRogue && utils.Contains(rogueData.RogueMode, "medians") {
medians = append(medians, razorUtils.GetRogueRandomValue(10000000))
continue
}
accWeight := big.NewInt(0)
for i := 0; i < len(revealedDataMaps.SortedRevealedValues[leafId]); i++ {
revealedValue := revealedDataMaps.SortedRevealedValues[leafId][i]
accWeight = accWeight.Add(accWeight, revealedDataMaps.VoteWeights[revealedValue.String()])
if accWeight.Cmp(influenceSum.Div(influenceSum, big.NewInt(2))) > 0 {
medians = append(medians, revealedValue)
break
}
wg.Add(1)
go func(leafId uint16) {
defer wg.Done()
median := calculateMedianForLeafId(revealedDataMaps, leafId, rogueData)
if median != nil {
resultsChan <- types.MedianResult{LeafId: leafId, Median: median}
}
}(leafId)
}

wg.Wait()
close(resultsChan)

// Storing the median results temporarily in a map
medianResults := make(map[uint16]*big.Int)
for result := range resultsChan {
medianResults[result.LeafId] = result.Median
}

var medians []*big.Int
var idsRevealedInThisEpoch []uint16

// Storing medians in order of increasing leafIds starting from 0
for leafId := uint16(0); leafId < uint16(len(activeCollections)); leafId++ {
if median, exists := medianResults[leafId]; exists {
medians = append(medians, median)
idsRevealedInThisEpoch = append(idsRevealedInThisEpoch, activeCollections[leafId])
}
}

// Handling rogue data
if rogueData.IsRogue && utils.Contains(rogueData.RogueMode, "missingIds") {
log.Warn("YOU ARE PROPOSING IDS REVEALED IN ROGUE MODE, THIS CAN INCUR PENALTIES!")
//Replacing the last ID: id with id+1 in idsRevealed array if rogueMode == missingIds
Expand All @@ -488,9 +499,30 @@ func (*UtilsStruct) MakeBlock(client *ethclient.Client, blockNumber *big.Int, ep
idsRevealedInThisEpoch[0] = idsRevealedInThisEpoch[1]
idsRevealedInThisEpoch[1] = temp
}

return medians, idsRevealedInThisEpoch, revealedDataMaps, nil
}

func calculateMedianForLeafId(revealedDataMaps *types.RevealedDataMaps, leafId uint16, rogueData types.Rogue) *big.Int {
influenceSum := revealedDataMaps.InfluenceSum[leafId]
if influenceSum != nil && influenceSum.Cmp(big.NewInt(0)) != 0 {
if rogueData.IsRogue && utils.Contains(rogueData.RogueMode, "medians") {
return razorUtils.GetRogueRandomValue(10000000)
}
accWeight := big.NewInt(0)
for _, revealedValue := range revealedDataMaps.SortedRevealedValues[leafId] {
accWeight = accWeight.Add(accWeight, revealedDataMaps.VoteWeights[revealedValue.String()])
if accWeight.Cmp(influenceSum.Div(influenceSum, big.NewInt(2))) > 0 {
log.Debugf("LeafId: %d, Calculated value %v", leafId, revealedValue)
return revealedValue
}
}
}
// Returning nil if no median is found or if influenceSum is nil or zero
log.Debugf("No median found for LeafId %d", leafId)
return nil
}

func (*UtilsStruct) GetSmallestStakeAndId(client *ethclient.Client, epoch uint32) (*big.Int, uint32, error) {
numberOfStakers, err := razorUtils.GetNumberOfStakers(client)
if err != nil {
Expand Down
62 changes: 48 additions & 14 deletions cmd/propose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1365,27 +1365,25 @@ func BenchmarkMakeBlock(b *testing.B) {
)

table := []struct {
numOfVotes int
numOfVotesPerLeafId int
numOfLeafIds int
}{
{numOfVotes: 1},
{numOfVotes: 100},
{numOfVotes: 1000},
{numOfVotes: 10000},
{numOfVotes: 100000},
{numOfVotesPerLeafId: 5, numOfLeafIds: 10},
{numOfVotesPerLeafId: 50, numOfLeafIds: 100},
{numOfVotesPerLeafId: 100, numOfLeafIds: 500},
{numOfVotesPerLeafId: 500, numOfLeafIds: 1000},
{numOfVotesPerLeafId: 1000, numOfLeafIds: 10000},
}
for _, v := range table {
b.Run(fmt.Sprintf("Number_Of_Votes_%d", v.numOfVotes), func(b *testing.B) {
b.Run(fmt.Sprintf("LeafIds_%d_VotesPerLeafId_%d", v.numOfLeafIds, v.numOfVotesPerLeafId), func(b *testing.B) {
for i := 0; i < b.N; i++ {
SetUpMockInterfaces()

votes := GetDummyVotes(v.numOfVotes)
revealedDataMaps := GetDummyRevealedDataMaps(v.numOfLeafIds, v.numOfVotesPerLeafId)

cmdUtilsMock.On("GetSortedRevealedValues", mock.Anything, mock.Anything, mock.Anything).Return(revealedDataMaps, nil)
utilsMock.On("GetActiveCollectionIds", mock.Anything).Return(GetDummyActiveCollections(v.numOfLeafIds), nil)

cmdUtilsMock.On("GetSortedRevealedValues", mock.Anything, mock.Anything, mock.Anything).Return(&types.RevealedDataMaps{
SortedRevealedValues: map[uint16][]*big.Int{0: votes},
VoteWeights: map[string]*big.Int{(big.NewInt(1).Mul(big.NewInt(697718000), big.NewInt(1e18))).String(): big.NewInt(100)},
InfluenceSum: map[uint16]*big.Int{0: big.NewInt(100)},
}, nil)
utilsMock.On("GetActiveCollectionIds", mock.Anything).Return([]uint16{1}, nil)
ut := &UtilsStruct{}
_, _, _, err := ut.MakeBlock(client, blockNumber, epoch, types.Rogue{IsRogue: false})
if err != nil {
Expand All @@ -1404,6 +1402,42 @@ func GetDummyVotes(numOfVotes int) []*big.Int {
return result
}

func GetDummyActiveCollections(numOfCollections int) []uint16 {
var collections []uint16
for i := 0; i < numOfCollections; i++ {
collections = append(collections, uint16(i+1))
}
return collections
}

func GetDummyRevealedDataMaps(numOfLeafIds, numOfVotesPerLeafId int) *types.RevealedDataMaps {
sortedRevealedValues := make(map[uint16][]*big.Int)
voteWeights := make(map[string]*big.Int)
influenceSum := make(map[uint16]*big.Int)

for leafId := 0; leafId < numOfLeafIds; leafId++ {
var votes []*big.Int
totalInfluence := big.NewInt(0)

for voteId := 0; voteId < numOfVotesPerLeafId; voteId++ {
voteValue := big.NewInt(1).Mul(big.NewInt(int64(leafId+voteId+1)), big.NewInt(1e18)) // Example vote value
votes = append(votes, voteValue)
weight := big.NewInt(100) // Example weight
voteWeights[voteValue.String()] = weight
totalInfluence.Add(totalInfluence, weight)
}

sortedRevealedValues[uint16(leafId)] = votes
influenceSum[uint16(leafId)] = totalInfluence
}

return &types.RevealedDataMaps{
SortedRevealedValues: sortedRevealedValues,
VoteWeights: voteWeights,
InfluenceSum: influenceSum,
}
}

func GetDummyAssignedAssets(asset types.RevealedStruct, numOfAssignedAssets int) []types.RevealedStruct {
var assignedAssets []types.RevealedStruct
for i := 1; i <= numOfAssignedAssets; i++ {
Expand Down
5 changes: 5 additions & 0 deletions core/types/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ type AssignedAsset struct {
Value *big.Int `json:"value"`
}

type MedianResult struct {
LeafId uint16
Median *big.Int
}

type CustomJob struct {
URL string `json:"URL"`
Name string `json:"name"`
Expand Down

0 comments on commit 230a971

Please sign in to comment.