diff --git a/cmd/dispute.go b/cmd/dispute.go index 539d9e80..ae662c91 100644 --- a/cmd/dispute.go +++ b/cmd/dispute.go @@ -110,7 +110,6 @@ func (*UtilsStruct) HandleDispute(client *ethclient.Client, config types.Configu err = cmdUtils.StoreBountyId(client, account) if err != nil { log.Error(err) - break } continue } @@ -124,6 +123,7 @@ func (*UtilsStruct) HandleDispute(client *ethclient.Client, config types.Configu idDisputeTxn, err := cmdUtils.CheckDisputeForIds(client, transactionOptions, epoch, uint8(blockIndex), proposedBlock.Ids, revealedCollectionIds) if err != nil { log.Error("Error in disputing: ", err) + continue } if idDisputeTxn != nil { idDisputeTxnHash := transactionUtils.Hash(idDisputeTxn) @@ -136,7 +136,6 @@ func (*UtilsStruct) HandleDispute(client *ethclient.Client, config types.Configu err = cmdUtils.StoreBountyId(client, account) if err != nil { log.Error(err) - break } continue } @@ -153,6 +152,11 @@ func (*UtilsStruct) HandleDispute(client *ethclient.Client, config types.Configu // ids [1, 2, 3, 4] // Sorted revealed values would be the vote values for the wrong median, here 230 log.Debug("HandleDispute: Mismatch index while iterating: ", mismatchIndex) + if mismatchIndex < 0 || mismatchIndex >= len(proposedBlock.Ids) { + log.Error("Mismatch index is out of bounds, cannot continue dispute for medians") + continue + } + collectionIdOfWrongMedian := proposedBlock.Ids[mismatchIndex] log.Debug("HandleDispute: Collection Id of wrong median: ", collectionIdOfWrongMedian) @@ -190,65 +194,63 @@ func (*UtilsStruct) HandleDispute(client *ethclient.Client, config types.Configu //This function returns the local median data func (*UtilsStruct) GetLocalMediansData(client *ethclient.Client, account types.Account, epoch uint32, blockNumber *big.Int, rogueData types.Rogue) (types.ProposeFileData, error) { - if (globalProposedDataStruct.MediansData == nil && !rogueData.IsRogue) || epoch != globalProposedDataStruct.Epoch { + if rogueData.IsRogue { + // As the staker has proposed with incorrect medians in rogue mode so those values needs to be compared with the correct calculated medians + log.Debug("Staker proposed in rogue mode, now calculating medians correctly...") + return calculateMedian(client, account, epoch, blockNumber) + } + + // Fetching the data from file only if the node is not in rogue mode and + // the proposed data in memory is nil or epoch in propose data from memory doesn't match with current epoch + nilProposedData := globalProposedDataStruct.MediansData == nil || globalProposedDataStruct.RevealedDataMaps == nil || globalProposedDataStruct.RevealedCollectionIds == nil + if nilProposedData || epoch != globalProposedDataStruct.Epoch { log.Debug("Global propose data struct is not updated, getting the proposed data from file...") fileName, err := pathUtils.GetProposeDataFileName(account.Address) if err != nil { log.Error("Error in getting file name to read median data: ", err) - goto CalculateMedian + return calculateMedian(client, account, epoch, blockNumber) } log.Debug("GetLocalMediansData: Propose data file path: ", fileName) proposedData, err := fileUtils.ReadFromProposeJsonFile(fileName) if err != nil { log.Errorf("Error in getting propose data from file %s: %v", fileName, err) - goto CalculateMedian + return calculateMedian(client, account, epoch, blockNumber) } log.Debugf("GetLocalMediansData: Proposed data from file: %+v", proposedData) if proposedData.Epoch != epoch { log.Errorf("File %s doesn't contain latest median data", fileName) - goto CalculateMedian + return calculateMedian(client, account, epoch, blockNumber) } - log.Debug("Updating global proposed data struct...") - updateGlobalProposedDataStruct(proposedData) - log.Debugf("GetLocalMediansData: Global proposed data struct: %+v", globalProposedDataStruct) + return proposedData, err } -CalculateMedian: + + return globalProposedDataStruct, nil +} + +func calculateMedian(client *ethclient.Client, account types.Account, epoch uint32, blockNumber *big.Int) (types.ProposeFileData, error) { stakerId, err := razorUtils.GetStakerId(client, account.Address) if err != nil { log.Error("Error in getting stakerId: ", err) return types.ProposeFileData{}, err } log.Debug("GetLocalMediansData: Staker Id: ", stakerId) - lastProposedEpoch, err := razorUtils.GetEpochLastProposed(client, stakerId) + + log.Debug("Calculating the medians data again...") + log.Debugf("GetLocalMediansData: Calling MakeBlock() with arguments blockNumber = %s, epoch = %d, rogueData = %+v", blockNumber, epoch, types.Rogue{IsRogue: false}) + medians, revealedCollectionIds, revealedDataMaps, err := cmdUtils.MakeBlock(client, blockNumber, epoch, types.Rogue{IsRogue: false}) if err != nil { - log.Error("Error in getting last proposed epoch: ", err) + log.Error("Error in calculating block medians: ", err) return types.ProposeFileData{}, err } - log.Debug("GetLocalMediansData: Last proposed epoch: ", lastProposedEpoch) - - nilProposedData := globalProposedDataStruct.MediansData == nil || globalProposedDataStruct.RevealedDataMaps == nil || globalProposedDataStruct.RevealedCollectionIds == nil - epochCheck := epoch != lastProposedEpoch - - if nilProposedData || rogueData.IsRogue || epochCheck { - log.Debug("Calculating the medians data again...") - log.Debugf("GetLocalMediansData: Calling MakeBlock() with arguments blockNumber = %s, epoch = %d, rogueData = %+v", blockNumber, epoch, types.Rogue{IsRogue: false}) - medians, revealedCollectionIds, revealedDataMaps, err := cmdUtils.MakeBlock(client, blockNumber, epoch, types.Rogue{IsRogue: false}) - if err != nil { - log.Error("Error in calculating block medians") - return types.ProposeFileData{}, err - } - log.Debug("Updating global proposed data struct...") - updateGlobalProposedDataStruct(types.ProposeFileData{ - MediansData: medians, - RevealedCollectionIds: revealedCollectionIds, - RevealedDataMaps: revealedDataMaps, - Epoch: epoch, - }) - log.Debugf("GetLocalMediansData: Global proposed data struct: %+v", globalProposedDataStruct) + calculatedProposedData := types.ProposeFileData{ + MediansData: medians, + RevealedCollectionIds: revealedCollectionIds, + RevealedDataMaps: revealedDataMaps, + Epoch: epoch, } - log.Debugf("Locally calculated data, Medians: %s", globalProposedDataStruct.MediansData) - return globalProposedDataStruct, nil + log.Debugf("Locally calculated data, Medians: %s", calculatedProposedData.MediansData) + return calculatedProposedData, nil } //This function check for the dispute in different type of Id's diff --git a/cmd/dispute_test.go b/cmd/dispute_test.go index 96573a2a..6723f7e3 100644 --- a/cmd/dispute_test.go +++ b/cmd/dispute_test.go @@ -494,6 +494,30 @@ func TestHandleDispute(t *testing.T) { }, want: nil, }, + { + name: "Test 19: When the mismatch id index is out of range", + args: args{ + sortedProposedBlockIds: []uint32{45, 65, 23, 64, 12}, + biggestStake: big.NewInt(1).Mul(big.NewInt(5356), big.NewInt(1e18)), + biggestStakeId: 2, + medians: []*big.Int{big.NewInt(6901548), big.NewInt(498307)}, + revealedCollectionIds: []uint16{1}, + revealedDataMaps: &types.RevealedDataMaps{ + SortedRevealedValues: nil, + VoteWeights: nil, + InfluenceSum: nil, + }, + proposedBlock: bindings.StructsBlock{ + Medians: []*big.Int{big.NewInt(6901548)}, + Ids: []uint16{1}, + Valid: true, + BiggestStake: big.NewInt(1).Mul(big.NewInt(5356), big.NewInt(1e18)), + }, + idDisputeTxn: nil, + disputeErr: nil, + }, + want: nil, + }, } for _, tt := range tests { @@ -656,7 +680,6 @@ func TestGetLocalMediansData(t *testing.T) { client *ethclient.Client account types.Account blockNumber *big.Int - rogueData types.Rogue ) type args struct { epoch uint32 @@ -670,8 +693,7 @@ func TestGetLocalMediansData(t *testing.T) { mediansErr error stakerId uint32 stakerIdErr error - lastProposedEpoch uint32 - lastProposedEpochErr error + isRogue bool } tests := []struct { name string @@ -717,7 +739,8 @@ func TestGetLocalMediansData(t *testing.T) { { name: "Test 4: When there is an error in getting medians", args: args{ - mediansErr: errors.New("error in fetching medians"), + fileNameErr: errors.New("error in getting fileName"), + mediansErr: errors.New("error in fetching medians"), }, want: nil, want1: nil, @@ -725,8 +748,9 @@ func TestGetLocalMediansData(t *testing.T) { wantErr: true, }, { - name: "Test 5: When GetLocalMediansData executes successfully", + name: "Test 5: When GetLocalMediansData executes successfully when there is an error in getting file name", args: args{ + fileNameErr: errors.New("error in getting fileName"), medians: []*big.Int{big.NewInt(100), big.NewInt(200), big.NewInt(300)}, revealedCollectionIds: []uint16{1, 2, 3}, revealedDataMaps: &types.RevealedDataMaps{}, @@ -739,6 +763,7 @@ func TestGetLocalMediansData(t *testing.T) { { name: "Test 6: When there is an error in getting stakerId", args: args{ + fileNameErr: errors.New("error in getting fileName"), medians: []*big.Int{big.NewInt(100), big.NewInt(200), big.NewInt(300)}, revealedCollectionIds: []uint16{1, 2, 3}, revealedDataMaps: &types.RevealedDataMaps{}, @@ -750,19 +775,17 @@ func TestGetLocalMediansData(t *testing.T) { wantErr: true, }, { - name: "Test 7: When there is an error in getting last proposed epoch", + name: "Test 7: When staker votes in rogue mode and needs to calculate median again", args: args{ + isRogue: true, medians: []*big.Int{big.NewInt(100), big.NewInt(200), big.NewInt(300)}, revealedCollectionIds: []uint16{1, 2, 3}, revealedDataMaps: &types.RevealedDataMaps{}, - stakerId: 2, - epoch: 5, - lastProposedEpochErr: errors.New("lastProposedEpoch error"), }, - want: nil, - want1: nil, - want2: nil, - wantErr: true, + want: []*big.Int{big.NewInt(100), big.NewInt(200), big.NewInt(300)}, + want1: []uint16{1, 2, 3}, + want2: &types.RevealedDataMaps{}, + wantErr: false, }, } for _, tt := range tests { @@ -773,9 +796,8 @@ func TestGetLocalMediansData(t *testing.T) { fileUtilsMock.On("ReadFromProposeJsonFile", mock.Anything).Return(tt.args.proposedData, tt.args.proposeDataErr) cmdUtilsMock.On("MakeBlock", mock.AnythingOfType("*ethclient.Client"), mock.Anything, mock.Anything, mock.Anything).Return(tt.args.medians, tt.args.revealedCollectionIds, tt.args.revealedDataMaps, tt.args.mediansErr) utilsMock.On("GetStakerId", mock.AnythingOfType("*ethclient.Client"), mock.AnythingOfType("string")).Return(tt.args.stakerId, tt.args.stakerIdErr) - utilsMock.On("GetEpochLastProposed", mock.AnythingOfType("*ethclient.Client"), mock.AnythingOfType("uint32")).Return(tt.args.lastProposedEpoch, tt.args.lastProposedEpochErr) ut := &UtilsStruct{} - localProposedData, err := ut.GetLocalMediansData(client, account, tt.args.epoch, blockNumber, rogueData) + localProposedData, err := ut.GetLocalMediansData(client, account, tt.args.epoch, blockNumber, types.Rogue{IsRogue: tt.args.isRogue}) if (err != nil) != tt.wantErr { t.Errorf("GetLocalMediansData() error = %v, wantErr %v", err, tt.wantErr) return