Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 16 additions & 38 deletions module/epochs/machine_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,39 @@ import (
)

var (
// Hard and soft balance limits for collection and consensus nodes.
// We will log a warning once for a soft limit, and will log an error
// in perpetuity for a hard limit.
// Balance limits for collection and consensus nodes.
// Taken from https://www.notion.so/dapperlabs/Machine-Account-f3c293593ea442a39614fcebf705a132
// TODO update these for FLIP74

defaultSoftMinBalanceLN cadence.UFix64
defaultHardMinBalanceLN cadence.UFix64
defaultSoftMinBalanceSN cadence.UFix64
defaultHardMinBalanceSN cadence.UFix64
cdcRecommendedMinBalanceLN cadence.UFix64
cdcRecommendedMinBalanceSN cadence.UFix64
)

const (
recommendedMinBalanceLN = 0.002
recommendedMinBalanceSN = 0.05
// We recommend node operators refill once they reach this threshold
recommendedMinBalanceLN = 0.25
recommendedMinBalanceSN = 2.0
recommendedRefillToBalanceLN = 0.75
recommendedRefillToBalanceSN = 6.0
)

func init() {
var err error
defaultSoftMinBalanceLN, err = cadence.NewUFix64("0.0025")
if err != nil {
panic(fmt.Errorf("could not convert soft min balance for LN: %w", err))
}
defaultHardMinBalanceLN, err = cadence.NewUFix64("0.002")
cdcRecommendedMinBalanceLN, err = cadence.NewUFix64("0.25")
if err != nil {
panic(fmt.Errorf("could not convert hard min balance for LN: %w", err))
}
defaultSoftMinBalanceSN, err = cadence.NewUFix64("0.125")
if err != nil {
panic(fmt.Errorf("could not convert soft min balance for SN: %w", err))
}
defaultHardMinBalanceSN, err = cadence.NewUFix64("0.05")
cdcRecommendedMinBalanceSN, err = cadence.NewUFix64("2.0")
if err != nil {
panic(fmt.Errorf("could not convert hard min balance for SN: %w", err))
}

// sanity checks
if asFloat, err := ufix64Tofloat64(defaultHardMinBalanceLN); err != nil {
if asFloat, err := ufix64Tofloat64(cdcRecommendedMinBalanceLN); err != nil {
panic(err)
} else if asFloat != recommendedMinBalanceLN {
panic(fmt.Errorf("failed sanity check: %f!=%f", asFloat, recommendedMinBalanceLN))
}
if asFloat, err := ufix64Tofloat64(defaultHardMinBalanceSN); err != nil {
if asFloat, err := ufix64Tofloat64(cdcRecommendedMinBalanceSN); err != nil {
panic(err)
} else if asFloat != recommendedMinBalanceSN {
panic(fmt.Errorf("failed sanity check: %f!=%f", asFloat, recommendedMinBalanceSN))
Expand All @@ -91,28 +81,22 @@ func checkMachineAccountRetryBackoff() retry.Backoff {

// MachineAccountValidatorConfig defines configuration options for MachineAccountConfigValidator.
type MachineAccountValidatorConfig struct {
SoftMinBalanceLN cadence.UFix64
HardMinBalanceLN cadence.UFix64
SoftMinBalanceSN cadence.UFix64
HardMinBalanceSN cadence.UFix64
}

func DefaultMachineAccountValidatorConfig() MachineAccountValidatorConfig {
return MachineAccountValidatorConfig{
SoftMinBalanceLN: defaultSoftMinBalanceLN,
HardMinBalanceLN: defaultHardMinBalanceLN,
SoftMinBalanceSN: defaultSoftMinBalanceSN,
HardMinBalanceSN: defaultHardMinBalanceSN,
HardMinBalanceLN: cdcRecommendedMinBalanceLN,
HardMinBalanceSN: cdcRecommendedMinBalanceSN,
}
}

// WithoutBalanceChecks sets minimum balances to 0 to effectively disable minimum
// balance checks. This is useful for test networks where transaction fees are
// disabled.
func WithoutBalanceChecks(conf *MachineAccountValidatorConfig) {
conf.SoftMinBalanceLN = 0
conf.HardMinBalanceLN = 0
conf.SoftMinBalanceSN = 0
conf.HardMinBalanceSN = 0
}

Expand Down Expand Up @@ -323,17 +307,11 @@ func CheckMachineAccountInfo(
switch role {
case flow.RoleCollection:
if balance < conf.HardMinBalanceLN {
return fmt.Errorf("machine account balance is below hard minimum (%s < %s)", balance, conf.HardMinBalanceLN)
}
if balance < conf.SoftMinBalanceLN {
log.Warn().Msgf("machine account balance is below recommended balance (%s < %s)", balance, conf.SoftMinBalanceLN)
return fmt.Errorf("machine account balance is below minimum (%s < %s). Please refill to %f FLOW", balance, conf.HardMinBalanceLN, recommendedRefillToBalanceLN)
}
case flow.RoleConsensus:
if balance < conf.HardMinBalanceSN {
return fmt.Errorf("machine account balance is below hard minimum (%s < %s)", balance, conf.HardMinBalanceSN)
}
if balance < conf.SoftMinBalanceSN {
log.Warn().Msgf("machine account balance is below recommended balance (%s < %s)", balance, conf.SoftMinBalanceSN)
return fmt.Errorf("machine account balance is below minimum (%s < %s). Please refill to %f FLOW", balance, conf.HardMinBalanceSN, recommendedRefillToBalanceSN)
}
default:
// sanity check - should be caught earlier in this function
Expand Down
35 changes: 6 additions & 29 deletions module/epochs/machine_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ func TestMachineAccountChecking(t *testing.T) {
t.Run("account with < hard minimum balance", func(t *testing.T) {
t.Run("collection", func(t *testing.T) {
local, remote := unittest.MachineAccountFixture(t)
remote.Balance = uint64(defaultHardMinBalanceLN) - 1
remote.Balance = uint64(cdcRecommendedMinBalanceLN) - 1
err := CheckMachineAccountInfo(zerolog.Nop(), conf, flow.RoleCollection, local, remote)
require.Error(t, err)
})
t.Run("consensus", func(t *testing.T) {
local, remote := unittest.MachineAccountFixture(t)
remote.Balance = uint64(defaultHardMinBalanceSN) - 1
remote.Balance = uint64(cdcRecommendedMinBalanceSN) - 1
err := CheckMachineAccountInfo(zerolog.Nop(), conf, flow.RoleConsensus, local, remote)
require.Error(t, err)
})
Expand All @@ -115,29 +115,6 @@ func TestMachineAccountChecking(t *testing.T) {
})
})

// should log a warning when balance below soft minimum balance (but not
// below hard minimum balance)
t.Run("account with < soft minimum balance", func(t *testing.T) {
t.Run("collection", func(t *testing.T) {
local, remote := unittest.MachineAccountFixture(t)
remote.Balance = uint64(defaultSoftMinBalanceLN) - 1
log, hook := unittest.HookedLogger()

err := CheckMachineAccountInfo(log, conf, flow.RoleCollection, local, remote)
assert.NoError(t, err)
assert.Regexp(t, "machine account balance is below recommended balance", hook.Logs())
})
t.Run("consensus", func(t *testing.T) {
local, remote := unittest.MachineAccountFixture(t)
remote.Balance = uint64(defaultSoftMinBalanceSN) - 1
log, hook := unittest.HookedLogger()

err := CheckMachineAccountInfo(log, conf, flow.RoleConsensus, local, remote)
assert.NoError(t, err)
assert.Regexp(t, "machine account balance is below recommended balance", hook.Logs())
})
})

// should log a warning when the local file deviates from defaults
t.Run("local file deviates from defaults", func(t *testing.T) {
t.Run("hash algo", func(t *testing.T) {
Expand Down Expand Up @@ -187,8 +164,8 @@ func TestMachineAccountValidatorBackoff_Overflow(t *testing.T) {
backoff := checkMachineAccountRetryBackoff()

// once the backoff reaches the maximum, it should remain in [(1-jitter)*max,(1+jitter*max)]
max := checkMachineAccountRetryMax + checkMachineAccountRetryMax*(checkMachineAccountRetryJitterPct+1)/100
min := checkMachineAccountRetryMax - checkMachineAccountRetryMax*(checkMachineAccountRetryJitterPct+1)/100
maxBackoff := checkMachineAccountRetryMax + checkMachineAccountRetryMax*(checkMachineAccountRetryJitterPct+1)/100
minBackoff := checkMachineAccountRetryMax - checkMachineAccountRetryMax*(checkMachineAccountRetryJitterPct+1)/100

lastWait, stop := backoff.Next()
assert.False(t, stop)
Expand All @@ -199,8 +176,8 @@ func TestMachineAccountValidatorBackoff_Overflow(t *testing.T) {
// * strictly increase, or
// * be within range of max duration + jitter
if wait < lastWait {
assert.Less(t, min, wait)
assert.Less(t, wait, max)
assert.Less(t, minBackoff, wait)
assert.Less(t, wait, maxBackoff)
}
lastWait = wait
}
Expand Down
2 changes: 1 addition & 1 deletion utils/unittest/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -2642,7 +2642,7 @@ func MachineAccountFixture(t *testing.T) (
) {
info := NodeMachineAccountInfoFixture()

bal, err := cadence.NewUFix64("0.5")
bal, err := cadence.NewUFix64("5.0")
require.NoError(t, err)

acct := &sdk.Account{
Expand Down
Loading