From 1bb1ac07601074999a0a0539e077334da745d75e Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Wed, 20 Nov 2019 22:37:39 +0200 Subject: [PATCH] calculate uptime using the stored values --- consensus/istanbul/backend/engine.go | 5 +++ consensus/istanbul/backend/pos.go | 46 ++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/consensus/istanbul/backend/engine.go b/consensus/istanbul/backend/engine.go index 96b73015c5..e41f990c47 100644 --- a/consensus/istanbul/backend/engine.go +++ b/consensus/istanbul/backend/engine.go @@ -458,6 +458,11 @@ func (sb *Backend) EpochSize() uint64 { return sb.config.Epoch } +// Returns the size of the lookback window for calculating uptime (in blocks) +func (sb *Backend) LookbackWindow() uint64 { + return sb.config.LookbackWindow +} + // Finalize runs any post-transaction state modifications (e.g. block rewards) // and assembles the final block. // diff --git a/consensus/istanbul/backend/pos.go b/consensus/istanbul/backend/pos.go index d1c0bbc6d1..164f8f0c5f 100644 --- a/consensus/istanbul/backend/pos.go +++ b/consensus/istanbul/backend/pos.go @@ -17,6 +17,8 @@ package backend import ( + "errors" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -29,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/contract_comm/gold_token" "github.com/ethereum/go-ethereum/contract_comm/validators" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" @@ -78,12 +81,16 @@ func (sb *Backend) distributeEpochPaymentsAndRewards(header *types.Header, state } func (sb *Backend) updateValidatorScores(header *types.Header, state *state.StateDB, valSet []istanbul.Validator) error { - for _, val := range valSet { - // TODO: Use actual uptime metric. - // 1.0 in fixidity - uptime := math.BigPow(10, 24) - sb.logger.Info("Updating validator score for address", "address", val.Address(), "uptime", uptime.String()) - err := validators.UpdateValidatorScore(header, state, val.Address(), uptime) + // we need to use the previous + epoch := istanbul.GetEpochNumber(header.Number.Uint64(), sb.EpochSize()) + log.Debug("uptime-trace: updateValidatorScores", "blocknum", header.Number.Uint64(), "epoch", epoch) + for i, val := range valSet { + uptime, err := sb.getUptime(i, epoch-1) + if err != nil { + return err + } + sb.logger.Info("Updating validator score for address", "index", i, "address", val.Address(), "uptime", uptime) + err = validators.UpdateValidatorScore(header, state, val.Address(), uptime) if err != nil { return err } @@ -91,6 +98,33 @@ func (sb *Backend) updateValidatorScores(header *types.Header, state *state.Stat return nil } +func (sb *Backend) getUptime(validatorIndex int, epoch uint64) (*big.Int, error) { + // try to get a handle on the core.blockchain's database + // sb.db is a different database (defined in CreateConsensusEngine) :/ + // is there a better way than this? don't think we want to pollute the interface + c := sb.chain.(*core.BlockChain) + db := c.GetDatabase() + uptimes := rawdb.ReadAccumulatedEpochUptime(db, epoch) + if uptimes == nil { + panic(fmt.Sprintf("could not read uptimes, i: %v", validatorIndex)) + return nil, errors.New("Invalid accumulated uptime") + } + + // skip the math if we've counted more signatures than necessary for that epoch + // when does this happen? + if uptimes[validatorIndex].Score >= sb.EpochSize()-2+1 { // sb.LookbackWindow()+1 { + // 1.0 in fixidity + return math.BigPow(10, 24), nil + } + + // this will end up being between 0 and 1 but in fixidty + numerator := big.NewInt(0).Mul(big.NewInt(int64(uptimes[validatorIndex].Score)), math.BigPow(10, 24)) + denominator := big.NewInt(int64(sb.EpochSize() - 2 + 1)) //- sb.LookbackWindow() + 1)) + validatorUptime := big.NewInt(0).Div(numerator, denominator) + + return validatorUptime, nil +} + func (sb *Backend) distributeEpochPayments(header *types.Header, state *state.StateDB, valSet []istanbul.Validator, maxPayment *big.Int) (*big.Int, error) { totalEpochPayments := big.NewInt(0) for _, val := range valSet {