summaryrefslogtreecommitdiff
path: root/ledger/testing/randomAccounts.go
diff options
context:
space:
mode:
Diffstat (limited to 'ledger/testing/randomAccounts.go')
-rw-r--r--ledger/testing/randomAccounts.go344
1 files changed, 344 insertions, 0 deletions
diff --git a/ledger/testing/randomAccounts.go b/ledger/testing/randomAccounts.go
new file mode 100644
index 000000000..86ec6a60c
--- /dev/null
+++ b/ledger/testing/randomAccounts.go
@@ -0,0 +1,344 @@
+// Copyright (C) 2019-2021 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 <https://www.gnu.org/licenses/>.
+
+package testing
+
+import (
+ "fmt"
+
+ "github.com/algorand/go-algorand/config"
+ "github.com/algorand/go-algorand/crypto"
+ "github.com/algorand/go-algorand/data/basics"
+ "github.com/algorand/go-algorand/protocol"
+ //"github.com/algorand/go-algorand/data/bookkeeping"
+
+ "github.com/algorand/go-algorand/ledger/ledgercore"
+)
+
+var testPoolAddr = basics.Address{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+var testSinkAddr = basics.Address{0x2c, 0x2a, 0x6c, 0xe9, 0xa9, 0xa7, 0xc2, 0x8c, 0x22, 0x95, 0xfd, 0x32, 0x4f, 0x77, 0xa5, 0x4, 0x8b, 0x42, 0xc2, 0xb7, 0xa8, 0x54, 0x84, 0xb6, 0x80, 0xb1, 0xe1, 0x3d, 0x59, 0x9b, 0xeb, 0x36}
+
+// RandomAddress generates a random address
+func RandomAddress() basics.Address {
+ var addr basics.Address
+ crypto.RandBytes(addr[:])
+ return addr
+}
+
+// RandomNote generates a random notes data
+func RandomNote() []byte {
+ var note [16]byte
+ crypto.RandBytes(note[:])
+ return note[:]
+}
+
+// RandomAccountData generates a random AccountData
+func RandomAccountData(rewardsLevel uint64) basics.AccountData {
+ var data basics.AccountData
+
+ // Avoid overflowing totals
+ data.MicroAlgos.Raw = crypto.RandUint64() % (1 << 32)
+
+ switch crypto.RandUint64() % 3 {
+ case 0:
+ data.Status = basics.Online
+ case 1:
+ data.Status = basics.Offline
+ default:
+ data.Status = basics.NotParticipating
+ }
+
+ data.RewardsBase = rewardsLevel
+ data.VoteFirstValid = 0
+ data.VoteLastValid = 1000
+ return data
+}
+
+// RandomFullAccountData generates a random AccountData
+func RandomFullAccountData(rewardsLevel, lastCreatableID uint64) (basics.AccountData, uint64) {
+ data := RandomAccountData(rewardsLevel)
+
+ crypto.RandBytes(data.VoteID[:])
+ crypto.RandBytes(data.SelectionID[:])
+ data.VoteFirstValid = basics.Round(crypto.RandUint64())
+ data.VoteLastValid = basics.Round(crypto.RandUint64())
+ data.VoteKeyDilution = crypto.RandUint64()
+ if 1 == (crypto.RandUint64() % 2) {
+ // if account has created assets, have these defined.
+ data.AssetParams = make(map[basics.AssetIndex]basics.AssetParams)
+ createdAssetsCount := crypto.RandUint64()%20 + 1
+ for i := uint64(0); i < createdAssetsCount; i++ {
+ ap := basics.AssetParams{
+ Total: crypto.RandUint64(),
+ Decimals: uint32(crypto.RandUint64() % 20),
+ DefaultFrozen: (crypto.RandUint64()%2 == 0),
+ UnitName: fmt.Sprintf("un%x", uint32(crypto.RandUint64()%0x7fffffff)),
+ AssetName: fmt.Sprintf("an%x", uint32(crypto.RandUint64()%0x7fffffff)),
+ URL: fmt.Sprintf("url%x", uint32(crypto.RandUint64()%0x7fffffff)),
+ }
+ crypto.RandBytes(ap.MetadataHash[:])
+ crypto.RandBytes(ap.Manager[:])
+ crypto.RandBytes(ap.Reserve[:])
+ crypto.RandBytes(ap.Freeze[:])
+ crypto.RandBytes(ap.Clawback[:])
+ lastCreatableID++
+ data.AssetParams[basics.AssetIndex(lastCreatableID)] = ap
+ }
+ }
+ if 1 == (crypto.RandUint64()%2) && lastCreatableID > 0 {
+ // if account owns assets
+ data.Assets = make(map[basics.AssetIndex]basics.AssetHolding)
+ ownedAssetsCount := crypto.RandUint64()%20 + 1
+ for i := uint64(0); i < ownedAssetsCount; i++ {
+ ah := basics.AssetHolding{
+ Amount: crypto.RandUint64(),
+ Frozen: (crypto.RandUint64()%2 == 0),
+ }
+ data.Assets[basics.AssetIndex(crypto.RandUint64()%lastCreatableID)] = ah
+ }
+ }
+ if 1 == (crypto.RandUint64() % 5) {
+ crypto.RandBytes(data.AuthAddr[:])
+ }
+
+ if 1 == (crypto.RandUint64()%3) && lastCreatableID > 0 {
+ data.AppLocalStates = make(map[basics.AppIndex]basics.AppLocalState)
+ appStatesCount := crypto.RandUint64()%20 + 1
+ for i := uint64(0); i < appStatesCount; i++ {
+ ap := basics.AppLocalState{
+ Schema: basics.StateSchema{
+ NumUint: crypto.RandUint64()%5 + 1,
+ NumByteSlice: crypto.RandUint64() % 5,
+ },
+ KeyValue: make(map[string]basics.TealValue),
+ }
+
+ for i := uint64(0); i < ap.Schema.NumUint; i++ {
+ appName := fmt.Sprintf("lapp%x-%x", crypto.RandUint64(), i)
+ ap.KeyValue[appName] = basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: crypto.RandUint64(),
+ }
+ }
+ for i := uint64(0); i < ap.Schema.NumByteSlice; i++ {
+ appName := fmt.Sprintf("lapp%x-%x", crypto.RandUint64(), i)
+ tv := basics.TealValue{
+ Type: basics.TealBytesType,
+ }
+ bytes := make([]byte, crypto.RandUint64()%uint64(config.MaxBytesKeyValueLen-len(appName)))
+ crypto.RandBytes(bytes[:])
+ tv.Bytes = string(bytes)
+ ap.KeyValue[appName] = tv
+ }
+ if len(ap.KeyValue) == 0 {
+ ap.KeyValue = nil
+ }
+ data.AppLocalStates[basics.AppIndex(crypto.RandUint64()%lastCreatableID)] = ap
+ }
+ }
+
+ if 1 == (crypto.RandUint64() % 3) {
+ data.TotalAppSchema = basics.StateSchema{
+ NumUint: crypto.RandUint64() % 50,
+ NumByteSlice: crypto.RandUint64() % 50,
+ }
+ }
+ if 1 == (crypto.RandUint64() % 3) {
+ data.AppParams = make(map[basics.AppIndex]basics.AppParams)
+ appParamsCount := crypto.RandUint64()%5 + 1
+ for i := uint64(0); i < appParamsCount; i++ {
+ ap := basics.AppParams{
+ ApprovalProgram: make([]byte, int(crypto.RandUint63())%config.MaxAppProgramLen),
+ ClearStateProgram: make([]byte, int(crypto.RandUint63())%config.MaxAppProgramLen),
+ GlobalState: make(basics.TealKeyValue),
+ StateSchemas: basics.StateSchemas{
+ LocalStateSchema: basics.StateSchema{
+ NumUint: crypto.RandUint64()%5 + 1,
+ NumByteSlice: crypto.RandUint64() % 5,
+ },
+ GlobalStateSchema: basics.StateSchema{
+ NumUint: crypto.RandUint64()%5 + 1,
+ NumByteSlice: crypto.RandUint64() % 5,
+ },
+ },
+ }
+ if len(ap.ApprovalProgram) > 0 {
+ crypto.RandBytes(ap.ApprovalProgram[:])
+ } else {
+ ap.ApprovalProgram = nil
+ }
+ if len(ap.ClearStateProgram) > 0 {
+ crypto.RandBytes(ap.ClearStateProgram[:])
+ } else {
+ ap.ClearStateProgram = nil
+ }
+
+ for i := uint64(0); i < ap.StateSchemas.LocalStateSchema.NumUint+ap.StateSchemas.GlobalStateSchema.NumUint; i++ {
+ appName := fmt.Sprintf("tapp%x-%x", crypto.RandUint64(), i)
+ ap.GlobalState[appName] = basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: crypto.RandUint64(),
+ }
+ }
+ for i := uint64(0); i < ap.StateSchemas.LocalStateSchema.NumByteSlice+ap.StateSchemas.GlobalStateSchema.NumByteSlice; i++ {
+ appName := fmt.Sprintf("tapp%x-%x", crypto.RandUint64(), i)
+ tv := basics.TealValue{
+ Type: basics.TealBytesType,
+ }
+ bytes := make([]byte, crypto.RandUint64()%uint64(config.MaxBytesKeyValueLen))
+ crypto.RandBytes(bytes[:])
+ tv.Bytes = string(bytes)
+ ap.GlobalState[appName] = tv
+ }
+ if len(ap.GlobalState) == 0 {
+ ap.GlobalState = nil
+ }
+ lastCreatableID++
+ data.AppParams[basics.AppIndex(lastCreatableID)] = ap
+ }
+
+ }
+ return data, lastCreatableID
+}
+
+// RandomAccounts generates a random set of accounts map
+func RandomAccounts(niter int, simpleAccounts bool) map[basics.Address]basics.AccountData {
+ res := make(map[basics.Address]basics.AccountData)
+ if simpleAccounts {
+ for i := 0; i < niter; i++ {
+ res[RandomAddress()] = RandomAccountData(0)
+ }
+ } else {
+ lastCreatableID := crypto.RandUint64() % 512
+ for i := 0; i < niter; i++ {
+ res[RandomAddress()], lastCreatableID = RandomFullAccountData(0, lastCreatableID)
+ }
+ }
+ return res
+}
+
+// RandomDeltas generates a random set of accounts delta
+func RandomDeltas(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, imbalance int64) {
+ updates, totals, imbalance, _ = RandomDeltasImpl(niter, base, rewardsLevel, true, 0)
+ return
+}
+
+// RandomDeltasFull generates a random set of accounts delta
+func RandomDeltasFull(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, imbalance int64, lastCreatableID uint64) {
+ updates, totals, imbalance, lastCreatableID = RandomDeltasImpl(niter, base, rewardsLevel, false, lastCreatableIDIn)
+ return
+}
+
+// RandomDeltasImpl generates a random set of accounts delta
+func RandomDeltasImpl(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, simple bool, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, imbalance int64, lastCreatableID uint64) {
+ proto := config.Consensus[protocol.ConsensusCurrentVersion]
+ totals = make(map[basics.Address]basics.AccountData)
+
+ // copy base -> totals
+ for addr, data := range base {
+ totals[addr] = data
+ }
+
+ // if making a full delta then need to determine max asset/app id to get rid of conflicts
+ lastCreatableID = lastCreatableIDIn
+ if !simple {
+ for _, ad := range base {
+ for aid := range ad.AssetParams {
+ if uint64(aid) > lastCreatableID {
+ lastCreatableID = uint64(aid)
+ }
+ }
+ for aid := range ad.AppParams {
+ if uint64(aid) > lastCreatableID {
+ lastCreatableID = uint64(aid)
+ }
+ }
+ }
+ }
+
+ // Change some existing accounts
+ {
+ i := 0
+ for addr, old := range base {
+ if i >= len(base)/2 || i >= niter {
+ break
+ }
+
+ if addr == testPoolAddr {
+ continue
+ }
+ i++
+
+ var new basics.AccountData
+ if simple {
+ new = RandomAccountData(rewardsLevel)
+ } else {
+ new, lastCreatableID = RandomFullAccountData(rewardsLevel, lastCreatableID)
+ }
+ updates.Upsert(addr, new)
+ imbalance += int64(old.WithUpdatedRewards(proto, rewardsLevel).MicroAlgos.Raw - new.MicroAlgos.Raw)
+ totals[addr] = new
+ }
+ }
+
+ // Change some new accounts
+ for i := 0; i < niter; i++ {
+ addr := RandomAddress()
+ old := totals[addr]
+ var new basics.AccountData
+ if simple {
+ new = RandomAccountData(rewardsLevel)
+ } else {
+ new, lastCreatableID = RandomFullAccountData(rewardsLevel, lastCreatableID)
+ }
+ updates.Upsert(addr, new)
+ imbalance += int64(old.WithUpdatedRewards(proto, rewardsLevel).MicroAlgos.Raw - new.MicroAlgos.Raw)
+ totals[addr] = new
+ }
+
+ return
+}
+
+// RandomDeltasBalanced generates a random set of accounts delta
+func RandomDeltasBalanced(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData) {
+ updates, totals, _ = RandomDeltasBalancedImpl(niter, base, rewardsLevel, true, 0)
+ return
+}
+
+// RandomDeltasBalancedFull generates a random set of accounts delta
+func RandomDeltasBalancedFull(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, lastCreatableID uint64) {
+ updates, totals, lastCreatableID = RandomDeltasBalancedImpl(niter, base, rewardsLevel, false, lastCreatableIDIn)
+ return
+}
+
+// RandomDeltasBalancedImpl generates a random set of accounts delta
+func RandomDeltasBalancedImpl(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, simple bool, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, lastCreatableID uint64) {
+ var imbalance int64
+ if simple {
+ updates, totals, imbalance = RandomDeltas(niter, base, rewardsLevel)
+ } else {
+ updates, totals, imbalance, lastCreatableID = RandomDeltasFull(niter, base, rewardsLevel, lastCreatableIDIn)
+ }
+
+ oldPool := base[testPoolAddr]
+ newPool := oldPool
+ newPool.MicroAlgos.Raw += uint64(imbalance)
+
+ updates.Upsert(testPoolAddr, newPool)
+ totals[testPoolAddr] = newPool
+
+ return updates, totals, lastCreatableID
+}