diff --git a/agreement/agreementtest/simulate_test.go b/agreement/agreementtest/simulate_test.go index 5c436a761c..0bb4d8d109 100644 --- a/agreement/agreementtest/simulate_test.go +++ b/agreement/agreementtest/simulate_test.go @@ -207,7 +207,7 @@ func (l *testLedger) LookupAgreement(r basics.Round, a basics.Address) (basics.O err := fmt.Errorf("Lookup called on future round: %v > %v! (this is probably a bug)", r, l.nextRound) panic(err) } - return l.state[a].OnlineAccountData(), nil + return basics_testing.OnlineAccountData(l.state[a]), nil } func (l *testLedger) Circulation(r basics.Round, voteRnd basics.Round) (basics.MicroAlgos, error) { @@ -222,7 +222,7 @@ func (l *testLedger) Circulation(r basics.Round, voteRnd basics.Round) (basics.M var sum basics.MicroAlgos var overflowed bool for _, rec := range l.state { - sum, overflowed = basics.OAddA(sum, rec.OnlineAccountData().VotingStake()) + sum, overflowed = basics.OAddA(sum, basics_testing.OnlineAccountData(rec).VotingStake()) if overflowed { panic("circulation computation overflowed") } diff --git a/agreement/common_test.go b/agreement/common_test.go index 1cbba828ab..9fa2a2829e 100644 --- a/agreement/common_test.go +++ b/agreement/common_test.go @@ -29,6 +29,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" + basics_testing "github.com/algorand/go-algorand/data/basics/testing" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/committee" "github.com/algorand/go-algorand/logging" @@ -332,7 +333,7 @@ func (l *testLedger) LookupAgreement(r basics.Round, a basics.Address) (basics.O return basics.OnlineAccountData{}, &LedgerDroppedRoundError{} } - return l.state[a].OnlineAccountData(), nil + return basics_testing.OnlineAccountData(l.state[a]), nil } func (l *testLedger) Circulation(r basics.Round, voteRnd basics.Round) (basics.MicroAlgos, error) { @@ -347,7 +348,7 @@ func (l *testLedger) Circulation(r basics.Round, voteRnd basics.Round) (basics.M var sum basics.MicroAlgos var overflowed bool for _, rec := range l.state { - sum, overflowed = basics.OAddA(sum, rec.OnlineAccountData().VotingStake()) + sum, overflowed = basics.OAddA(sum, basics_testing.OnlineAccountData(rec).VotingStake()) if overflowed { panic("circulation computation overflowed") } diff --git a/agreement/fuzzer/ledger_test.go b/agreement/fuzzer/ledger_test.go index 53a05f761b..efe21958ad 100644 --- a/agreement/fuzzer/ledger_test.go +++ b/agreement/fuzzer/ledger_test.go @@ -25,6 +25,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" + basics_testing "github.com/algorand/go-algorand/data/basics/testing" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/committee" "github.com/algorand/go-algorand/protocol" @@ -241,7 +242,7 @@ func (l *testLedger) LookupAgreement(r basics.Round, a basics.Address) (basics.O err := fmt.Errorf("Lookup called on future round: %d >= %d! (this is probably a bug)", r, l.nextRound) panic(err) } - return l.state[a].OnlineAccountData(), nil + return basics_testing.OnlineAccountData(l.state[a]), nil } func (l *testLedger) Circulation(r basics.Round, voteRnd basics.Round) (basics.MicroAlgos, error) { @@ -256,7 +257,7 @@ func (l *testLedger) Circulation(r basics.Round, voteRnd basics.Round) (basics.M var sum basics.MicroAlgos var overflowed bool for _, rec := range l.state { - sum, overflowed = basics.OAddA(sum, rec.OnlineAccountData().VotingStake()) + sum, overflowed = basics.OAddA(sum, basics_testing.OnlineAccountData(rec).VotingStake()) if overflowed { panic("circulation computation overflowed") } diff --git a/data/basics/testing/userBalance.go b/data/basics/testing/userBalance.go index 1d9d673d7b..f12737c767 100644 --- a/data/basics/testing/userBalance.go +++ b/data/basics/testing/userBalance.go @@ -29,3 +29,28 @@ func MakeAccountData(status basics.Status, algos basics.MicroAlgos) basics.Accou } return ad } + +// OnlineAccountData converts basics.AccountData to basics.OnlineAccountData. +// Account is expected to be Online otherwise it is cleared out. +// This function is intended for testing purposes only. +func OnlineAccountData(u basics.AccountData) basics.OnlineAccountData { + if u.Status != basics.Online { + // if the account is not Online and agreement requests it for some reason, clear it out + return basics.OnlineAccountData{} + } + + return basics.OnlineAccountData{ + MicroAlgosWithRewards: u.MicroAlgos, + VotingData: basics.VotingData{ + VoteID: u.VoteID, + SelectionID: u.SelectionID, + StateProofID: u.StateProofID, + VoteFirstValid: u.VoteFirstValid, + VoteLastValid: u.VoteLastValid, + VoteKeyDilution: u.VoteKeyDilution, + }, + IncentiveEligible: u.IncentiveEligible, + LastProposed: u.LastProposed, + LastHeartbeat: u.LastHeartbeat, + } +} diff --git a/data/basics/testing/userBalance_test.go b/data/basics/testing/userBalance_test.go new file mode 100644 index 0000000000..38bef08bea --- /dev/null +++ b/data/basics/testing/userBalance_test.go @@ -0,0 +1,73 @@ +// Copyright (C) 2019-2025 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package testing + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/crypto/merklesignature" + "github.com/algorand/go-algorand/data/basics" + "github.com/algorand/go-algorand/test/partitiontest" +) + +// Helper function to create a sample account data for testing +func getSampleAccountData() basics.AccountData { + oneTimeSecrets := crypto.GenerateOneTimeSignatureSecrets(0, 1) + vrfSecrets := crypto.GenerateVRFSecrets() + var stateProofID merklesignature.Commitment + crypto.RandBytes(stateProofID[:]) + + return basics.AccountData{ + Status: basics.NotParticipating, + MicroAlgos: basics.MicroAlgos{}, + RewardsBase: 0x1234123412341234, + RewardedMicroAlgos: basics.MicroAlgos{}, + VoteID: oneTimeSecrets.OneTimeSignatureVerifier, + SelectionID: vrfSecrets.PK, + StateProofID: stateProofID, + VoteFirstValid: basics.Round(0x1234123412341234), + VoteLastValid: basics.Round(0x1234123412341234), + VoteKeyDilution: 0x1234123412341234, + AssetParams: make(map[basics.AssetIndex]basics.AssetParams), + Assets: make(map[basics.AssetIndex]basics.AssetHolding), + AppLocalStates: make(map[basics.AppIndex]basics.AppLocalState), + AppParams: make(map[basics.AppIndex]basics.AppParams), + AuthAddr: basics.Address(crypto.Hash([]byte{1, 2, 3, 4})), + IncentiveEligible: true, + } +} + +func TestOnlineAccountData(t *testing.T) { + partitiontest.PartitionTest(t) + + ad := getSampleAccountData() + ad.MicroAlgos.Raw = 1000000 + ad.Status = basics.Offline + + oad := OnlineAccountData(ad) + require.Empty(t, oad) + + ad.Status = basics.Online + oad = OnlineAccountData(ad) + require.Equal(t, ad.MicroAlgos, oad.MicroAlgosWithRewards) + require.Equal(t, ad.VoteID, oad.VoteID) + require.Equal(t, ad.SelectionID, oad.SelectionID) + require.Equal(t, ad.IncentiveEligible, oad.IncentiveEligible) +} diff --git a/data/basics/userBalance.go b/data/basics/userBalance.go index 4a2da748a9..468507a102 100644 --- a/data/basics/userBalance.go +++ b/data/basics/userBalance.go @@ -545,30 +545,6 @@ func MinBalance( return MicroAlgos{min} } -// OnlineAccountData returns subset of AccountData as OnlineAccountData data structure. -// Account is expected to be Online otherwise its is cleared out -func (u AccountData) OnlineAccountData() OnlineAccountData { - if u.Status != Online { - // if the account is not Online and agreement requests it for some reason, clear it out - return OnlineAccountData{} - } - - return OnlineAccountData{ - MicroAlgosWithRewards: u.MicroAlgos, - VotingData: VotingData{ - VoteID: u.VoteID, - SelectionID: u.SelectionID, - StateProofID: u.StateProofID, - VoteFirstValid: u.VoteFirstValid, - VoteLastValid: u.VoteLastValid, - VoteKeyDilution: u.VoteKeyDilution, - }, - IncentiveEligible: u.IncentiveEligible, - LastProposed: u.LastProposed, - LastHeartbeat: u.LastHeartbeat, - } -} - // VotingStake returns the amount of MicroAlgos associated with the user's account // for the purpose of participating in the Algorand protocol. It assumes the // caller has already updated rewards appropriately using WithUpdatedRewards(). diff --git a/data/basics/userBalance_test.go b/data/basics/userBalance_test.go index cc4ba8056a..52b9c54c94 100644 --- a/data/basics/userBalance_test.go +++ b/data/basics/userBalance_test.go @@ -24,8 +24,6 @@ import ( "github.com/stretchr/testify/require" "github.com/algorand/go-algorand/config" - "github.com/algorand/go-algorand/crypto" - "github.com/algorand/go-algorand/crypto/merklesignature" "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" ) @@ -98,40 +96,6 @@ func TestWithUpdatedRewardsPanics(t *testing.T) { }) } -func makeString(len int) string { - s := "" - for i := 0; i < len; i++ { - s += string(byte(i)) - } - return s -} - -func getSampleAccountData() AccountData { - oneTimeSecrets := crypto.GenerateOneTimeSignatureSecrets(0, 1) - vrfSecrets := crypto.GenerateVRFSecrets() - var stateProofID merklesignature.Commitment - crypto.RandBytes(stateProofID[:]) - - return AccountData{ - Status: NotParticipating, - MicroAlgos: MicroAlgos{}, - RewardsBase: 0x1234123412341234, - RewardedMicroAlgos: MicroAlgos{}, - VoteID: oneTimeSecrets.OneTimeSignatureVerifier, - SelectionID: vrfSecrets.PK, - StateProofID: stateProofID, - VoteFirstValid: Round(0x1234123412341234), - VoteLastValid: Round(0x1234123412341234), - VoteKeyDilution: 0x1234123412341234, - AssetParams: make(map[AssetIndex]AssetParams), - Assets: make(map[AssetIndex]AssetHolding), - AppLocalStates: make(map[AppIndex]AppLocalState), - AppParams: make(map[AppIndex]AppParams), - AuthAddr: Address(crypto.Hash([]byte{1, 2, 3, 4})), - IncentiveEligible: true, - } -} - func TestEncodedAccountAllocationBounds(t *testing.T) { partitiontest.PartitionTest(t) @@ -175,21 +139,3 @@ func TestAppIndexHashing(t *testing.T) { i = AppIndex(77) require.Equal(t, "PCYUFPA2ZTOYWTP43MX2MOX2OWAIAXUDNC2WFCXAGMRUZ3DYD6BWFDL5YM", i.Address().String()) } - -func TestOnlineAccountData(t *testing.T) { - partitiontest.PartitionTest(t) - - ad := getSampleAccountData() - ad.MicroAlgos.Raw = 1000000 - ad.Status = Offline - - oad := ad.OnlineAccountData() - require.Empty(t, oad) - - ad.Status = Online - oad = ad.OnlineAccountData() - require.Equal(t, ad.MicroAlgos, oad.MicroAlgosWithRewards) - require.Equal(t, ad.VoteID, oad.VoteID) - require.Equal(t, ad.SelectionID, oad.SelectionID) - require.Equal(t, ad.IncentiveEligible, oad.IncentiveEligible) -} diff --git a/data/committee/common_test.go b/data/committee/common_test.go index 98437117db..f6dd60ecf2 100644 --- a/data/committee/common_test.go +++ b/data/committee/common_test.go @@ -24,6 +24,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" + basics_testing "github.com/algorand/go-algorand/data/basics/testing" "github.com/algorand/go-algorand/protocol" ) @@ -97,7 +98,7 @@ func testingenvMoreKeys(t testing.TB, numAccounts, numTxs int, seedGen io.Reader if !ok { return false, BalanceRecord{}, Seed{}, basics.MicroAlgos{Raw: 0} } - return true, BalanceRecord{Addr: addr, OnlineAccountData: data.OnlineAccountData()}, seed, total + return true, BalanceRecord{Addr: addr, OnlineAccountData: basics_testing.OnlineAccountData(data)}, seed, total } selParamsList := func(addrs []basics.Address) (ok bool, records []BalanceRecord, seed Seed, total basics.MicroAlgos) { diff --git a/ledger/acctonline_test.go b/ledger/acctonline_test.go index 4e8f7b1759..0335a20f6f 100644 --- a/ledger/acctonline_test.go +++ b/ledger/acctonline_test.go @@ -27,6 +27,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" + basics_testing "github.com/algorand/go-algorand/data/basics/testing" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/ledger/ledgercore" "github.com/algorand/go-algorand/ledger/store/trackerdb" @@ -2021,12 +2022,12 @@ func TestAcctOnline_ExpiredOnlineCirculation(t *testing.T) { stakeA := allAccts[0].MicroAlgos statesA := map[acctState]ledgercore.AccountData{ acctStateOffline: {AccountBaseData: ledgercore.AccountBaseData{Status: basics.Offline, MicroAlgos: stakeA}, VotingData: basics.VotingData{}}, - acctStateOnline: {AccountBaseData: ledgercore.AccountBaseData{Status: basics.Online, MicroAlgos: stakeA}, VotingData: basics.VotingData(allAccts[0].OnlineAccountData().VotingData)}, + acctStateOnline: {AccountBaseData: ledgercore.AccountBaseData{Status: basics.Online, MicroAlgos: stakeA}, VotingData: basics.VotingData(basics_testing.OnlineAccountData(allAccts[0].AccountData).VotingData)}, } addrB := allAccts[1].Addr stakeB := allAccts[1].MicroAlgos - votingDataB := allAccts[1].OnlineAccountData().VotingData + votingDataB := basics_testing.OnlineAccountData(allAccts[1].AccountData).VotingData statesB := map[acctState]ledgercore.AccountData{ acctStateOffline: {AccountBaseData: ledgercore.AccountBaseData{Status: basics.Offline, MicroAlgos: stakeB}, VotingData: basics.VotingData{}}, acctStateOnline: {AccountBaseData: ledgercore.AccountBaseData{Status: basics.Online, MicroAlgos: stakeB}, VotingData: basics.VotingData(votingDataB)}, diff --git a/ledger/eval/eval_test.go b/ledger/eval/eval_test.go index d375feeea3..b90530b1e3 100644 --- a/ledger/eval/eval_test.go +++ b/ledger/eval/eval_test.go @@ -797,7 +797,7 @@ func (ledger *evalTestLedger) GetKnockOfflineCandidates(rnd basics.Round, _ conf ret := make(map[basics.Address]basics.OnlineAccountData) for addr, data := range ledger.roundBalances[rnd] { if data.Status == basics.Online && !data.MicroAlgos.IsZero() { - ret[addr] = data.OnlineAccountData() + ret[addr] = basics_testing.OnlineAccountData(data) } } return ret, nil diff --git a/ledger/eval_simple_test.go b/ledger/eval_simple_test.go index 5bd11bd10a..b7817e4e36 100644 --- a/ledger/eval_simple_test.go +++ b/ledger/eval_simple_test.go @@ -32,6 +32,7 @@ import ( "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/crypto/merklesignature" "github.com/algorand/go-algorand/data/basics" + basics_testing "github.com/algorand/go-algorand/data/basics/testing" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/committee" "github.com/algorand/go-algorand/data/transactions" @@ -849,8 +850,8 @@ func TestDoubleLedgerGetKnockoffCandidates(t *testing.T) { for addr, ad := range genBalances.Balances { if ad.Status == basics.Online { onlineCnt++ - genesisOnlineAccts[addr] = ad.OnlineAccountData() - afterPayTxnOnlineAccts[addr] = ad.OnlineAccountData() + genesisOnlineAccts[addr] = basics_testing.OnlineAccountData(ad) + afterPayTxnOnlineAccts[addr] = basics_testing.OnlineAccountData(ad) } } diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index 8528ea5052..633fc4397d 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -37,6 +37,7 @@ import ( "github.com/algorand/go-algorand/crypto/stateproof" "github.com/algorand/go-algorand/data/account" "github.com/algorand/go-algorand/data/basics" + basics_testing "github.com/algorand/go-algorand/data/basics/testing" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/transactions" "github.com/algorand/go-algorand/data/transactions/logic" @@ -1973,7 +1974,7 @@ func TestLookupAgreement(t *testing.T) { ad, _, _, err := ledger.LookupLatest(addrOnline) require.NoError(t, err) require.NotEmpty(t, ad) - require.Equal(t, oad, ad.OnlineAccountData()) + require.Equal(t, oad, basics_testing.OnlineAccountData(ad)) require.NoError(t, err) oad, err = ledger.LookupAgreement(0, addrOffline) @@ -1982,7 +1983,7 @@ func TestLookupAgreement(t *testing.T) { ad, _, _, err = ledger.LookupLatest(addrOffline) require.NoError(t, err) require.NotEmpty(t, ad) - require.Equal(t, oad, ad.OnlineAccountData()) + require.Equal(t, oad, basics_testing.OnlineAccountData(ad)) } func TestGetKnockOfflineCandidates(t *testing.T) { @@ -2007,7 +2008,7 @@ func TestGetKnockOfflineCandidates(t *testing.T) { for addr, ad := range genesisInitState.Accounts { if ad.Status == basics.Online { onlineCnt++ - onlineAddrs[addr] = ad.OnlineAccountData() + onlineAddrs[addr] = basics_testing.OnlineAccountData(ad) } } require.Len(t, accts, onlineCnt)