From 8bc1e0d0a96c4432c30a8e26995001aff67cff9e Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 3 Dec 2024 20:32:27 -0500 Subject: [PATCH] Make the absenteeism factor = 20 instead of 10 --- ledger/apply/heartbeat.go | 4 ++-- ledger/eval/eval.go | 11 +++++++---- ledger/eval/eval_test.go | 18 +++++++++--------- ledger/eval_simple_test.go | 14 ++++++++------ .../features/incentives/suspension_test.go | 7 +++---- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/ledger/apply/heartbeat.go b/ledger/apply/heartbeat.go index 9e1056dc3c..ec6bc3a768 100644 --- a/ledger/apply/heartbeat.go +++ b/ledger/apply/heartbeat.go @@ -43,8 +43,8 @@ func Heartbeat(hb transactions.HeartbeatTxnFields, header transactions.Header, b kind = "cheap" } - // These first checks are a little draconian. The idea is not let these - // free transactions do anything except their exact intended purpose. + // These first checks are a little draconian. Don't let these free + // transactions do anything except their exact intended purpose. if len(header.Note) > 0 { return fmt.Errorf("%s heartbeat is not allowed to have a note", kind) } diff --git a/ledger/eval/eval.go b/ledger/eval/eval.go index 7bd8577b9f..c3eececc88 100644 --- a/ledger/eval/eval.go +++ b/ledger/eval/eval.go @@ -1768,6 +1768,8 @@ func (eval *BlockEvaluator) generateKnockOfflineAccountsList(participating []bas } } +const absentFactor = 20 + func isAbsent(totalOnlineStake basics.MicroAlgos, acctStake basics.MicroAlgos, lastSeen basics.Round, current basics.Round) bool { // Don't consider accounts that were online when payouts went into effect as // absent. They get noticed the next time they propose or keyreg, which @@ -1775,11 +1777,12 @@ func isAbsent(totalOnlineStake basics.MicroAlgos, acctStake basics.MicroAlgos, l if lastSeen == 0 || acctStake.Raw == 0 { return false } - // See if the account has exceeded 10x their expected observation interval. - allowableLag, o := basics.Muldiv(10, totalOnlineStake.Raw, acctStake.Raw) + // See if the account has exceeded their expected observation interval. + allowableLag, o := basics.Muldiv(absentFactor, totalOnlineStake.Raw, acctStake.Raw) if o { - // This can't happen with 10B total possible stake, but if we imagine - // another algorand network with huge possible stake, this seems reasonable. + // This can't happen with 10B total possible stake and a reasonable + // absentFactor, but if we imagine another algorand network with huge + // possible stake, this seems reasonable. allowableLag = math.MaxInt64 / acctStake.Raw } return lastSeen+basics.Round(allowableLag) < current diff --git a/ledger/eval/eval_test.go b/ledger/eval/eval_test.go index d33996b2d8..d92ff31f1b 100644 --- a/ledger/eval/eval_test.go +++ b/ledger/eval/eval_test.go @@ -1385,7 +1385,7 @@ func TestAbsenteeChecks(t *testing.T) { blkEval = l.nextBlock(t) switch vb.Block().Round() { - case 102: // 2 out of 10 genesis accounts are now absent + case 202: // 2 out of 10 genesis accounts are now absent require.Contains(t, vb.Block().AbsentParticipationAccounts, addrs[1]) require.Contains(t, vb.Block().AbsentParticipationAccounts, addrs[2]) case 1000: @@ -1613,13 +1613,13 @@ func TestIsAbsent(t *testing.T) { var absent = func(total uint64, acct uint64, last uint64, current uint64) bool { return isAbsent(basics.Algos(total), basics.Algos(acct), basics.Round(last), basics.Round(current)) } - // 1% of stake, absent for 1000 rounds - a.False(absent(1000, 10, 5000, 6000)) - a.True(absent(1000, 10, 5000, 6001)) // longer - a.True(absent(1000, 11, 5000, 6001)) // more acct stake - a.False(absent(1000, 9, 5000, 6001)) // less acct stake - a.False(absent(1001, 10, 5000, 6001)) // more online stake + a.False(absent(1000, 10, 5000, 6000)) // 1% of stake, absent for 1000 rounds + a.False(absent(1000, 10, 5000, 7000)) // 1% of stake, absent for 2000 rounds + a.True(absent(1000, 10, 5000, 7001)) // 2001 + a.True(absent(1000, 11, 5000, 7000)) // more acct stake drives percent down, makes it absent + a.False(absent(1000, 9, 5000, 7001)) // less acct stake + a.False(absent(1001, 10, 5000, 7001)) // more online stake // not absent if never seen - a.False(absent(1000, 10, 0, 6000)) - a.False(absent(1000, 10, 0, 6001)) + a.False(absent(1000, 10, 0, 2001)) + a.True(absent(1000, 10, 1, 2002)) } diff --git a/ledger/eval_simple_test.go b/ledger/eval_simple_test.go index 191ee6e1c0..94ff28bbdc 100644 --- a/ledger/eval_simple_test.go +++ b/ledger/eval_simple_test.go @@ -610,7 +610,9 @@ func TestAbsentTracking(t *testing.T) { var addr1off basics.Round var addr2off basics.Round - // We're at 20, skip ahead by lookback + 30 to see the knockoffs + // We're at 20, skip ahead by lookback + 60 to see the knockoffs + const absentFactor = 20 + skip := basics.Round(3) * absentFactor for { vb := dl.fullBlock() printAbsent(vb) @@ -643,12 +645,12 @@ func TestAbsentTracking(t *testing.T) { checkState(addrs[2], true, true, 833_333_331_429_333) // after keyreg w/ 2A is effective } - if rnd > 20+lookback+30 { + if rnd > 20+lookback+skip { break } } - require.Equal(t, addr2Eligible+lookback+30, addr2off) - require.Equal(t, addr1Keyreg+lookback+31, addr1off) // addr1 paid out a little bit, extending its lag by 1 + require.Equal(t, addr2Eligible+lookback+skip, addr2off) + require.Equal(t, addr1Keyreg+lookback+skip+1, addr1off) // addr1 paid out a little bit, extending its lag by 1 require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[0]).Status) // genesis account require.Equal(t, basics.Offline, lookup(t, dl.generator, addrs[1]).Status) @@ -683,11 +685,11 @@ func TestAbsentTracking(t *testing.T) { addr2check = true } - if rnd > 20+2*lookback+30 { + if rnd > 20+2*lookback+skip { break } } - // sanity check that we didn't skip one because of checkstate advanacing a round + // sanity check that we didn't skip one because of checkstate advancing a round require.True(t, addr1check) require.True(t, addr2check) diff --git a/test/e2e-go/features/incentives/suspension_test.go b/test/e2e-go/features/incentives/suspension_test.go index cb9ff47259..0191f6613c 100644 --- a/test/e2e-go/features/incentives/suspension_test.go +++ b/test/e2e-go/features/incentives/suspension_test.go @@ -45,10 +45,10 @@ func TestBasicSuspension(t *testing.T) { // Start a three-node network (70,20,10), all online // Wait for 10 and 20% nodes to propose (we never suspend accounts with lastProposed=lastHeartbeat=0) // Stop them both - // Run for 55 rounds, which is enough for 20% node to be suspended, but not 10% + // Run for 105 rounds, which is enough for 20% node to be suspended, but not 10% // check neither suspended, send a tx from 20% to 10%, only 20% gets suspended - // TODO once we have heartbeats: bring them back up, make sure 20% gets back online - const suspend20 = 55 + // bring n20 back up, make sure it gets back online by proposing during the lookback + const suspend20 = 105 // 1.00/0.20 * absentFactor var fixture fixtures.RestClientFixture // Speed up rounds. Long enough lookback, so 20% node has a chance to @@ -101,7 +101,6 @@ func TestBasicSuspension(t *testing.T) { a.NotZero(account.VoteID) a.False(account.IncentiveEligible) // suspension turns off flag - // TODO: n10 wasn't turned off, it's still online account, err = c10.AccountData(account10.Address) a.NoError(err) a.Equal(basics.Online, account.Status)