From 2229778ce0a2102d5d17b2cef6cbe21db0316e28 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Sun, 18 Jun 2023 02:07:44 -0400 Subject: [PATCH] Use exp/slices and exp/maps to simplify some code The intent is to only make changes where the result is clearer, and to catch enough cases that the next time someone does something similar, they will have seen the new, clearer way to write the thing they intend. --- agreement/autopsy.go | 5 +- cmd/algokey/keyreg.go | 6 +- cmd/goal/account.go | 13 ++-- cmd/tealdbg/local.go | 4 +- crypto/merklearray/merkle.go | 3 +- crypto/merkletrie/cache.go | 11 ++-- crypto/merkletrie/committer.go | 6 +- crypto/merkletrie/committer_test.go | 5 +- crypto/merkletrie/node.go | 4 +- daemon/algod/api/server/v2/account.go | 4 +- .../algod/api/server/v2/test/handlers_test.go | 4 +- daemon/algod/api/server/v2/utils.go | 4 +- data/basics/teal.go | 10 +-- data/basics/userBalance.go | 7 +-- data/transactions/logic/eval.go | 14 ++--- data/transactions/logic/evalCrypto_test.go | 13 ++-- data/transactions/logic/opcodes.go | 7 +-- data/transactions/logic/opcodes_test.go | 13 +--- go.mod | 1 + go.sum | 2 + ledger/acctupdates.go | 3 +- ledger/apply/application_test.go | 16 +---- ledger/apply/asset_test.go | 13 +--- ledger/apply/mockBalances_test.go | 61 +++++++------------ ledger/eval/txntracer.go | 32 +++------- ledger/ledger_test.go | 4 +- ledger/ledgercore/statedelta.go | 12 ++-- network/phonebook.go | 4 +- stateproof/builder.go | 10 ++- test/reflectionhelpers/helpers.go | 6 +- tools/block-generator/go.mod | 1 + tools/block-generator/go.sum | 2 + util/metrics/tagcounter.go | 5 +- 33 files changed, 114 insertions(+), 191 deletions(-) diff --git a/agreement/autopsy.go b/agreement/autopsy.go index e940ae4bc9..30f41e13cb 100644 --- a/agreement/autopsy.go +++ b/agreement/autopsy.go @@ -24,6 +24,7 @@ import ( "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/logging" "github.com/algorand/go-algorand/protocol" + "golang.org/x/exp/slices" ) // An Autopsy is a trace of the ordered input events and output @@ -102,9 +103,7 @@ func (m *multiCloser) Close() error { // makeMultiCloser returns a Closer that closes all the given closers. func makeMultiCloser(closers ...io.Closer) io.Closer { - r := make([]io.Closer, len(closers)) - copy(r, closers) - return &multiCloser{r} + return &multiCloser{slices.Clone(closers)} } type autopsyTrace struct { diff --git a/cmd/algokey/keyreg.go b/cmd/algokey/keyreg.go index 02f18649bc..4393664420 100644 --- a/cmd/algokey/keyreg.go +++ b/cmd/algokey/keyreg.go @@ -24,6 +24,7 @@ import ( "strings" "github.com/spf13/cobra" + "golang.org/x/exp/maps" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/account" @@ -94,10 +95,7 @@ func init() { "betanet": mustConvertB64ToDigest("mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0="), "devnet": mustConvertB64ToDigest("sC3P7e2SdbqKJK0tbiCdK9tdSpbe6XeCGKdoNzmlj0E="), } - validNetworkList = make([]string, 0, len(validNetworks)) - for k := range validNetworks { - validNetworkList = append(validNetworkList, k) - } + validNetworkList = maps.Keys(validNetworks) } func mustConvertB64ToDigest(b64 string) (digest crypto.Digest) { diff --git a/cmd/goal/account.go b/cmd/goal/account.go index 1ca85e5677..77b6cc3c70 100644 --- a/cmd/goal/account.go +++ b/cmd/goal/account.go @@ -27,6 +27,7 @@ import ( "time" "github.com/spf13/cobra" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/cmd/util/datadir" "github.com/algorand/go-algorand/config" @@ -557,8 +558,7 @@ var infoCmd = &cobra.Command{ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bool, account model.Account) bool { var createdAssets []model.Asset if account.CreatedAssets != nil { - createdAssets = make([]model.Asset, len(*account.CreatedAssets)) - copy(createdAssets, *account.CreatedAssets) + createdAssets = slices.Clone(*account.CreatedAssets) sort.Slice(createdAssets, func(i, j int) bool { return createdAssets[i].Index < createdAssets[j].Index }) @@ -566,8 +566,7 @@ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bo var heldAssets []model.AssetHolding if account.Assets != nil { - heldAssets = make([]model.AssetHolding, len(*account.Assets)) - copy(heldAssets, *account.Assets) + heldAssets = slices.Clone(*account.Assets) sort.Slice(heldAssets, func(i, j int) bool { return heldAssets[i].AssetID < heldAssets[j].AssetID }) @@ -575,8 +574,7 @@ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bo var createdApps []model.Application if account.CreatedApps != nil { - createdApps = make([]model.Application, len(*account.CreatedApps)) - copy(createdApps, *account.CreatedApps) + createdApps = slices.Clone(*account.CreatedApps) sort.Slice(createdApps, func(i, j int) bool { return createdApps[i].Id < createdApps[j].Id }) @@ -584,8 +582,7 @@ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bo var optedInApps []model.ApplicationLocalState if account.AppsLocalState != nil { - optedInApps = make([]model.ApplicationLocalState, len(*account.AppsLocalState)) - copy(optedInApps, *account.AppsLocalState) + optedInApps = slices.Clone(*account.AppsLocalState) sort.Slice(optedInApps, func(i, j int) bool { return optedInApps[i].Id < optedInApps[j].Id }) diff --git a/cmd/tealdbg/local.go b/cmd/tealdbg/local.go index d8125362e2..d3a9e57fce 100644 --- a/cmd/tealdbg/local.go +++ b/cmd/tealdbg/local.go @@ -28,6 +28,7 @@ import ( "github.com/algorand/go-algorand/data/transactions/logic" "github.com/algorand/go-algorand/ledger/apply" "github.com/algorand/go-algorand/protocol" + "golang.org/x/exp/slices" ) func protoFromString(protoString string) (name string, proto config.ConsensusParams, err error) { @@ -190,8 +191,7 @@ func (a *AppState) clone() (b AppState) { b.locals[addr][aid] = tkv.Clone() } } - b.logs = make([]string, len(a.logs)) - copy(b.logs, a.logs) + b.logs = slices.Clone(a.logs) b.innerTxns = cloneInners(a.innerTxns) return } diff --git a/crypto/merklearray/merkle.go b/crypto/merklearray/merkle.go index b4591bf6b7..203d92110e 100644 --- a/crypto/merklearray/merkle.go +++ b/crypto/merklearray/merkle.go @@ -24,6 +24,7 @@ import ( "sort" "github.com/algorand/go-algorand/crypto" + "golang.org/x/exp/slices" ) const ( @@ -223,7 +224,7 @@ func (tree *Tree) Prove(idxs []uint64) (*Proof, error) { idxs = VcIdxs } - sort.Slice(idxs, func(i, j int) bool { return idxs[i] < idxs[j] }) + slices.Sort(idxs) return tree.createProof(idxs) } diff --git a/crypto/merkletrie/cache.go b/crypto/merkletrie/cache.go index 01648d73a6..453e51645e 100644 --- a/crypto/merkletrie/cache.go +++ b/crypto/merkletrie/cache.go @@ -21,7 +21,9 @@ import ( "encoding/binary" "errors" "fmt" - "sort" + + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) // storedNodeIdentifier is the "equivalent" of a node-ptr, but oriented around persisting the @@ -446,11 +448,8 @@ func (mtc *merkleTrieCache) reallocatePendingPages(stats *CommitStats) (pagesToC } // create a sorted list of created pages - sortedCreatedPages := make([]uint64, 0, len(createdPages)) - for page := range createdPages { - sortedCreatedPages = append(sortedCreatedPages, page) - } - sort.SliceStable(sortedCreatedPages, func(i, j int) bool { return sortedCreatedPages[i] < sortedCreatedPages[j] }) + sortedCreatedPages := maps.Keys(createdPages) + slices.Sort(sortedCreatedPages) mtc.reallocatedPages = make(map[uint64]map[storedNodeIdentifier]*node) diff --git a/crypto/merkletrie/committer.go b/crypto/merkletrie/committer.go index 5e5ae758ab..305ce1f663 100644 --- a/crypto/merkletrie/committer.go +++ b/crypto/merkletrie/committer.go @@ -16,6 +16,8 @@ package merkletrie +import "golang.org/x/exp/slices" + // Committer is the interface supporting serializing tries into persistent storage. type Committer interface { StorePage(page uint64, content []byte) error @@ -40,9 +42,7 @@ func (mc *InMemoryCommitter) StorePage(page uint64, content []byte) error { if content == nil { delete(mc.memStore, page) } else { - storedContent := make([]byte, len(content)) - copy(storedContent, content) - mc.memStore[page] = storedContent + mc.memStore[page] = slices.Clone(content) } return nil } diff --git a/crypto/merkletrie/committer_test.go b/crypto/merkletrie/committer_test.go index c8bfd71435..317261f727 100644 --- a/crypto/merkletrie/committer_test.go +++ b/crypto/merkletrie/committer_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/test/partitiontest" @@ -33,9 +34,7 @@ func (mc *InMemoryCommitter) Duplicate(flat bool) (out *InMemoryCommitter) { if flat { out.memStore[k] = v } else { - bytes := make([]byte, len(v)) - copy(bytes[:], v[:]) - out.memStore[k] = bytes + out.memStore[k] = slices.Clone(v) } } return diff --git a/crypto/merkletrie/node.go b/crypto/merkletrie/node.go index de765793dd..972ef0e1e9 100644 --- a/crypto/merkletrie/node.go +++ b/crypto/merkletrie/node.go @@ -23,6 +23,7 @@ import ( "unsafe" "github.com/algorand/go-algorand/crypto" + "golang.org/x/exp/slices" ) type childEntry struct { @@ -339,8 +340,7 @@ func deserializeNode(buf []byte) (n *node, s int) { if hashLength2 <= 0 { return nil, hashLength2 } - n.hash = make([]byte, hashLength) - copy(n.hash, buf[hashLength2:hashLength2+int(hashLength)]) + n.hash = slices.Clone(buf[hashLength2 : hashLength2+int(hashLength)]) s = hashLength2 + int(hashLength) isLeaf := (buf[s] == 0) s++ diff --git a/daemon/algod/api/server/v2/account.go b/daemon/algod/api/server/v2/account.go index 9c25021b9c..f5bf773028 100644 --- a/daemon/algod/api/server/v2/account.go +++ b/daemon/algod/api/server/v2/account.go @@ -26,6 +26,7 @@ import ( "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/model" "github.com/algorand/go-algorand/data/basics" + "golang.org/x/exp/slices" ) // AssetHolding converts between basics.AssetHolding and model.AssetHolding @@ -477,8 +478,7 @@ func AssetParamsToAsset(creator string, idx basics.AssetIndex, params *basics.As Reserve: addrOrNil(params.Reserve), } if params.MetadataHash != ([32]byte{}) { - metadataHash := make([]byte, len(params.MetadataHash)) - copy(metadataHash, params.MetadataHash[:]) + metadataHash := slices.Clone(params.MetadataHash[:]) assetParams.MetadataHash = &metadataHash } diff --git a/daemon/algod/api/server/v2/test/handlers_test.go b/daemon/algod/api/server/v2/test/handlers_test.go index e30169b4ad..b02e63bcb3 100644 --- a/daemon/algod/api/server/v2/test/handlers_test.go +++ b/daemon/algod/api/server/v2/test/handlers_test.go @@ -32,6 +32,7 @@ import ( "github.com/algorand/go-algorand/ledger/eval" "github.com/algorand/go-algorand/ledger/ledgercore" + "golang.org/x/exp/slices" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" @@ -1028,8 +1029,7 @@ int 1`, var expectedFailedAt *[]uint64 if len(scenario.FailedAt) != 0 { - clone := make([]uint64, len(scenario.FailedAt)) - copy(clone, scenario.FailedAt) + clone := slices.Clone(scenario.FailedAt) clone[0]++ expectedFailedAt = &clone } diff --git a/daemon/algod/api/server/v2/utils.go b/daemon/algod/api/server/v2/utils.go index 07f06221f5..77d40089c4 100644 --- a/daemon/algod/api/server/v2/utils.go +++ b/daemon/algod/api/server/v2/utils.go @@ -26,6 +26,7 @@ import ( "github.com/algorand/go-codec/codec" "github.com/labstack/echo/v4" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/model" "github.com/algorand/go-algorand/data/basics" @@ -431,8 +432,7 @@ func convertTxnGroupResult(txnGroupResult simulation.TxnGroupResult) PreEncodedS } if len(txnGroupResult.FailedAt) > 0 { - failedAt := make([]uint64, len(txnGroupResult.FailedAt)) - copy(failedAt, txnGroupResult.FailedAt) + failedAt := slices.Clone[[]uint64, uint64](txnGroupResult.FailedAt) encoded.FailedAt = &failedAt } diff --git a/data/basics/teal.go b/data/basics/teal.go index 0898c2883b..dcfb1d2e08 100644 --- a/data/basics/teal.go +++ b/data/basics/teal.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/algorand/go-algorand/config" + "golang.org/x/exp/maps" ) // DeltaAction is an enum of actions that may be performed when applying a @@ -234,14 +235,7 @@ type TealKeyValue map[string]TealValue // Clone returns a copy of a TealKeyValue that may be modified without // affecting the original func (tk TealKeyValue) Clone() TealKeyValue { - if tk == nil { - return nil - } - res := make(TealKeyValue, len(tk)) - for k, v := range tk { - res[k] = v - } - return res + return maps.Clone(tk) } // ToStateSchema calculates the number of each value type in a TealKeyValue and diff --git a/data/basics/userBalance.go b/data/basics/userBalance.go index 7ca18566b9..2d696c50d8 100644 --- a/data/basics/userBalance.go +++ b/data/basics/userBalance.go @@ -26,6 +26,7 @@ import ( "github.com/algorand/go-algorand/crypto/merklesignature" "github.com/algorand/go-algorand/logging" "github.com/algorand/go-algorand/protocol" + "golang.org/x/exp/slices" ) // Status is the delegation status of an account's MicroAlgos @@ -268,10 +269,8 @@ type StateSchemas struct { // affecting the original func (ap *AppParams) Clone() (res AppParams) { res = *ap - res.ApprovalProgram = make([]byte, len(ap.ApprovalProgram)) - copy(res.ApprovalProgram, ap.ApprovalProgram) - res.ClearStateProgram = make([]byte, len(ap.ClearStateProgram)) - copy(res.ClearStateProgram, ap.ClearStateProgram) + res.ApprovalProgram = slices.Clone(ap.ApprovalProgram) + res.ClearStateProgram = slices.Clone(ap.ClearStateProgram) res.GlobalState = ap.GlobalState.Clone() return } diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 6c6407b6fd..6feccae243 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -35,6 +35,7 @@ import ( "strings" "golang.org/x/crypto/sha3" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" @@ -5291,8 +5292,7 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t if len(sv.Bytes) > cx.Proto.MaxTxnNoteBytes { return fmt.Errorf("%s may not exceed %d bytes", fs.field, cx.Proto.MaxTxnNoteBytes) } - txn.Note = make([]byte, len(sv.Bytes)) - copy(txn.Note, sv.Bytes) + txn.Note = slices.Clone(sv.Bytes) // GenesisID, GenesisHash unsettable: surely makes no sense // Group unsettable: Can't make groups from AVM (yet?) // Lease unsettable: This seems potentially useful. @@ -5406,9 +5406,7 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t if len(txn.ApplicationArgs) >= cx.Proto.MaxAppArgs { return errors.New("too many application args") } - new := make([]byte, len(sv.Bytes)) - copy(new, sv.Bytes) - txn.ApplicationArgs = append(txn.ApplicationArgs, new) + txn.ApplicationArgs = append(txn.ApplicationArgs, slices.Clone(sv.Bytes)) case Accounts: var new basics.Address new, err = cx.assignAccount(sv) @@ -5424,15 +5422,13 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t if len(sv.Bytes) > maxPossible { return fmt.Errorf("%s may not exceed %d bytes", fs.field, maxPossible) } - txn.ApprovalProgram = make([]byte, len(sv.Bytes)) - copy(txn.ApprovalProgram, sv.Bytes) + txn.ApprovalProgram = slices.Clone(sv.Bytes) case ClearStateProgram: maxPossible := cx.Proto.MaxAppProgramLen * (1 + cx.Proto.MaxExtraAppProgramPages) if len(sv.Bytes) > maxPossible { return fmt.Errorf("%s may not exceed %d bytes", fs.field, maxPossible) } - txn.ClearStateProgram = make([]byte, len(sv.Bytes)) - copy(txn.ClearStateProgram, sv.Bytes) + txn.ClearStateProgram = slices.Clone(sv.Bytes) case ApprovalProgramPages: maxPossible := cx.Proto.MaxAppProgramLen * (1 + cx.Proto.MaxExtraAppProgramPages) txn.ApprovalProgram = append(txn.ApprovalProgram, sv.Bytes...) diff --git a/data/transactions/logic/evalCrypto_test.go b/data/transactions/logic/evalCrypto_test.go index 65f0787a97..766fe66baa 100644 --- a/data/transactions/logic/evalCrypto_test.go +++ b/data/transactions/logic/evalCrypto_test.go @@ -31,6 +31,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/crypto/secp256k1" @@ -331,8 +332,7 @@ load 0 byte 0x%s == &&` - pkTampered1 := make([]byte, len(pk)) - copy(pkTampered1, pk) + pkTampered1 := slices.Clone(pk) pkTampered1[0] = 0 // first byte is a prefix of either 0x02 or 0x03 pkTampered2 := make([]byte, len(pk)-1) // must be 33 bytes length copy(pkTampered2, pk) @@ -378,8 +378,7 @@ ecdsa_verify Secp256k1 s := sign[32:64] v := int(sign[64]) - rTampered := make([]byte, len(r)) - copy(rTampered, r) + rTampered := slices.Clone(r) rTampered[0] += byte(1) // intentional overflow var verifyTests = []struct { @@ -487,8 +486,7 @@ load 0 byte 0x%s == &&` - pkTampered1 := make([]byte, len(pk)) - copy(pkTampered1, pk) + pkTampered1 := slices.Clone(pk) pkTampered1[0] = 0 // first byte is a prefix of either 0x02 or 0x03 pkTampered2 := make([]byte, len(pk)-1) // must be 33 bytes length copy(pkTampered2, pk) @@ -533,8 +531,7 @@ ecdsa_verify Secp256r1 r := ri.Bytes() s := si.Bytes() - rTampered := make([]byte, len(r)) - copy(rTampered, r) + rTampered := slices.Clone(r) rTampered[0] += byte(1) // intentional overflow var verifyTests = []struct { diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 028ceecbdc..b0fd08e21a 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -21,6 +21,8 @@ import ( "sort" "strconv" "strings" + + "golang.org/x/exp/maps" ) // LogicVersion defines default assembler and max eval versions @@ -707,10 +709,7 @@ func OpcodesByVersion(version uint64) []OpSpec { } } } - result := make([]OpSpec, 0, len(subv)) - for _, v := range subv { - result = append(result, v) - } + result := maps.Values(subv) sort.Sort(sortByOpcode(result)) return result } diff --git a/data/transactions/logic/opcodes_test.go b/data/transactions/logic/opcodes_test.go index 2ce3648a69..df69bbf708 100644 --- a/data/transactions/logic/opcodes_test.go +++ b/data/transactions/logic/opcodes_test.go @@ -23,6 +23,7 @@ import ( "github.com/algorand/go-algorand/test/partitiontest" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" ) func TestOpSpecs(t *testing.T) { @@ -62,11 +63,7 @@ func TestOpcodesByVersionReordered(t *testing.T) { // nolint:paralleltest // man partitiontest.PartitionTest(t) // Make a copy to restore to the original - OpSpecsOrig := make([]OpSpec, len(OpSpecs)) - for idx, opspec := range OpSpecs { - cp := opspec - OpSpecsOrig[idx] = cp - } + OpSpecsOrig := slices.Clone(OpSpecs) defer func() { OpSpecs = OpSpecsOrig }() @@ -88,11 +85,7 @@ func TestOpcodesByVersion(t *testing.T) { func testOpcodesByVersion(t *testing.T) { // Make a copy of the OpSpecs to check if OpcodesByVersion will change it - OpSpecs2 := make([]OpSpec, len(OpSpecs)) - for idx, opspec := range OpSpecs { - cp := opspec - OpSpecs2[idx] = cp - } + OpSpecs2 := slices.Clone(OpSpecs) opSpecs := make([][]OpSpec, LogicVersion) for v := uint64(1); v <= LogicVersion; v++ { diff --git a/go.mod b/go.mod index a9988bef08..78a055cb73 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.8.1 golang.org/x/crypto v0.1.0 + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/sys v0.7.0 golang.org/x/text v0.9.0 gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 diff --git a/go.sum b/go.sum index d69bf76259..431bc7f092 100644 --- a/go.sum +++ b/go.sum @@ -482,6 +482,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/ledger/acctupdates.go b/ledger/acctupdates.go index 9c16e09279..ba9bca99af 100644 --- a/ledger/acctupdates.go +++ b/ledger/acctupdates.go @@ -27,6 +27,7 @@ import ( "time" "github.com/algorand/go-deadlock" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" @@ -614,7 +615,7 @@ func (au *accountUpdates) listCreatables(maxCreatableIdx basics.CreatableIndex, keys = append(keys, cidx) } } - sort.Slice(keys, func(i, j int) bool { return keys[i] > keys[j] }) + slices.Sort(keys) // Check for creatables that haven't been synced to disk yet. unsyncedCreatables := make([]basics.CreatableLocator, 0, len(keys)) diff --git a/ledger/apply/application_test.go b/ledger/apply/application_test.go index 37c132c135..2a935f7720 100644 --- a/ledger/apply/application_test.go +++ b/ledger/apply/application_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" @@ -37,22 +38,14 @@ import ( // call clone on each basics.AppParams -- callers must do that for any values where // they intend to modify a contained reference type. func cloneAppParams(m map[basics.AppIndex]basics.AppParams) map[basics.AppIndex]basics.AppParams { - res := make(map[basics.AppIndex]basics.AppParams, len(m)) - for k, v := range m { - res[k] = v - } - return res + return maps.Clone(m) } // Allocate the map of LocalStates if it is nil, and return a copy. We do *not* // call clone on each AppLocalState -- callers must do that for any values // where they intend to modify a contained reference type. func cloneAppLocalStates(m map[basics.AppIndex]basics.AppLocalState) map[basics.AppIndex]basics.AppLocalState { - res := make(map[basics.AppIndex]basics.AppLocalState, len(m)) - for k, v := range m { - res[k] = v - } - return res + return maps.Clone(m) } func TestApplicationCallFieldsEmpty(t *testing.T) { @@ -571,9 +564,6 @@ func TestAppCallApplyCreate(t *testing.T) { a.Zero(b.putAppParams) // ensure original balance record in the mock was not changed // this ensure proper cloning and any in-intended in-memory modifications - // - // known artefact of cloning AppLocalState even with empty update, nil map vs empty map - saved.AppLocalStates = map[basics.AppIndex]basics.AppLocalState{} a.Equal(saved, b.balances[creator]) saved = b.putBalances[creator] diff --git a/ledger/apply/asset_test.go b/ledger/apply/asset_test.go index 2b7908ac64..d13059ce4c 100644 --- a/ledger/apply/asset_test.go +++ b/ledger/apply/asset_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/data/basics" @@ -30,19 +31,11 @@ import ( ) func cloneAssetHoldings(m map[basics.AssetIndex]basics.AssetHolding) map[basics.AssetIndex]basics.AssetHolding { - res := make(map[basics.AssetIndex]basics.AssetHolding, len(m)) - for id, val := range m { - res[id] = val - } - return res + return maps.Clone(m) } func cloneAssetParams(m map[basics.AssetIndex]basics.AssetParams) map[basics.AssetIndex]basics.AssetParams { - res := make(map[basics.AssetIndex]basics.AssetParams, len(m)) - for id, val := range m { - res[id] = val - } - return res + return maps.Clone(m) } func TestAssetTransfer(t *testing.T) { diff --git a/ledger/apply/mockBalances_test.go b/ledger/apply/mockBalances_test.go index a9b8387159..48b5d6d8ac 100644 --- a/ledger/apply/mockBalances_test.go +++ b/ledger/apply/mockBalances_test.go @@ -23,6 +23,7 @@ import ( "github.com/algorand/go-algorand/data/transactions/logic" "github.com/algorand/go-algorand/ledger/ledgercore" "github.com/algorand/go-algorand/protocol" + "golang.org/x/exp/maps" ) type mockBalances struct { @@ -161,18 +162,25 @@ func (b *mockCreatableBalances) GetAssetParams(addr basics.Address, aidx basics. return } +// mapWith returns a new map with the given key and value added to it. Care must +// be taken for nil input maps, which maps.Clone would keep as nil. +func mapWith[M ~map[K]V, K comparable, V any](m M, k K, v V) M { + if m == nil { + m = make(M, len(m)+1) + } else { + m = maps.Clone(m) + } + m[k] = v + return m +} + func (b *mockCreatableBalances) PutAppParams(addr basics.Address, aidx basics.AppIndex, params basics.AppParams) error { b.putAppParams++ acct, err := b.access.getAccount(addr, false) if err != nil { return err } - m := make(map[basics.AppIndex]basics.AppParams, len(acct.AppParams)) - for k, v := range acct.AppParams { - m[k] = v - } - m[aidx] = params - acct.AppParams = m + acct.AppParams = mapWith(acct.AppParams, aidx, params) return b.access.putAccount(addr, acct) } func (b *mockCreatableBalances) PutAppLocalState(addr basics.Address, aidx basics.AppIndex, state basics.AppLocalState) error { @@ -181,12 +189,7 @@ func (b *mockCreatableBalances) PutAppLocalState(addr basics.Address, aidx basic if err != nil { return err } - m := make(map[basics.AppIndex]basics.AppLocalState, len(acct.AppLocalStates)) - for k, v := range acct.AppLocalStates { - m[k] = v - } - m[aidx] = state - acct.AppLocalStates = m + acct.AppLocalStates = mapWith(acct.AppLocalStates, aidx, state) return b.access.putAccount(addr, acct) } func (b *mockCreatableBalances) PutAssetHolding(addr basics.Address, aidx basics.AssetIndex, data basics.AssetHolding) error { @@ -195,12 +198,7 @@ func (b *mockCreatableBalances) PutAssetHolding(addr basics.Address, aidx basics if err != nil { return err } - m := make(map[basics.AssetIndex]basics.AssetHolding, len(acct.Assets)) - for k, v := range acct.Assets { - m[k] = v - } - m[aidx] = data - acct.Assets = m + acct.Assets = mapWith(acct.Assets, aidx, data) return b.access.putAccount(addr, acct) } func (b *mockCreatableBalances) PutAssetParams(addr basics.Address, aidx basics.AssetIndex, data basics.AssetParams) error { @@ -209,12 +207,7 @@ func (b *mockCreatableBalances) PutAssetParams(addr basics.Address, aidx basics. if err != nil { return err } - m := make(map[basics.AssetIndex]basics.AssetParams, len(acct.AssetParams)) - for k, v := range acct.AssetParams { - m[k] = v - } - m[aidx] = data - acct.AssetParams = m + acct.AssetParams = mapWith(acct.AssetParams, aidx, data) return b.access.putAccount(addr, acct) } @@ -224,10 +217,7 @@ func (b *mockCreatableBalances) DeleteAppParams(addr basics.Address, aidx basics if err != nil { return err } - m := make(map[basics.AppIndex]basics.AppParams, len(acct.AppParams)) - for k, v := range acct.AppParams { - m[k] = v - } + m := maps.Clone(acct.AppParams) delete(m, aidx) acct.AppParams = m return b.access.putAccount(addr, acct) @@ -238,10 +228,7 @@ func (b *mockCreatableBalances) DeleteAppLocalState(addr basics.Address, aidx ba if err != nil { return err } - m := make(map[basics.AppIndex]basics.AppLocalState, len(acct.AppLocalStates)) - for k, v := range acct.AppLocalStates { - m[k] = v - } + m := maps.Clone(acct.AppLocalStates) delete(m, aidx) acct.AppLocalStates = m return b.access.putAccount(addr, acct) @@ -252,10 +239,7 @@ func (b *mockCreatableBalances) DeleteAssetHolding(addr basics.Address, aidx bas if err != nil { return err } - m := make(map[basics.AssetIndex]basics.AssetHolding, len(acct.Assets)) - for k, v := range acct.Assets { - m[k] = v - } + m := maps.Clone(acct.Assets) delete(m, aidx) acct.Assets = m return b.access.putAccount(addr, acct) @@ -266,10 +250,7 @@ func (b *mockCreatableBalances) DeleteAssetParams(addr basics.Address, aidx basi if err != nil { return err } - m := make(map[basics.AssetIndex]basics.AssetParams, len(acct.AssetParams)) - for k, v := range acct.AssetParams { - m[k] = v - } + m := maps.Clone(acct.AssetParams) delete(m, aidx) acct.AssetParams = m return b.access.putAccount(addr, acct) diff --git a/ledger/eval/txntracer.go b/ledger/eval/txntracer.go index 036ad773de..f4c6277c71 100644 --- a/ledger/eval/txntracer.go +++ b/ledger/eval/txntracer.go @@ -20,6 +20,8 @@ import ( "fmt" "github.com/algorand/go-deadlock" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" @@ -51,36 +53,22 @@ func convertStateDelta(delta ledgercore.StateDelta) StateDeltaSubset { // The StateDelta object returned through the EvalTracer has its values deleted between txn groups to avoid // reallocation during evaluation. // This means the map values need to be copied (to avoid deletion) since they are all passed by reference. - kvmods := make(map[string]ledgercore.KvValueDelta, len(delta.KvMods)) - for k1, v1 := range delta.KvMods { - kvmods[k1] = v1 - } - txids := make(map[transactions.Txid]ledgercore.IncludedTransactions, len(delta.Txids)) - for k2, v2 := range delta.Txids { - txids[k2] = v2 - } - txleases := make(map[ledgercore.Txlease]basics.Round, len(delta.Txleases)) - for k3, v3 := range delta.Txleases { - txleases[k3] = v3 - } - creatables := make(map[basics.CreatableIndex]ledgercore.ModifiedCreatable, len(delta.Creatables)) - for k4, v4 := range delta.Creatables { - creatables[k4] = v4 - } + kvmods := maps.Clone(delta.KvMods) + txids := maps.Clone(delta.Txids) + txleases := maps.Clone(delta.Txleases) + creatables := maps.Clone(delta.Creatables) + var accR []ledgercore.BalanceRecord var appR []ledgercore.AppResourceRecord var assetR []ledgercore.AssetResourceRecord if len(delta.Accts.Accts) > 0 { - accR = make([]ledgercore.BalanceRecord, len(delta.Accts.Accts)) - copy(accR, delta.Accts.Accts) + accR = slices.Clone(delta.Accts.Accts) } if len(delta.Accts.AppResources) > 0 { - appR = make([]ledgercore.AppResourceRecord, len(delta.Accts.AppResources)) - copy(appR, delta.Accts.AppResources) + appR = slices.Clone(delta.Accts.AppResources) } if len(delta.Accts.AssetResources) > 0 { - assetR = make([]ledgercore.AssetResourceRecord, len(delta.Accts.AssetResources)) - copy(assetR, delta.Accts.AssetResources) + assetR = slices.Clone(delta.Accts.AssetResources) } return StateDeltaSubset{ Accts: ledgercore.AccountDeltas{ diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index 1fe51799c3..e71af91fd2 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -30,6 +30,7 @@ import ( "time" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" "github.com/algorand/go-algorand/agreement" "github.com/algorand/go-algorand/config" @@ -696,8 +697,7 @@ func TestLedgerSingleTxV24(t *testing.T) { appIdx = 2 // the second successful txn badTx = correctAppCreate - program := make([]byte, len(approvalProgram)) - copy(program, approvalProgram) + program := slices.Clone(approvalProgram) program[0] = '\x01' badTx.ApprovalProgram = program err = l.appendUnvalidatedTx(t, initAccounts, initSecrets, badTx, ad) diff --git a/ledger/ledgercore/statedelta.go b/ledger/ledgercore/statedelta.go index 7e9e25e0d0..d7284ade92 100644 --- a/ledger/ledgercore/statedelta.go +++ b/ledger/ledgercore/statedelta.go @@ -22,6 +22,8 @@ import ( "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/transactions" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) const ( @@ -572,20 +574,14 @@ func (sd *StateDelta) AddKvMod(key string, delta KvValueDelta) { func (sd *StateDelta) OptimizeAllocatedMemory(maxBalLookback uint64) { // Accts takes up 232 bytes per entry, and is saved for 320 rounds if uint64(cap(sd.Accts.Accts)-len(sd.Accts.Accts))*accountArrayEntrySize*maxBalLookback > stateDeltaTargetOptimizationThreshold { - accts := make([]BalanceRecord, len(sd.Accts.Accts)) - copy(accts, sd.Accts.Accts) - sd.Accts.Accts = accts + sd.Accts.Accts = slices.Clone(sd.Accts.Accts) } // acctsCache takes up 64 bytes per entry, and is saved for 320 rounds // realloc if original allocation capacity greater than length of data, and space difference is significant if 2*sd.initialHint > len(sd.Accts.acctsCache) && uint64(2*sd.initialHint-len(sd.Accts.acctsCache))*accountMapCacheEntrySize*maxBalLookback > stateDeltaTargetOptimizationThreshold { - acctsCache := make(map[basics.Address]int, len(sd.Accts.acctsCache)) - for k, v := range sd.Accts.acctsCache { - acctsCache[k] = v - } - sd.Accts.acctsCache = acctsCache + sd.Accts.acctsCache = maps.Clone(sd.Accts.acctsCache) } } diff --git a/network/phonebook.go b/network/phonebook.go index ac5914a299..ad07a2b5f5 100644 --- a/network/phonebook.go +++ b/network/phonebook.go @@ -22,6 +22,7 @@ import ( "time" "github.com/algorand/go-deadlock" + "golang.org/x/exp/slices" ) // when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless @@ -287,8 +288,7 @@ func shuffleStrings(set []string) { func shuffleSelect(set []string, n int) []string { if n >= len(set) || n == getAllAddresses { // return shuffled copy of everything - out := make([]string, len(set)) - copy(out, set) + out := slices.Clone(set) shuffleStrings(out) return out } diff --git a/stateproof/builder.go b/stateproof/builder.go index 7d90e8b731..13f4aa5b9b 100644 --- a/stateproof/builder.go +++ b/stateproof/builder.go @@ -22,7 +22,6 @@ import ( "encoding/binary" "errors" "fmt" - "sort" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto/stateproof" @@ -35,6 +34,8 @@ import ( "github.com/algorand/go-algorand/network" "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/stateproof/verify" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) var errVotersNotTracked = errors.New("voters not tracked for the given lookback round") @@ -641,11 +642,8 @@ func (spw *Worker) tryBroadcast() { spw.mu.Lock() defer spw.mu.Unlock() - sortedRounds := make([]basics.Round, 0, len(spw.provers)) - for rnd := range spw.provers { - sortedRounds = append(sortedRounds, rnd) - } - sort.Slice(sortedRounds, func(i, j int) bool { return sortedRounds[i] < sortedRounds[j] }) + sortedRounds := maps.Keys(spw.provers) + slices.Sort(sortedRounds) for _, rnd := range sortedRounds { // Iterate over the provers in a sequential manner. If the earlist state proof is not ready/rejected diff --git a/test/reflectionhelpers/helpers.go b/test/reflectionhelpers/helpers.go index 79c24d5e2e..f43b72c9b4 100644 --- a/test/reflectionhelpers/helpers.go +++ b/test/reflectionhelpers/helpers.go @@ -20,6 +20,8 @@ import ( "fmt" "reflect" "strings" + + "golang.org/x/exp/slices" ) // TypeSegmentKind is a enum for the types of TypeSegment @@ -61,9 +63,7 @@ type TypePath []TypeSegment // Clone creates a deep copy of a TypePath func (p TypePath) Clone() TypePath { - cloned := make(TypePath, len(p)) - copy(cloned, p) - return cloned + return slices.Clone(p) } // AddMapKey adds a map key segment to a TypePath. The modification is done using append, so this diff --git a/tools/block-generator/go.mod b/tools/block-generator/go.mod index 4af3d6683d..d0e1fc2b3f 100644 --- a/tools/block-generator/go.mod +++ b/tools/block-generator/go.mod @@ -45,6 +45,7 @@ require ( github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/crypto v0.1.0 // indirect + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 // indirect diff --git a/tools/block-generator/go.sum b/tools/block-generator/go.sum index 95bdafc558..f7ba8ae15e 100644 --- a/tools/block-generator/go.sum +++ b/tools/block-generator/go.sum @@ -85,6 +85,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= diff --git a/util/metrics/tagcounter.go b/util/metrics/tagcounter.go index 1daf30ba13..ff3b8a732b 100644 --- a/util/metrics/tagcounter.go +++ b/util/metrics/tagcounter.go @@ -22,6 +22,7 @@ import ( "sync/atomic" "github.com/algorand/go-deadlock" + "golang.org/x/exp/maps" ) // NewTagCounterFiltered makes a set of metrics under rootName for tagged counting. @@ -98,9 +99,7 @@ func (tc *TagCounter) Add(tag string, val uint64) { // Still need to add a new tag. // Make a new map so there's never any race. newtags := make(map[string]*uint64, len(tc.tags)+1) - for k, v := range tc.tags { - newtags[k] = v - } + maps.Copy(newtags, tc.tags) var st []uint64 if len(tc.storage) > 0 { st = tc.storage[len(tc.storage)-1]