*: use slices.Clone instead of make/copy

It's much easier this way.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2024-08-24 00:07:41 +03:00
parent 7243754a0d
commit 9e112fc024
23 changed files with 82 additions and 114 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"slices"
"syscall" "syscall"
"time" "time"
@ -36,10 +37,9 @@ import (
func NewCommands() []*cli.Command { func NewCommands() []*cli.Command {
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath} cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags = append(cfgFlags, options.Network...) cfgFlags = append(cfgFlags, options.Network...)
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
copy(cfgWithCountFlags, cfgFlags)
cfgFlags = append(cfgFlags, options.Debug)
var cfgWithCountFlags = slices.Clone(cfgFlags)
cfgFlags = append(cfgFlags, options.Debug)
cfgWithCountFlags = append(cfgWithCountFlags, cfgWithCountFlags = append(cfgWithCountFlags,
&cli.UintFlag{ &cli.UintFlag{
Name: "count", Name: "count",
@ -47,8 +47,7 @@ func NewCommands() []*cli.Command {
Usage: "Number of blocks to be processed (default or 0: all chain)", Usage: "Number of blocks to be processed (default or 0: all chain)",
}, },
) )
var cfgCountOutFlags = make([]cli.Flag, len(cfgWithCountFlags)) var cfgCountOutFlags = slices.Clone(cfgWithCountFlags)
copy(cfgCountOutFlags, cfgWithCountFlags)
cfgCountOutFlags = append(cfgCountOutFlags, cfgCountOutFlags = append(cfgCountOutFlags,
&cli.UintFlag{ &cli.UintFlag{
Name: "start", Name: "start",
@ -61,8 +60,7 @@ func NewCommands() []*cli.Command {
Usage: "Output file (stdout if not given)", Usage: "Output file (stdout if not given)",
}, },
) )
var cfgCountInFlags = make([]cli.Flag, len(cfgWithCountFlags)) var cfgCountInFlags = slices.Clone(cfgWithCountFlags)
copy(cfgCountInFlags, cfgWithCountFlags)
cfgCountInFlags = append(cfgCountInFlags, cfgCountInFlags = append(cfgCountInFlags,
&cli.StringFlag{ &cli.StringFlag{
Name: "in", Name: "in",
@ -79,13 +77,12 @@ func NewCommands() []*cli.Command {
Usage: "Use if dump is incremental", Usage: "Use if dump is incremental",
}, },
) )
var cfgHeightFlags = make([]cli.Flag, len(cfgFlags)+1) var cfgHeightFlags = slices.Clone(cfgFlags)
copy(cfgHeightFlags, cfgFlags) cfgHeightFlags = append(cfgHeightFlags, &cli.UintFlag{
cfgHeightFlags[len(cfgHeightFlags)-1] = &cli.UintFlag{
Name: "height", Name: "height",
Usage: "Height of the state to reset DB to", Usage: "Height of the state to reset DB to",
Required: true, Required: true,
} })
return []*cli.Command{ return []*cli.Command{
{ {
Name: "node", Name: "node",

View file

@ -4,6 +4,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"slices"
"strconv" "strconv"
"github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/cmdargs"
@ -39,12 +40,11 @@ func newNEP11Commands() []*cli.Command {
Usage: "Hex-encoded token ID", Usage: "Hex-encoded token ID",
} }
balanceFlags := make([]cli.Flag, len(baseBalanceFlags)) balanceFlags := slices.Clone(baseBalanceFlags)
copy(balanceFlags, baseBalanceFlags)
balanceFlags = append(balanceFlags, tokenID) balanceFlags = append(balanceFlags, tokenID)
balanceFlags = append(balanceFlags, options.RPC...) balanceFlags = append(balanceFlags, options.RPC...)
transferFlags := make([]cli.Flag, len(baseTransferFlags))
copy(transferFlags, baseTransferFlags) transferFlags := slices.Clone(baseTransferFlags)
transferFlags = append(transferFlags, tokenID) transferFlags = append(transferFlags, tokenID)
transferFlags = append(transferFlags, options.RPC...) transferFlags = append(transferFlags, options.RPC...)
return []*cli.Command{ return []*cli.Command{

View file

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"slices"
"strings" "strings"
"github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/cmdargs"
@ -91,11 +92,10 @@ var (
) )
func newNEP17Commands() []*cli.Command { func newNEP17Commands() []*cli.Command {
balanceFlags := make([]cli.Flag, len(baseBalanceFlags)) balanceFlags := slices.Clone(baseBalanceFlags)
copy(balanceFlags, baseBalanceFlags)
balanceFlags = append(balanceFlags, options.RPC...) balanceFlags = append(balanceFlags, options.RPC...)
transferFlags := make([]cli.Flag, len(baseTransferFlags))
copy(transferFlags, baseTransferFlags) transferFlags := slices.Clone(baseTransferFlags)
transferFlags = append(transferFlags, options.RPC...) transferFlags = append(transferFlags, options.RPC...)
return []*cli.Command{ return []*cli.Command{
{ {

View file

@ -5,6 +5,7 @@ import (
"go/ast" "go/ast"
"go/constant" "go/constant"
"go/types" "go/types"
"slices"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding" "github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
@ -56,8 +57,7 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
// while stored in the new. // while stored in the new.
oldScope := c.scope.vars.locals oldScope := c.scope.vars.locals
c.scope.vars.newScope() c.scope.vars.newScope()
newScope := make([]map[string]varInfo, len(c.scope.vars.locals)) newScope := slices.Clone(c.scope.vars.locals)
copy(newScope, c.scope.vars.locals)
defer c.scope.vars.dropScope() defer c.scope.vars.dropScope()
if f.decl.Recv != nil { if f.decl.Recv != nil {

View file

@ -2,6 +2,7 @@ package config
import ( import (
"fmt" "fmt"
"slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -38,10 +39,8 @@ func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration
if len(a.P2P.Addresses) != len(o.P2P.Addresses) { if len(a.P2P.Addresses) != len(o.P2P.Addresses) {
return false return false
} }
aCp := make([]string, len(a.P2P.Addresses)) aCp := slices.Clone(a.P2P.Addresses)
oCp := make([]string, len(o.P2P.Addresses)) oCp := slices.Clone(o.P2P.Addresses)
copy(aCp, a.P2P.Addresses)
copy(oCp, o.P2P.Addresses)
sort.Strings(aCp) sort.Strings(aCp)
sort.Strings(oCp) sort.Strings(oCp)
for i := range aCp { for i := range aCp {

View file

@ -3,6 +3,7 @@ package consensus
import ( import (
"errors" "errors"
"fmt" "fmt"
"slices"
"sort" "sort"
"sync/atomic" "sync/atomic"
"time" "time"
@ -788,9 +789,7 @@ func (s *service) newBlockFromContext(ctx *dbft.Context[util.Uint256]) dbft.Bloc
block.Block.PrimaryIndex = primaryIndex block.Block.PrimaryIndex = primaryIndex
// it's OK to have ctx.TransactionsHashes == nil here // it's OK to have ctx.TransactionsHashes == nil here
hashes := make([]util.Uint256, len(ctx.TransactionHashes)) block.Block.MerkleRoot = hash.CalcMerkleRoot(slices.Clone(ctx.TransactionHashes))
copy(hashes, ctx.TransactionHashes)
block.Block.MerkleRoot = hash.CalcMerkleRoot(hashes)
return block return block
} }

View file

@ -6,7 +6,9 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"maps"
"math/big" "math/big"
"slices"
"sort" "sort"
"strings" "strings"
@ -150,13 +152,8 @@ func copyNeoCache(src, dst *NeoCache) {
// Can't omit copying because gasPerBlock is append-only, thus to be able to // Can't omit copying because gasPerBlock is append-only, thus to be able to
// discard cache changes in case of FAULTed transaction we need a separate // discard cache changes in case of FAULTed transaction we need a separate
// container for updated gasPerBlock values. // container for updated gasPerBlock values.
dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock)) dst.gasPerBlock = slices.Clone(src.gasPerBlock)
copy(dst.gasPerBlock, src.gasPerBlock) dst.gasPerVoteCache = maps.Clone(src.gasPerVoteCache)
dst.gasPerVoteCache = make(map[string]big.Int)
for k, v := range src.gasPerVoteCache {
dst.gasPerVoteCache[k] = v
}
} }
// makeValidatorKey creates a key from the account script hash. // makeValidatorKey creates a key from the account script hash.
@ -376,8 +373,7 @@ func (n *NEO) InitializeCache(blockHeight uint32, d *dao.Simple) error {
// nextValidators, committee and committee hash are filled in by this moment // nextValidators, committee and committee hash are filled in by this moment
// via n.updateCache call. // via n.updateCache call.
cache.newEpochNextValidators = cache.nextValidators.Copy() cache.newEpochNextValidators = cache.nextValidators.Copy()
cache.newEpochCommittee = make(keysWithVotes, len(cache.committee)) cache.newEpochCommittee = slices.Clone(cache.committee)
copy(cache.newEpochCommittee, cache.committee)
cache.newEpochCommitteeHash = cache.committeeHash cache.newEpochCommitteeHash = cache.committeeHash
} }

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"slices"
"testing" "testing"
ojson "github.com/nspcc-dev/go-ordered-json" ojson "github.com/nspcc-dev/go-ordered-json"
@ -423,8 +424,7 @@ func TestManagement_ContractDeploy(t *testing.T) {
}) })
t.Run("bad methods in manifest 1", func(t *testing.T) { t.Run("bad methods in manifest 1", func(t *testing.T) {
badManifest := cs1.Manifest badManifest := cs1.Manifest
badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods)
copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
badManifest.ABI.Methods[0].Offset = 100500 // out of bounds badManifest.ABI.Methods[0].Offset = 100500 // out of bounds
manifB, err := json.Marshal(&badManifest) manifB, err := json.Marshal(&badManifest)
require.NoError(t, err) require.NoError(t, err)
@ -433,8 +433,7 @@ func TestManagement_ContractDeploy(t *testing.T) {
}) })
t.Run("bad methods in manifest 2", func(t *testing.T) { t.Run("bad methods in manifest 2", func(t *testing.T) {
var badManifest = cs1.Manifest var badManifest = cs1.Manifest
badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods)
copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
badManifest.ABI.Methods[0].Offset = len(cs1.NEF.Script) - 2 // Ends with `CALLT(X,X);RET`. badManifest.ABI.Methods[0].Offset = len(cs1.NEF.Script) - 2 // Ends with `CALLT(X,X);RET`.
manifB, err := json.Marshal(badManifest) manifB, err := json.Marshal(badManifest)
@ -444,8 +443,7 @@ func TestManagement_ContractDeploy(t *testing.T) {
}) })
t.Run("duplicated methods in manifest 1", func(t *testing.T) { t.Run("duplicated methods in manifest 1", func(t *testing.T) {
badManifest := cs1.Manifest badManifest := cs1.Manifest
badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods)
copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
badManifest.ABI.Methods[0] = badManifest.ABI.Methods[1] // duplicates badManifest.ABI.Methods[0] = badManifest.ABI.Methods[1] // duplicates
manifB, err := json.Marshal(&badManifest) manifB, err := json.Marshal(&badManifest)
require.NoError(t, err) require.NoError(t, err)
@ -454,8 +452,7 @@ func TestManagement_ContractDeploy(t *testing.T) {
}) })
t.Run("duplicated events in manifest 1", func(t *testing.T) { t.Run("duplicated events in manifest 1", func(t *testing.T) {
badManifest := cs1.Manifest badManifest := cs1.Manifest
badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods)
copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
badManifest.ABI.Events = []manifest.Event{{Name: "event"}, {Name: "event"}} // duplicates badManifest.ABI.Events = []manifest.Event{{Name: "event"}, {Name: "event"}} // duplicates
manifB, err := json.Marshal(&badManifest) manifB, err := json.Marshal(&badManifest)
require.NoError(t, err) require.NoError(t, err)

View file

@ -3,7 +3,9 @@ package native
import ( import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"maps"
"math/big" "math/big"
"slices"
"sort" "sort"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
@ -91,12 +93,8 @@ func (c *PolicyCache) Copy() dao.NativeContractCache {
func copyPolicyCache(src, dst *PolicyCache) { func copyPolicyCache(src, dst *PolicyCache) {
*dst = *src *dst = *src
dst.attributeFee = make(map[transaction.AttrType]uint32, len(src.attributeFee)) dst.attributeFee = maps.Clone(src.attributeFee)
for t, v := range src.attributeFee { dst.blockedAccounts = slices.Clone(src.blockedAccounts)
dst.attributeFee[t] = v
}
dst.blockedAccounts = make([]util.Uint160, len(src.blockedAccounts))
copy(dst.blockedAccounts, src.blockedAccounts)
} }
// newPolicy returns Policy native contract. // newPolicy returns Policy native contract.

View file

@ -2,6 +2,7 @@ package statesync
import ( import (
"bytes" "bytes"
"slices"
"sort" "sort"
"sync" "sync"
@ -38,9 +39,7 @@ func (mp *Pool) TryGet(hash util.Uint256) ([][]byte, bool) {
paths, ok := mp.hashes[hash] paths, ok := mp.hashes[hash]
// need to copy here, because we can modify existing array of paths inside the pool. // need to copy here, because we can modify existing array of paths inside the pool.
res := make([][]byte, len(paths)) return slices.Clone(paths), ok
copy(res, paths)
return res, ok
} }
// GetAll returns all MPT nodes with the corresponding paths from the pool. // GetAll returns all MPT nodes with the corresponding paths from the pool.

View file

@ -3,6 +3,7 @@ package transaction
import ( import (
"errors" "errors"
"math/big" "math/big"
"slices"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
@ -93,10 +94,7 @@ func (c *Signer) Copy() *Signer {
return nil return nil
} }
cp := *c cp := *c
if c.AllowedContracts != nil { cp.AllowedContracts = slices.Clone(c.AllowedContracts)
cp.AllowedContracts = make([]util.Uint160, len(c.AllowedContracts))
copy(cp.AllowedContracts, c.AllowedContracts)
}
cp.AllowedGroups = keys.PublicKeys(c.AllowedGroups).Copy() cp.AllowedGroups = keys.PublicKeys(c.AllowedGroups).Copy()
if c.Rules != nil { if c.Rules != nil {
cp.Rules = make([]WitnessRule, len(c.Rules)) cp.Rules = make([]WitnessRule, len(c.Rules))

View file

@ -9,6 +9,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"slices"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
lru "github.com/hashicorp/golang-lru/v2" lru "github.com/hashicorp/golang-lru/v2"
@ -81,12 +82,7 @@ func (keys PublicKeys) Contains(pKey *PublicKey) bool {
// Copy returns a shallow copy of the PublicKeys slice. It creates a new slice with the same elements, // Copy returns a shallow copy of the PublicKeys slice. It creates a new slice with the same elements,
// but does not perform a deep copy of the elements themselves. // but does not perform a deep copy of the elements themselves.
func (keys PublicKeys) Copy() PublicKeys { func (keys PublicKeys) Copy() PublicKeys {
if keys == nil { return slices.Clone(keys)
return nil
}
res := make(PublicKeys, len(keys))
copy(res, keys)
return res
} }
// Unique returns a set of public keys. // Unique returns a set of public keys.

View file

@ -5,6 +5,7 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"math/rand" "math/rand"
"slices"
"sort" "sort"
"testing" "testing"
@ -145,8 +146,7 @@ func TestSort(t *testing.T) {
pubs1[i] = priv.PublicKey() pubs1[i] = priv.PublicKey()
} }
pubs2 := make(PublicKeys, len(pubs1)) pubs2 := slices.Clone(pubs1)
copy(pubs2, pubs1)
sort.Sort(pubs1) sort.Sort(pubs1)

View file

@ -10,6 +10,7 @@ import (
mrand "math/rand" mrand "math/rand"
"net" "net"
"runtime" "runtime"
"slices"
"sort" "sort"
"strconv" "strconv"
"sync" "sync"
@ -1494,8 +1495,7 @@ func (s *Server) RequestTx(hashes ...util.Uint256) {
return return
} }
var sorted = make([]util.Uint256, len(hashes)) var sorted = slices.Clone(hashes)
copy(sorted, hashes)
sort.Slice(sorted, func(i, j int) bool { sort.Slice(sorted, func(i, j int) bool {
return sorted[i].CompareTo(sorted[j]) < 0 return sorted[i].CompareTo(sorted[j]) < 0
}) })

View file

@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math" "math"
"slices"
"strings" "strings"
ojson "github.com/nspcc-dev/go-ordered-json" ojson "github.com/nspcc-dev/go-ordered-json"
@ -100,8 +101,7 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error {
} }
} }
if len(m.SupportedStandards) > 1 { if len(m.SupportedStandards) > 1 {
names := make([]string, len(m.SupportedStandards)) names := slices.Clone(m.SupportedStandards)
copy(names, m.SupportedStandards)
if stringsHaveDups(names) { if stringsHaveDups(names) {
return errors.New("duplicate supported standards") return errors.New("duplicate supported standards")
} }
@ -128,8 +128,7 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error {
return errors.New("invalid (null?) trusts") return errors.New("invalid (null?) trusts")
} }
if len(m.Trusts.Value) > 1 { if len(m.Trusts.Value) > 1 {
hashes := make([]PermissionDesc, len(m.Trusts.Value)) hashes := slices.Clone(m.Trusts.Value)
copy(hashes, m.Trusts.Value)
if permissionDescsHaveDups(hashes) { if permissionDescsHaveDups(hashes) {
return errors.New("duplicate trusted contracts") return errors.New("duplicate trusted contracts")
} }

View file

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"slices"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -128,8 +129,7 @@ func (p *Permission) IsValid() error {
if len(p.Methods.Value) < 2 { if len(p.Methods.Value) < 2 {
return nil return nil
} }
names := make([]string, len(p.Methods.Value)) names := slices.Clone(p.Methods.Value)
copy(names, p.Methods.Value)
if stringsHaveDups(names) { if stringsHaveDups(names) {
return errors.New("duplicate method names") return errors.New("duplicate method names")
} }

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"slices"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
@ -349,10 +350,8 @@ func NewParameterFromValue(value any) (Parameter, error) {
result.Type = ArrayType result.Type = ArrayType
result.Value = arr result.Value = arr
case []Parameter: case []Parameter:
arr := make([]Parameter, len(v))
copy(arr, v)
result.Type = ArrayType result.Type = ArrayType
result.Value = arr result.Value = slices.Clone(v)
case []*keys.PublicKey: case []*keys.PublicKey:
return NewParameterFromValue(keys.PublicKeys(v)) return NewParameterFromValue(keys.PublicKeys(v))
case keys.PublicKeys: case keys.PublicKeys:

View file

@ -2,6 +2,7 @@ package rpcbinding
import ( import (
"fmt" "fmt"
"slices"
"sort" "sort"
"strings" "strings"
"text/template" "text/template"
@ -390,8 +391,7 @@ func NewConfig() binding.Config {
func Generate(cfg binding.Config) error { func Generate(cfg binding.Config) error {
// Avoid changing *cfg.Manifest. // Avoid changing *cfg.Manifest.
mfst := *cfg.Manifest mfst := *cfg.Manifest
mfst.ABI.Methods = make([]manifest.Method, len(mfst.ABI.Methods)) mfst.ABI.Methods = slices.Clone(mfst.ABI.Methods)
copy(mfst.ABI.Methods, cfg.Manifest.ABI.Methods)
cfg.Manifest = &mfst cfg.Manifest = &mfst
var imports = make(map[string]struct{}) var imports = make(map[string]struct{})

View file

@ -5,6 +5,8 @@ providing only things used by neo-go.
*/ */
package bitfield package bitfield
import "slices"
// Field is a bit field represented as a slice of uint64 values. // Field is a bit field represented as a slice of uint64 values.
type Field []uint64 type Field []uint64
@ -32,9 +34,7 @@ func (f Field) IsSet(i int) bool {
// Copy makes a copy of the current Field. // Copy makes a copy of the current Field.
func (f Field) Copy() Field { func (f Field) Copy() Field {
fn := make(Field, len(f)) return slices.Clone(f)
copy(fn, f)
return fn
} }
// And implements logical AND between f's and m's bits saving the result into f. // And implements logical AND between f's and m's bits saving the result into f.

View file

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"slices"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
@ -351,7 +352,5 @@ func DynamicOnUnload(v *VM, ctx *Context, commit bool) error {
// BreakPoints returns the current set of Context's breakpoints. // BreakPoints returns the current set of Context's breakpoints.
func (c *Context) BreakPoints() []int { func (c *Context) BreakPoints() []int {
res := make([]int, len(c.sc.breakPoints)) return slices.Clone(c.sc.breakPoints)
copy(res, c.sc.breakPoints)
return res
} }

View file

@ -2,6 +2,7 @@ package vm
import ( import (
"encoding/binary" "encoding/binary"
"slices"
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -143,54 +144,48 @@ func TestIsScriptCorrect(t *testing.T) {
good := w.Bytes() good := w.Bytes()
getScript := func() []byte {
s := make([]byte, len(good))
copy(s, good)
return s
}
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
require.NoError(t, IsScriptCorrect(good, nil)) require.NoError(t, IsScriptCorrect(good, nil))
}) })
t.Run("bad instruction", func(t *testing.T) { t.Run("bad instruction", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[retOff] = 0xff bad[retOff] = 0xff
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds JMP 1", func(t *testing.T) { t.Run("out of bounds JMP 1", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmpOff+1] = 0x80 // -128 bad[jmpOff+1] = 0x80 // -128
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds JMP 2", func(t *testing.T) { t.Run("out of bounds JMP 2", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmpOff+1] = 0x7f bad[jmpOff+1] = 0x7f
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("bad JMP offset 1", func(t *testing.T) { t.Run("bad JMP offset 1", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmpOff+1] = 0xff // into "something" bad[jmpOff+1] = 0xff // into "something"
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("bad JMP offset 2", func(t *testing.T) { t.Run("bad JMP offset 2", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmpOff+1] = byte(pushOff - jmpOff + 1) bad[jmpOff+1] = byte(pushOff - jmpOff + 1)
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds JMPL 1", func(t *testing.T) { t.Run("out of bounds JMPL 1", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmplOff+1] = byte(-jmplOff - 1) bad[jmplOff+1] = byte(-jmplOff - 1)
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds JMPL 1", func(t *testing.T) { t.Run("out of bounds JMPL 1", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmplOff+1] = byte(len(bad)-jmplOff) + 1 bad[jmplOff+1] = byte(len(bad)-jmplOff) + 1
bad[jmplOff+2] = 0 bad[jmplOff+2] = 0
bad[jmplOff+3] = 0 bad[jmplOff+3] = 0
@ -206,25 +201,25 @@ func TestIsScriptCorrect(t *testing.T) {
}) })
t.Run("bad JMPL offset", func(t *testing.T) { t.Run("bad JMPL offset", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[jmplOff+1] = 0xfe // into JMP bad[jmplOff+1] = 0xfe // into JMP
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds TRY 1", func(t *testing.T) { t.Run("out of bounds TRY 1", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[tryOff+1] = byte(-tryOff - 1) bad[tryOff+1] = byte(-tryOff - 1)
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds TRY 2", func(t *testing.T) { t.Run("out of bounds TRY 2", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[tryOff+1] = byte(len(bad)-tryOff) + 1 bad[tryOff+1] = byte(len(bad)-tryOff) + 1
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("out of bounds TRY 2", func(t *testing.T) { t.Run("out of bounds TRY 2", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[tryOff+2] = byte(len(bad)-tryOff) + 1 bad[tryOff+2] = byte(len(bad)-tryOff) + 1
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
@ -239,31 +234,31 @@ func TestIsScriptCorrect(t *testing.T) {
}) })
t.Run("bad TRYL offset 1", func(t *testing.T) { t.Run("bad TRYL offset 1", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[trylOff+1] = byte(-(trylOff - jmpOff) - 1) // into "something" bad[trylOff+1] = byte(-(trylOff - jmpOff) - 1) // into "something"
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("bad TRYL offset 2", func(t *testing.T) { t.Run("bad TRYL offset 2", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[trylOff+5] = byte(len(bad) - trylOff - 1) bad[trylOff+5] = byte(len(bad) - trylOff - 1)
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("bad ISTYPE type", func(t *testing.T) { t.Run("bad ISTYPE type", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[istypeOff+1] = byte(0xff) bad[istypeOff+1] = byte(0xff)
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("bad ISTYPE type (Any)", func(t *testing.T) { t.Run("bad ISTYPE type (Any)", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[istypeOff+1] = byte(stackitem.AnyT) bad[istypeOff+1] = byte(stackitem.AnyT)
require.Error(t, IsScriptCorrect(bad, nil)) require.Error(t, IsScriptCorrect(bad, nil))
}) })
t.Run("good NEWARRAY_T type", func(t *testing.T) { t.Run("good NEWARRAY_T type", func(t *testing.T) {
bad := getScript() bad := slices.Clone(good)
bad[istypeOff] = byte(opcode.NEWARRAYT) bad[istypeOff] = byte(opcode.NEWARRAYT)
bad[istypeOff+1] = byte(stackitem.AnyT) bad[istypeOff+1] = byte(stackitem.AnyT)
require.NoError(t, IsScriptCorrect(bad, nil)) require.NoError(t, IsScriptCorrect(bad, nil))

View file

@ -57,5 +57,5 @@ func TestContext_BreakPoints(t *testing.T) {
// New context -> clean breakpoints. // New context -> clean breakpoints.
v.loadScriptWithCallingHash(prog, nil, nil, util.Uint160{}, util.Uint160{}, callflag.All, 1, 3, nil) v.loadScriptWithCallingHash(prog, nil, nil, util.Uint160{}, util.Uint160{}, callflag.All, 1, 3, nil)
require.Equal(t, []int{}, v.Context().BreakPoints()) require.Nil(t, v.Context().BreakPoints())
} }

View file

@ -9,6 +9,7 @@ import (
"math" "math"
"math/big" "math/big"
"reflect" "reflect"
"slices"
"unicode/utf8" "unicode/utf8"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
@ -348,9 +349,7 @@ func (i *Struct) Convert(typ Type) (Item, error) {
case StructT: case StructT:
return i, nil return i, nil
case ArrayT: case ArrayT:
arr := make([]Item, len(i.value)) return NewArray(slices.Clone(i.value)), nil
copy(arr, i.value)
return NewArray(arr), nil
case BooleanT: case BooleanT:
return NewBool(true), nil return NewBool(true), nil
default: default:
@ -793,9 +792,7 @@ func (i *Array) Convert(typ Type) (Item, error) {
case ArrayT: case ArrayT:
return i, nil return i, nil
case StructT: case StructT:
arr := make([]Item, len(i.value)) return NewStruct(slices.Clone(i.value)), nil
copy(arr, i.value)
return NewStruct(arr), nil
case BooleanT: case BooleanT:
return NewBool(true), nil return NewBool(true), nil
default: default: