Skip to content

Commit

Permalink
Merge branch 'feat/release-2022-April' into feat-april-with-indexer-v…
Browse files Browse the repository at this point in the history
…1-2-x

# Conflicts:
#	go.mod
#	go.sum
  • Loading branch information
iulianpascalau committed Apr 20, 2022
2 parents 5346bac + 49f8528 commit beb0e4f
Show file tree
Hide file tree
Showing 59 changed files with 1,357 additions and 890 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ on:
branches:
- master
pull_request:
branches: [ master, development ]
branches: [ master, development, feat/*, rc/* ]

workflow_dispatch:

jobs:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ on:
branches:
- master
pull_request:
branches: [ master, development ]
branches: [ master, development, feat/*, rc/* ]

jobs:
golangci:
name: golangci linter
Expand Down
66 changes: 18 additions & 48 deletions cmd/termui/presenter/instanceInfoGetters.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package presenter

import (
"math/big"
"strconv"
"strings"

"github.com/ElrondNetwork/elrond-go/common"
)

const precisionRewards = 2

// GetAppVersion will return application version
func (psh *PresenterStatusHandler) GetAppVersion() string {
return psh.getFromCacheAsString(common.MetricAppVersion)
Expand All @@ -34,6 +32,23 @@ func (psh *PresenterStatusHandler) GetPublicKeyBlockSign() string {
return psh.getFromCacheAsString(common.MetricPublicKeyBlockSign)
}

// GetRedundancyLevel will return the redundancy level of the node
func (psh *PresenterStatusHandler) GetRedundancyLevel() int64 {
// redundancy level is sent as string as JSON unmarshal doesn't treat well the casting from interface{} to int64
redundancyLevelStr := psh.getFromCacheAsString(common.MetricRedundancyLevel)
i64Val, err := strconv.ParseInt(redundancyLevelStr, 10, 64)
if err != nil {
return 0
}

return i64Val
}

// GetRedundancyIsMainActive will return the info about redundancy main machine
func (psh *PresenterStatusHandler) GetRedundancyIsMainActive() string {
return psh.getFromCacheAsString(common.MetricRedundancyIsMainActive)
}

// GetShardId will return shard Id of node
func (psh *PresenterStatusHandler) GetShardId() uint64 {
return psh.getFromCacheAsUint64(common.MetricShardId)
Expand Down Expand Up @@ -81,48 +96,3 @@ func (psh *PresenterStatusHandler) GetNodeName() string {

return nodeName
}

// GetTotalRewardsValue will return total value of rewards and how the rewards were increased on every second
// Rewards estimation will be equal with :
// numSignedBlocks * denomination * Rewards
func (psh *PresenterStatusHandler) GetTotalRewardsValue() (string, string) {
numSignedBlocks := psh.getFromCacheAsUint64(common.MetricCountConsensusAcceptedBlocks)
rewardsInErd := psh.computeRewardsInErd()

totalRewardsFloat := big.NewFloat(float64(numSignedBlocks))
totalRewardsFloat.Mul(totalRewardsFloat, rewardsInErd)
difRewards := big.NewFloat(0).Sub(totalRewardsFloat, psh.totalRewardsOld)

defer func() {
psh.totalRewardsOld = totalRewardsFloat
}()

return psh.totalRewardsOld.Text('f', precisionRewards), difRewards.Text('f', precisionRewards)
}

// CalculateRewardsPerHour will return an approximation of how many ERDs a validator will earn per hour
// Rewards estimation per hour will be equals with :
// chanceToBeInConsensus * roundsPerHour * hitRate * denominationCoefficient * Rewards
func (psh *PresenterStatusHandler) CalculateRewardsPerHour() string {
chanceToBeInConsensus := psh.computeChanceToBeInConsensus()
roundsPerHourAccordingToHitRate := psh.computeRoundsPerHourAccordingToHitRate()
rewardsInErd := psh.computeRewardsInErd()
if chanceToBeInConsensus == 0 || roundsPerHourAccordingToHitRate == 0 || rewardsInErd.Cmp(big.NewFloat(0)) <= 0 {
return "0"
}

rewardsPerHourCoefficient := chanceToBeInConsensus * roundsPerHourAccordingToHitRate
totalRewardsPerHourFloat := big.NewFloat(rewardsPerHourCoefficient)
totalRewardsPerHourFloat.Mul(totalRewardsPerHourFloat, rewardsInErd)
return totalRewardsPerHourFloat.Text('f', precisionRewards)
}

// GetZeros will return a string with a specific number of zeros
func (psh *PresenterStatusHandler) GetZeros() string {
retValue := "." + strings.Repeat("0", precisionRewards)
if retValue == "." {
return ""
}

return retValue
}
76 changes: 11 additions & 65 deletions cmd/termui/presenter/instanceInfoGetters_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package presenter

import (
"math/big"
"testing"

"github.com/ElrondNetwork/elrond-go/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestPresenterStatusHandler_GetAppVersion(t *testing.T) {
Expand Down Expand Up @@ -150,72 +150,18 @@ func TestPresenterStatusHandler_GetNodeName(t *testing.T) {
assert.Equal(t, nodeName, result)
}

func TestPresenterStatusHandler_CalculateRewardsTotal(t *testing.T) {
func TestPresenterStatusHandler_GetRedundancyLevel(t *testing.T) {
t.Parallel()

rewardsValue := "1000"

numSignedBlocks := uint64(50)

presenterStatusHandler := NewPresenterStatusHandler()
presenterStatusHandler.SetStringValue(common.MetricRewardsValue, rewardsValue)
presenterStatusHandler.SetUInt64Value(common.MetricCountConsensusAcceptedBlocks, numSignedBlocks)
presenterStatusHandler.SetUInt64Value(common.MetricDenomination, 4)
totalRewards, diff := presenterStatusHandler.GetTotalRewardsValue()
expectedDifValue := "5" + presenterStatusHandler.GetZeros()

assert.Equal(t, "0"+presenterStatusHandler.GetZeros(), totalRewards)
assert.Equal(t, expectedDifValue, diff)
}

func TestPresenterStatusHandler_CalculateRewardsTotalRewards(t *testing.T) {
t.Parallel()

rewardsValue := "1000"
numSignedBlocks := uint64(50000)

presenterStatusHandler := NewPresenterStatusHandler()
totalRewardsOld, _ := big.NewFloat(0).SetString(rewardsValue)
presenterStatusHandler.totalRewardsOld = big.NewFloat(0).Set(totalRewardsOld)
presenterStatusHandler.SetStringValue(common.MetricRewardsValue, rewardsValue)
presenterStatusHandler.SetUInt64Value(common.MetricCountConsensusAcceptedBlocks, numSignedBlocks)
presenterStatusHandler.SetUInt64Value(common.MetricDenomination, 4)
totalRewards, diff := presenterStatusHandler.GetTotalRewardsValue()
expectedDiffValue := "4000" + presenterStatusHandler.GetZeros()

assert.Equal(t, totalRewardsOld.Text('f', precisionRewards), totalRewards)
assert.Equal(t, expectedDiffValue, diff)
testRedundancyParsing(t, "-1", -1)
testRedundancyParsing(t, "0", 0)
testRedundancyParsing(t, "invalid", 0)
testRedundancyParsing(t, "1", 1)
}

func TestPresenterStatusHandler_CalculateRewardsPerHourReturnZero(t *testing.T) {
t.Parallel()

presenterStatusHandler := NewPresenterStatusHandler()
result := presenterStatusHandler.CalculateRewardsPerHour()

assert.Equal(t, "0", result)
}

func TestPresenterStatusHandler_CalculateRewardsPerHourShouldWork(t *testing.T) {
t.Parallel()

consensusGroupSize := uint64(50)
numValidators := uint64(100)
totalBlocks := uint64(1000)
totalRounds := uint64(1000)
roundTime := uint64(6)
rewardsValue := "10000"

presenterStatusHandler := NewPresenterStatusHandler()
presenterStatusHandler.SetUInt64Value(common.MetricConsensusGroupSize, consensusGroupSize)
presenterStatusHandler.SetUInt64Value(common.MetricNumValidators, numValidators)
presenterStatusHandler.SetUInt64Value(common.MetricProbableHighestNonce, totalBlocks)
presenterStatusHandler.SetStringValue(common.MetricRewardsValue, rewardsValue)
presenterStatusHandler.SetUInt64Value(common.MetricCurrentRound, totalRounds)
presenterStatusHandler.SetUInt64Value(common.MetricRoundTime, roundTime)
presenterStatusHandler.SetUInt64Value(common.MetricDenomination, 4)
expectedValue := "300" + presenterStatusHandler.GetZeros()

result := presenterStatusHandler.CalculateRewardsPerHour()
assert.Equal(t, expectedValue, result)
func testRedundancyParsing(t *testing.T, input string, desiredOutput int64) {
psh := NewPresenterStatusHandler()
psh.SetStringValue(common.MetricRedundancyLevel, input)
redLev := psh.GetRedundancyLevel()
require.Equal(t, desiredOutput, redLev)
}
6 changes: 2 additions & 4 deletions cmd/termui/view/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ type Presenter interface {
GetAppVersion() string
GetNodeName() string
GetPublicKeyBlockSign() string
GetRedundancyLevel() int64
GetRedundancyIsMainActive() string
GetShardId() uint64
GetNodeType() string
GetPeerType() string
Expand Down Expand Up @@ -55,10 +57,6 @@ type Presenter interface {
GetNetworkSentBytesInEpoch() uint64
GetNetworkReceivedBytesInEpoch() uint64

GetTotalRewardsValue() (string, string)
CalculateRewardsPerHour() string
GetZeros() string

InvalidateCache()
IsInterfaceNil() bool
}
56 changes: 29 additions & 27 deletions cmd/termui/view/termuic/termuiRenders/widgetsRender.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import (
"github.com/gizak/termui/v3/widgets"
)

const statusSyncing = "currently syncing"
const statusSynchronized = "synchronized"
const invalidKey = "invalid key"
const (
statusSyncing = "currently syncing"
statusSynchronized = "synchronized"
statusNotApplicable = "N/A"
invalidKey = "invalid key"
)

// WidgetsRender will define termui widgets that need to display a termui console
type WidgetsRender struct {
Expand Down Expand Up @@ -162,30 +165,7 @@ func (wr *WidgetsRender) prepareInstanceInfo() {
countAcceptedBlocks := wr.presenter.GetCountAcceptedBlocks()
rows[4] = []string{fmt.Sprintf("Blocks proposed: %d | Blocks accepted: %d", countLeader, countAcceptedBlocks)}

// TODO: repair the rewards estimation or replace these 2 rows with rating details
//switch instanceType {
//case string(common.NodeTypeValidator):
// rewardsPerHour := wr.presenter.CalculateRewardsPerHour()
// rows[5] = []string{fmt.Sprintf("Rewards estimation: %s ERD/h (without fees)", rewardsPerHour)}
//
// var rewardsInfo []string
// totalRewardsValue, diffRewards := wr.presenter.GetTotalRewardsValue()
// zeroString := "0" + wr.presenter.GetZeros()
// if diffRewards != zeroString {
// wr.instanceInfo.RowStyles[7] = ui.NewStyle(ui.ColorGreen)
// rewardsInfo = []string{fmt.Sprintf("Total rewards %s + %s ERD (without fees)", totalRewardsValue, diffRewards)}
// } else {
// wr.instanceInfo.RowStyles[7] = ui.NewStyle(ui.ColorWhite)
// rewardsInfo = []string{fmt.Sprintf("Total rewards %s ERD (without fees)", totalRewardsValue)}
// }
// rows[6] = rewardsInfo
//
//default:
// rows[5] = []string{""}
// rows[6] = []string{""}
//}

rows[5] = []string{""}
rows[5] = []string{computeRedundancyStr(wr.presenter.GetRedundancyLevel(), wr.presenter.GetRedundancyIsMainActive())}
rows[6] = []string{""}

wr.instanceInfo.Title = "Elrond instance info"
Expand All @@ -211,6 +191,8 @@ func (wr *WidgetsRender) prepareChainInfo(numMillisecondsRefreshTime int) {

blocksPerSecond := wr.presenter.CalculateSynchronizationSpeed(numMillisecondsRefreshTime)
blocksPerSecondMessage = fmt.Sprintf("%d blocks/sec", blocksPerSecond)
case currentRound == 0:
syncingStr = statusNotApplicable
default:
syncingStr = statusSynchronized
}
Expand Down Expand Up @@ -263,6 +245,26 @@ func (wr *WidgetsRender) prepareChainInfo(numMillisecondsRefreshTime int) {
wr.chainInfo.Rows = rows
}

func computeRedundancyStr(redundancyLevel int64, redundancyIsMainActive string) string {
if redundancyIsMainActive == statusNotApplicable {
return ""
}

redundancyStr := "Redundancy: "
if redundancyLevel < 0 {
redundancyStr += "inactive"
} else {
if redundancyLevel == 0 {
redundancyStr += "main machine"
} else {
redundancyStr += fmt.Sprintf("back-up #%d", redundancyLevel)
redundancyStr += fmt.Sprintf(" (is main active: %s)", redundancyIsMainActive)
}
}

return redundancyStr
}

func (wr *WidgetsRender) prepareBlockInfo() {
//7 rows and one column
numRows := 8
Expand Down
13 changes: 11 additions & 2 deletions common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,16 +276,25 @@ const MetricRoundsPassedInCurrentEpoch = "erd_rounds_passed_in_current_epoch"
// MetricNoncesPassedInCurrentEpoch is the metric that tells the number of nonces passed in current epoch
const MetricNoncesPassedInCurrentEpoch = "erd_nonces_passed_in_current_epoch"

//MetricReceivedProposedBlock is the metric that specify the moment in the round when the received block has reached the
//MetricReceivedProposedBlock is the metric that specifies the moment in the round when the received block has reached the
//current node. The value is provided in percent (0 meaning it has been received just after the round started and
//100 meaning that the block has been received in the last moment of the round)
const MetricReceivedProposedBlock = "erd_consensus_received_proposed_block"

//MetricCreatedProposedBlock is the metric that specify the percent of the block subround used for header and body
//MetricCreatedProposedBlock is the metric that specifies the percent of the block subround used for header and body
//creation (0 meaning that the block was created in no-time and 100 meaning that the block creation used all the
//subround spare duration)
const MetricCreatedProposedBlock = "erd_consensus_created_proposed_block"

// MetricRedundancyLevel is the metric that specifies the redundancy level of the current node
const MetricRedundancyLevel = "erd_redundancy_level"

// MetricRedundancyMainActive is the metrics that specifies data about the redundancy main machine
const MetricRedundancyIsMainActive = "erd_redundancy_is_main_active"

// MetricValueNA represents the value to be used when a metric is not available/applicable
const MetricValueNA = "N/A"

//MetricProcessedProposedBlock is the metric that specify the percent of the block subround used for header and body
//processing (0 meaning that the block was processed in no-time and 100 meaning that the block processing used all the
//subround spare duration)
Expand Down
27 changes: 27 additions & 0 deletions common/disabled/processStatusHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package disabled

// processStatusHandler is the disabled implementation for the status handler that keeps track what the node is doing:
// processing blocks or idle
type processStatusHandler struct {
}

// NewProcessStatusHandler creates a new instance of type processStatusHandler
func NewProcessStatusHandler() *processStatusHandler {
return &processStatusHandler{}
}

// SetBusy does nothing
func (psh *processStatusHandler) SetBusy(_ string) {}

// SetIdle does nothing
func (psh *processStatusHandler) SetIdle() {}

// IsIdle returns true
func (psh *processStatusHandler) IsIdle() bool {
return true
}

// IsInterfaceNil returns true if there is no value under the interface
func (psh *processStatusHandler) IsInterfaceNil() bool {
return psh == nil
}
26 changes: 26 additions & 0 deletions common/disabled/processStatusHandler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package disabled

import (
"fmt"
"testing"

"github.com/ElrondNetwork/elrond-go-core/core/check"
"github.com/stretchr/testify/assert"
)

func TestProcessStatusHandler_MethodsShouldNotPanic(t *testing.T) {
t.Parallel()

defer func() {
r := recover()
if r != nil {
assert.Fail(t, fmt.Sprintf("should have not panicked: %v", r))
}
}()

psh := NewProcessStatusHandler()
assert.False(t, check.IfNil(psh))
psh.SetBusy("")
psh.SetIdle()
assert.True(t, psh.IsIdle())
}
Loading

0 comments on commit beb0e4f

Please sign in to comment.