From 5b7d2165d8098bcbab0e791563cd7359a6f8b569 Mon Sep 17 00:00:00 2001 From: Ganesha Upadhyaya Date: Thu, 2 Apr 2020 20:03:10 -0700 Subject: [PATCH] fix earned-reward per key by temporary persisting stats and writing at once (#2693) sorted slice of map for deterministic write --- core/offchain.go | 69 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/core/offchain.go b/core/offchain.go index bc7535127..f7a5f08a8 100644 --- a/core/offchain.go +++ b/core/offchain.go @@ -1,7 +1,9 @@ package core import ( + "bytes" "math/big" + "sort" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" @@ -12,6 +14,7 @@ import ( "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/staking/slash" + staking "github.com/harmony-one/harmony/staking/types" "github.com/pkg/errors" ) @@ -214,36 +217,56 @@ func (bc *BlockChain) CommitOffChainData( ); err != nil { return NonStatTy, err } - + tempValidatorStats := map[common.Address]*staking.ValidatorStats{} for _, paid := range [...][]reward.Payout{ roundResult.BeaconchainAward, roundResult.ShardChainAward, } { for i := range paid { - if stats, err := bc.ReadValidatorStats(paid[i].Addr); err == nil { - doUpdate := false - for j := range stats.MetricsPerShard { - if stats.MetricsPerShard[j].Vote.Identity == paid[i].EarningKey { - doUpdate = true - stats.MetricsPerShard[j].Earned.Add( - stats.MetricsPerShard[j].Earned, - paid[i].NewlyEarned, - ) - } + stats, ok := tempValidatorStats[paid[i].Addr] + if !ok { + stats, err = bc.ReadValidatorStats(paid[i].Addr) + if err != nil { + utils.Logger().Info().Err(err). + Str("bls-earning-key", paid[i].EarningKey.Hex()). + Msg("could not read validator stats to update for earning per key") + continue } - if doUpdate { - if err := rawdb.WriteValidatorStats( - batch, paid[i].Addr, stats, - ); err != nil { - utils.Logger().Info().Err(err). - Str("bls-earning-key", paid[i].EarningKey.Hex()). - Msg("could not update earning per key in stats") - } + tempValidatorStats[paid[i].Addr] = stats + } + for j := range stats.MetricsPerShard { + if stats.MetricsPerShard[j].Vote.Identity == paid[i].EarningKey { + stats.MetricsPerShard[j].Earned.Add( + stats.MetricsPerShard[j].Earned, + paid[i].NewlyEarned, + ) } - } else { - utils.Logger().Info().Err(err). - Str("bls-earning-key", paid[i].EarningKey.Hex()). - Msg("could not read validator stats to update for earning per key") } + + } + } + type t struct { + addr common.Address + stats *staking.ValidatorStats + } + sortedStats := []t{} + for key, value := range tempValidatorStats { + sortedStats = append(sortedStats, t{key, value}) + } + sort.SliceStable( + sortedStats, + func(i, j int) bool { + return bytes.Compare( + sortedStats[i].addr[:], sortedStats[j].addr[:], + ) == -1 + }, + ) + for _, stat := range sortedStats { + if err := rawdb.WriteValidatorStats( + batch, stat.addr, stat.stats, + ); err != nil { + utils.Logger().Info().Err(err). + Str("validator address", stat.addr.Hex()). + Msg("could not update stats for validator") } }