diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec5dbf047..0d8cf6cae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,7 +53,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version: '1.23' - name: Build CLI run: make build @@ -135,7 +135,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version: '1.23' - name: Login to DockerHub if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ff74ab05d..eab01a75a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -135,7 +135,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version: '1.23' cache: true - name: Write coverage profile @@ -156,24 +156,24 @@ jobs: strategy: matrix: os: [ubuntu-22.04, windows-2022, macos-12, macos-14] - go_versions: [ '1.20', '1.21', '1.22' ] + go_versions: [ '1.21', '1.22', '1.23' ] exclude: # Only latest Go version for Windows and MacOS. - os: windows-2022 - go_versions: '1.20' + go_versions: '1.21' - os: windows-2022 - go_versions: '1.21' - - os: macos-12 - go_versions: '1.20' + go_versions: '1.22' - os: macos-12 go_versions: '1.21' - - os: macos-14 - go_versions: '1.20' + - os: macos-12 + go_versions: '1.22' - os: macos-14 go_versions: '1.21' + - os: macos-14 + go_versions: '1.22' # Exclude latest Go version for Ubuntu as Coverage uses it. - os: ubuntu-22.04 - go_versions: '1.22' + go_versions: '1.23' fail-fast: false steps: - uses: actions/checkout@v4 diff --git a/.golangci.yml b/.golangci.yml index 3597c7093..5169c5a42 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -51,7 +51,7 @@ linters: - decorder - durationcheck - errorlint - - exportloopref + - copyloopvar - gofmt - misspell - predeclared diff --git a/Dockerfile b/Dockerfile index c23ada9b2..2680555c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Builder image # Keep go version in sync with Build GA job. -FROM golang:1.22-alpine as builder +FROM golang:1.23-alpine as builder # Display go version for information purposes. RUN go version diff --git a/Dockerfile.wsc b/Dockerfile.wsc index 58e09f65a..30d1774d1 100644 --- a/Dockerfile.wsc +++ b/Dockerfile.wsc @@ -1,6 +1,6 @@ # Builder image # Keep go version in sync with Build GA job. -FROM golang:1.22.0-windowsservercore-ltsc2022 as builder +FROM golang:1.23.0-windowsservercore-ltsc2022 as builder COPY . /neo-go diff --git a/Makefile b/Makefile index 07c2c51aa..ac5111659 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ REPONAME = "neo-go" NETMODE ?= "privnet" BINARY=neo-go BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE) -GO_VERSION ?= 1.20 +GO_VERSION ?= 1.23 DESTDIR = "" SYSCONFIGDIR = "/etc" BINDIR = "/usr/bin" diff --git a/README.md b/README.md index a435c83c3..3b6f0668c 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ NeoGo, `:latest` points to the latest release) or build yourself. ### Building -Building NeoGo requires Go 1.20+ and `make`: +Building NeoGo requires Go 1.21+ and `make`: ``` make diff --git a/cli/query/query.go b/cli/query/query.go index f945a37fe..424b473b5 100644 --- a/cli/query/query.go +++ b/cli/query/query.go @@ -2,9 +2,10 @@ package query import ( "bytes" + "cmp" "encoding/base64" "fmt" - "sort" + "slices" "strconv" "strings" "text/tabwriter" @@ -192,14 +193,18 @@ func queryCandidates(ctx *cli.Context) error { return cli.Exit(err, 1) } - sort.Slice(vals, func(i, j int) bool { - if vals[i].Active != vals[j].Active { - return vals[i].Active + slices.SortFunc(vals, func(a, b result.Candidate) int { + if a.Active && !b.Active { + return 1 } - if vals[i].Votes != vals[j].Votes { - return vals[i].Votes > vals[j].Votes + if !a.Active && b.Active { + return -1 } - return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1 + res := cmp.Compare(a.Votes, b.Votes) + if res != 0 { + return res + } + return a.PublicKey.Cmp(&b.PublicKey) }) var res []byte res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n") diff --git a/cli/server/server.go b/cli/server/server.go index 67787ced9..ceab19586 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "os/signal" + "slices" "syscall" "time" @@ -36,10 +37,9 @@ import ( func NewCommands() []*cli.Command { cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath} 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, &cli.UintFlag{ Name: "count", @@ -47,8 +47,7 @@ func NewCommands() []*cli.Command { Usage: "Number of blocks to be processed (default or 0: all chain)", }, ) - var cfgCountOutFlags = make([]cli.Flag, len(cfgWithCountFlags)) - copy(cfgCountOutFlags, cfgWithCountFlags) + var cfgCountOutFlags = slices.Clone(cfgWithCountFlags) cfgCountOutFlags = append(cfgCountOutFlags, &cli.UintFlag{ Name: "start", @@ -61,8 +60,7 @@ func NewCommands() []*cli.Command { Usage: "Output file (stdout if not given)", }, ) - var cfgCountInFlags = make([]cli.Flag, len(cfgWithCountFlags)) - copy(cfgCountInFlags, cfgWithCountFlags) + var cfgCountInFlags = slices.Clone(cfgWithCountFlags) cfgCountInFlags = append(cfgCountInFlags, &cli.StringFlag{ Name: "in", @@ -79,13 +77,12 @@ func NewCommands() []*cli.Command { Usage: "Use if dump is incremental", }, ) - var cfgHeightFlags = make([]cli.Flag, len(cfgFlags)+1) - copy(cfgHeightFlags, cfgFlags) - cfgHeightFlags[len(cfgHeightFlags)-1] = &cli.UintFlag{ + var cfgHeightFlags = slices.Clone(cfgFlags) + cfgHeightFlags = append(cfgHeightFlags, &cli.UintFlag{ Name: "height", Usage: "Height of the state to reset DB to", Required: true, - } + }) return []*cli.Command{ { Name: "node", diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index c3c8d4032..8489c31b5 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -417,7 +417,7 @@ func initSmartContract(ctx *cli.Context) error { gm := []byte("module " + contractName + ` -go 1.20 +go 1.21 require ( github.com/nspcc-dev/neo-go/pkg/interop ` + ver + ` diff --git a/cli/util/cancel.go b/cli/util/cancel.go index fcb56a059..eca0f5dfc 100644 --- a/cli/util/cancel.go +++ b/cli/util/cancel.go @@ -64,8 +64,8 @@ func cancelTx(ctx *cli.Context) error { if err != nil { return err } - if mainTx != nil && t.NetworkFee < mainTx.NetworkFee+1 { - t.NetworkFee = mainTx.NetworkFee + 1 + if mainTx != nil { + t.NetworkFee = max(t.NetworkFee, mainTx.NetworkFee+1) } t.NetworkFee += int64(flags.Fixed8FromContext(ctx, "gas")) if mainTx != nil { diff --git a/cli/vm/cli.go b/cli/vm/cli.go index 2c742d6a8..21125ed67 100644 --- a/cli/vm/cli.go +++ b/cli/vm/cli.go @@ -12,6 +12,7 @@ import ( "io" "math/big" "os" + "slices" "strconv" "strings" "text/tabwriter" @@ -41,7 +42,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/urfave/cli/v2" @@ -1456,7 +1456,9 @@ func Parse(args []string) (string, error) { } buf = fmt.Appendf(buf, "Hex to String\t%s\n", fmt.Sprintf("%q", string(rawStr))) buf = fmt.Appendf(buf, "Hex to Integer\t%s\n", bigint.FromBytes(rawStr)) - buf = fmt.Appendf(buf, "Swap Endianness\t%s\n", hex.EncodeToString(slice.CopyReverse(rawStr))) + var clonedStr = slices.Clone(rawStr) + slices.Reverse(clonedStr) + buf = fmt.Appendf(buf, "Swap Endianness\t%s\n", hex.EncodeToString(clonedStr)) } if addr, err := address.StringToUint160(arg); err == nil { buf = fmt.Appendf(buf, "Address to BE ScriptHash\t%s\n", addr) diff --git a/cli/vm/cli_test.go b/cli/vm/cli_test.go index 555c66fc9..c2b994f92 100644 --- a/cli/vm/cli_test.go +++ b/cli/vm/cli_test.go @@ -353,7 +353,7 @@ require ( github.com/nspcc-dev/neo-go/pkg/interop v0.0.0 ) replace github.com/nspcc-dev/neo-go/pkg/interop => ` + filepath.Join(wd, "../../pkg/interop") + ` -go 1.20`) +go 1.21`) require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm)) return filename } diff --git a/cli/wallet/nep11.go b/cli/wallet/nep11.go index 7c4d97206..809e76c01 100644 --- a/cli/wallet/nep11.go +++ b/cli/wallet/nep11.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "errors" "fmt" + "slices" "strconv" "github.com/nspcc-dev/neo-go/cli/cmdargs" @@ -39,12 +40,11 @@ func newNEP11Commands() []*cli.Command { Usage: "Hex-encoded token ID", } - balanceFlags := make([]cli.Flag, len(baseBalanceFlags)) - copy(balanceFlags, baseBalanceFlags) + balanceFlags := slices.Clone(baseBalanceFlags) balanceFlags = append(balanceFlags, tokenID) 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, options.RPC...) return []*cli.Command{ diff --git a/cli/wallet/nep17.go b/cli/wallet/nep17.go index f8f6efe9c..462069b8b 100644 --- a/cli/wallet/nep17.go +++ b/cli/wallet/nep17.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "slices" "strings" "github.com/nspcc-dev/neo-go/cli/cmdargs" @@ -91,11 +92,10 @@ var ( ) func newNEP17Commands() []*cli.Command { - balanceFlags := make([]cli.Flag, len(baseBalanceFlags)) - copy(balanceFlags, baseBalanceFlags) + balanceFlags := slices.Clone(baseBalanceFlags) balanceFlags = append(balanceFlags, options.RPC...) - transferFlags := make([]cli.Flag, len(baseTransferFlags)) - copy(transferFlags, baseTransferFlags) + + transferFlags := slices.Clone(baseTransferFlags) transferFlags = append(transferFlags, options.RPC...) return []*cli.Command{ { diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index 17e46b8d8..2645f1722 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -8,6 +8,7 @@ import ( "io" "math/big" "os" + "slices" "strings" "github.com/nspcc-dev/neo-go/cli/cmdargs" @@ -512,16 +513,13 @@ func exportKeys(ctx *cli.Context) error { var wifs []string -loop: for _, a := range wall.Accounts { if addr != "" && a.Address != addr { continue } - for i := range wifs { - if a.EncryptedWIF == wifs[i] { - continue loop - } + if slices.Contains(wifs, a.EncryptedWIF) { + continue } wifs = append(wifs, a.EncryptedWIF) diff --git a/examples/engine/go.mod b/examples/engine/go.mod index ebdc433c8..12283f847 100644 --- a/examples/engine/go.mod +++ b/examples/engine/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/engine -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/events/go.mod b/examples/events/go.mod index c85b6254e..f9aaf9d18 100644 --- a/examples/events/go.mod +++ b/examples/events/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/events -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/iterator/go.mod b/examples/iterator/go.mod index b1c9a1e9d..622f38c53 100644 --- a/examples/iterator/go.mod +++ b/examples/iterator/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/iterator -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/nft-d/go.mod b/examples/nft-d/go.mod index a3c711a79..d9d8b6507 100644 --- a/examples/nft-d/go.mod +++ b/examples/nft-d/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/nft -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/nft-nd-nns/go.mod b/examples/nft-nd-nns/go.mod index 54fa6324a..3f95e8566 100644 --- a/examples/nft-nd-nns/go.mod +++ b/examples/nft-nd-nns/go.mod @@ -1,6 +1,6 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd-nns -go 1.20 +go 1.21 require ( github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 diff --git a/examples/nft-nd-nns/go.sum b/examples/nft-nd-nns/go.sum index c0ce31b26..8e80dd9da 100644 --- a/examples/nft-nd-nns/go.sum +++ b/examples/nft-nd-nns/go.sum @@ -39,6 +39,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -55,6 +56,7 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -170,16 +172,19 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= @@ -195,19 +200,25 @@ github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c h1:uyK5aLbAhrnZtnvobJLN24gGUrlxIJAAFqiWl+liZuo= +github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c/go.mod h1:kjBC9F8L25GR+kIHy/1KgG/KfcoGnVwIiyovgq1uszk= github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg= github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= +github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= +github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= +github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11/go.mod h1:W+ImTNRnSNMH8w43H1knCcIqwu7dLHePXtlJNZ7EFIs= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/tzhash v1.7.0 h1:/+aL33NC7y5OIGnY2kYgjZt8mg7LVGFMdj/KAJLndnk= +github.com/nspcc-dev/tzhash v1.7.0/go.mod h1:Dnx9LUlOLr5paL2Rtc96x0PPs8D9eIkUtowt1n+KQus= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -218,6 +229,7 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -260,6 +272,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -288,6 +301,7 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -311,6 +325,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= 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= @@ -368,6 +383,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -562,6 +578,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -581,6 +598,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/examples/nft-nd/go.mod b/examples/nft-nd/go.mod index e9e7e535d..da95393ae 100644 --- a/examples/nft-nd/go.mod +++ b/examples/nft-nd/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/oracle/go.mod b/examples/oracle/go.mod index 8b4402b64..1f719a097 100644 --- a/examples/oracle/go.mod +++ b/examples/oracle/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/oracle -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/runtime/go.mod b/examples/runtime/go.mod index ea01f8e9d..3b90e9622 100644 --- a/examples/runtime/go.mod +++ b/examples/runtime/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/runtime -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/storage/go.mod b/examples/storage/go.mod index e9c9aa510..99851cce0 100644 --- a/examples/storage/go.mod +++ b/examples/storage/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/storage -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/timer/go.mod b/examples/timer/go.mod index 3f4d91367..1e7a09d7b 100644 --- a/examples/timer/go.mod +++ b/examples/timer/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/timer -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/token/go.mod b/examples/token/go.mod index f9d6d9edc..6e86fae28 100644 --- a/examples/token/go.mod +++ b/examples/token/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/token -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/examples/zkp/cubic_circuit/go.mod b/examples/zkp/cubic_circuit/go.mod index 96e2e70ff..5ca7861c9 100644 --- a/examples/zkp/cubic_circuit/go.mod +++ b/examples/zkp/cubic_circuit/go.mod @@ -1,10 +1,10 @@ module github.com/nspcc-dev/neo-go/examples/zkp/cubic -go 1.20 +go 1.21 require ( - github.com/consensys/gnark v0.9.1 - github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb + github.com/consensys/gnark v0.10.0 + github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e github.com/nspcc-dev/neo-go v0.103.1 github.com/stretchr/testify v1.8.4 ) @@ -27,6 +27,8 @@ require ( github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/holiman/uint256 v1.2.0 // indirect + github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71 // indirect + github.com/ingonyama-zk/iciclegnark v0.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect diff --git a/examples/zkp/cubic_circuit/go.sum b/examples/zkp/cubic_circuit/go.sum index 702a54e2d..e6b18a5ec 100644 --- a/examples/zkp/cubic_circuit/go.sum +++ b/examples/zkp/cubic_circuit/go.sum @@ -39,6 +39,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -57,15 +58,16 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark v0.9.1 h1:aTwBp5469MY/2jNrf4ABrqHRW3+JytfkADdw4ZBY7T0= -github.com/consensys/gnark v0.9.1/go.mod h1:udWvWGXnfBE7mn7BsNoGAvZDnUhcONBEtNijvVjfY80= -github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc= -github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark v0.10.0 h1:yhi6ThoeFP7WrH8zQDaO56WVXe9iJEBSkfrZ9PZxabw= +github.com/consensys/gnark v0.10.0/go.mod h1:VJU5JrrhZorbfDH+EUjcuFWr2c5z19tHPh8D6KVQksU= +github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e h1:MKdOuCiy2DAX1tMp2YsmtNDaqdigpY6B5cZQDJ9BvEo= +github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -141,6 +143,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -169,6 +172,10 @@ github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71 h1:YxI1RTPzpFJ3MBmxPl3Bo0F7ume7CmQEC1M9jL6CT94= +github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk= +github.com/ingonyama-zk/iciclegnark v0.1.0 h1:88MkEghzjQBMjrYRJFxZ9oR9CTIpB8NG2zLeCJSvXKQ= +github.com/ingonyama-zk/iciclegnark v0.1.0/go.mod h1:wz6+IpyHKs6UhMMoQpNqz1VY+ddfKqC/gRwR/64W6WU= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -179,16 +186,20 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -211,19 +222,25 @@ github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c h1:uyK5aLbAhrnZtnvobJLN24gGUrlxIJAAFqiWl+liZuo= +github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c/go.mod h1:kjBC9F8L25GR+kIHy/1KgG/KfcoGnVwIiyovgq1uszk= github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c h1:OOQeE613BH93ICPq3eke5N78gWNeMjcBWkmD2NKyXVg= github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= +github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= github.com/nspcc-dev/neo-go v0.103.1 h1:BfRBceHUu8jSc1KQy7CzmQ/pa+xzAmgcyteGf0/IGgM= github.com/nspcc-dev/neo-go v0.103.1/go.mod h1:MD7MPiyshUwrE5n1/LzxeandbItaa/iLW/bJb6gNs/U= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= +github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= +github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11/go.mod h1:W+ImTNRnSNMH8w43H1knCcIqwu7dLHePXtlJNZ7EFIs= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/tzhash v1.7.0 h1:/+aL33NC7y5OIGnY2kYgjZt8mg7LVGFMdj/KAJLndnk= +github.com/nspcc-dev/tzhash v1.7.0/go.mod h1:Dnx9LUlOLr5paL2Rtc96x0PPs8D9eIkUtowt1n+KQus= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -234,6 +251,7 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -267,6 +285,7 @@ github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= @@ -278,6 +297,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -308,6 +328,7 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -331,6 +352,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= 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= @@ -388,6 +410,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -586,6 +609,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= +google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -605,6 +629,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/examples/zkp/xor_compat/go.mod b/examples/zkp/xor_compat/go.mod index 7ef9bc482..29b882dec 100644 --- a/examples/zkp/xor_compat/go.mod +++ b/examples/zkp/xor_compat/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/go.mod b/go.mod index 73d095310..435b33068 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/nspcc-dev/neo-go -go 1.20 +go 1.21 require ( github.com/chzyer/readline v1.5.1 - github.com/consensys/gnark v0.9.1 - github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb + github.com/consensys/gnark v0.10.0 + github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/google/uuid v1.6.0 @@ -48,6 +48,8 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect + github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71 // indirect + github.com/ingonyama-zk/iciclegnark v0.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect diff --git a/go.sum b/go.sum index e7ff71e45..d4de8ad65 100644 --- a/go.sum +++ b/go.sum @@ -16,10 +16,10 @@ github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark v0.9.1 h1:aTwBp5469MY/2jNrf4ABrqHRW3+JytfkADdw4ZBY7T0= -github.com/consensys/gnark v0.9.1/go.mod h1:udWvWGXnfBE7mn7BsNoGAvZDnUhcONBEtNijvVjfY80= -github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc= -github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark v0.10.0 h1:yhi6ThoeFP7WrH8zQDaO56WVXe9iJEBSkfrZ9PZxabw= +github.com/consensys/gnark v0.10.0/go.mod h1:VJU5JrrhZorbfDH+EUjcuFWr2c5z19tHPh8D6KVQksU= +github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e h1:MKdOuCiy2DAX1tMp2YsmtNDaqdigpY6B5cZQDJ9BvEo= +github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -54,6 +54,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= @@ -66,6 +67,10 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71 h1:YxI1RTPzpFJ3MBmxPl3Bo0F7ume7CmQEC1M9jL6CT94= +github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk= +github.com/ingonyama-zk/iciclegnark v0.1.0 h1:88MkEghzjQBMjrYRJFxZ9oR9CTIpB8NG2zLeCJSvXKQ= +github.com/ingonyama-zk/iciclegnark v0.1.0/go.mod h1:wz6+IpyHKs6UhMMoQpNqz1VY+ddfKqC/gRwR/64W6WU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -73,6 +78,7 @@ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3x github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -126,6 +132,7 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= @@ -146,6 +153,7 @@ github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQut go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -166,6 +174,7 @@ golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -211,12 +220,14 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= diff --git a/internal/contracts/oracle_contract/go.mod b/internal/contracts/oracle_contract/go.mod index 50d3cd2a3..8cd5d6312 100644 --- a/internal/contracts/oracle_contract/go.mod +++ b/internal/contracts/oracle_contract/go.mod @@ -1,5 +1,5 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index 79827d303..e9a0acc49 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -6,6 +6,7 @@ import ( "go/ast" "go/token" "go/types" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/vm/emit" @@ -118,9 +119,7 @@ func (c *codegen) traverseGlobals() bool { var currMax int lastCnt, currMax = c.convertInitFuncs(f, pkg.Types, lastCnt) - if currMax > maxCnt { - maxCnt = currMax - } + maxCnt = max(currMax, maxCnt) } // because we reuse `convertFuncDecl` for init funcs, // we need to clear scope, so that global variables @@ -128,9 +127,7 @@ func (c *codegen) traverseGlobals() bool { c.scope = nil }) - if c.globalInlineCount > maxCnt { - maxCnt = c.globalInlineCount - } + maxCnt = max(c.globalInlineCount, maxCnt) // Here we remove `INITSLOT` if no code was emitted for `init` function. // Note that the `INITSSLOT` must stay in place. @@ -701,12 +698,7 @@ func (c *codegen) pickVarsFromNodes(nodes []nodeContext, markAsUsed func(name st } func isGoBuiltin(name string) bool { - for i := range goBuiltins { - if name == goBuiltins[i] { - return true - } - } - return false + return slices.Contains(goBuiltins, name) } func isPotentialCustomBuiltin(f *funcScope, expr ast.Expr) bool { diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 8bc1d1a80..2d9cfc1a9 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -1,6 +1,7 @@ package compiler import ( + "cmp" "encoding/binary" "errors" "fmt" @@ -10,7 +11,7 @@ import ( "go/types" "math" "math/big" - "sort" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/encoding/address" @@ -402,9 +403,7 @@ func (c *codegen) convertInitFuncs(f *ast.File, pkg *types.Package, lastCount in f := c.convertFuncDecl(f, n, pkg) lastCount = f.vars.localsCnt - if lastCount > maxCount { - maxCount = lastCount - } + maxCount = max(lastCount, maxCount) } case *ast.GenDecl: return false @@ -437,9 +436,7 @@ func (c *codegen) convertDeployFuncs() int { f := c.convertFuncDecl(f, n, pkg) lastCount = f.vars.localsCnt - if lastCount > maxCount { - maxCount = lastCount - } + maxCount = max(lastCount, maxCount) } case *ast.GenDecl: return false @@ -2257,7 +2254,7 @@ func (c *codegen) compile(info *buildInfo, pkg *packages.Package) error { for _, p := range info.program { keys = append(keys, p.Types) } - sort.Slice(keys, func(i, j int) bool { return keys[i].Path() < keys[j].Path() }) + slices.SortFunc(keys, func(a, b *types.Package) int { return cmp.Compare(a.Path(), b.Path()) }) // Generate the code for the program. c.ForEachFile(func(f *ast.File, pkg *types.Package) { @@ -2539,9 +2536,7 @@ func removeNOPs(b []byte, nopOffsets []int, sequencePoints map[string][]DebugSeq func calcOffsetCorrection(ip, target int, offsets []int) int { cnt := 0 - start := sort.Search(len(offsets), func(i int) bool { - return offsets[i] >= ip || offsets[i] >= target - }) + start, _ := slices.BinarySearch(offsets, min(ip, target)) for i := start; i < len(offsets) && (offsets[i] < target || offsets[i] <= ip); i++ { ind := offsets[i] if ip <= ind && ind < target || target <= ind && ind < ip { diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 191bfb848..7e47f844d 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -11,7 +11,7 @@ import ( "io" "os" "path/filepath" - "sort" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -362,7 +362,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) { for k := range di.EmittedEvents { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, eventName := range keys { var ( eventUsages = di.EmittedEvents[eventName] diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 70fe6751d..ea75e3d6c 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -6,7 +6,7 @@ import ( "fmt" "go/ast" "go/types" - "sort" + "slices" "strconv" "strings" "unicode" @@ -210,7 +210,7 @@ func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo { } fnames = append(fnames, name) } - sort.Strings(fnames) + slices.Sort(fnames) d.NamedTypes = make(map[string]binding.ExtendedType) for _, name := range fnames { m := c.methodInfoFromScope(name, c.funcs[name], d.NamedTypes) diff --git a/pkg/compiler/inline.go b/pkg/compiler/inline.go index b6cd03d3b..e9e07320d 100644 --- a/pkg/compiler/inline.go +++ b/pkg/compiler/inline.go @@ -5,6 +5,7 @@ import ( "go/ast" "go/constant" "go/types" + "slices" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/smartcontract/binding" @@ -47,9 +48,7 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) { c.scope = &funcScope{} c.scope.vars.newScope() defer func() { - if cnt := c.scope.vars.localsCnt; cnt > c.globalInlineCount { - c.globalInlineCount = cnt - } + c.globalInlineCount = max(c.globalInlineCount, c.scope.vars.localsCnt) c.scope = nil }() } @@ -58,8 +57,7 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) { // while stored in the new. oldScope := c.scope.vars.locals c.scope.vars.newScope() - newScope := make([]map[string]varInfo, len(c.scope.vars.locals)) - copy(newScope, c.scope.vars.locals) + newScope := slices.Clone(c.scope.vars.locals) defer c.scope.vars.dropScope() if f.decl.Recv != nil { diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 75066b5bb..dfac38b02 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -3,6 +3,7 @@ package compiler import ( "go/ast" "go/types" + "slices" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -45,11 +46,7 @@ func (c *codegen) typeOf(e ast.Expr) types.Type { func isBasicTypeOfKind(typ types.Type, ks ...types.BasicKind) bool { if t, ok := typ.Underlying().(*types.Basic); ok { k := t.Kind() - for i := range ks { - if k == ks[i] { - return true - } - } + return slices.Contains(ks, k) } return false } diff --git a/pkg/config/application_config.go b/pkg/config/application_config.go index 2e94961d7..9ac369238 100644 --- a/pkg/config/application_config.go +++ b/pkg/config/application_config.go @@ -2,7 +2,7 @@ package config import ( "fmt" - "sort" + "slices" "strconv" "strings" @@ -38,16 +38,12 @@ func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration if len(a.P2P.Addresses) != len(o.P2P.Addresses) { return false } - aCp := make([]string, len(a.P2P.Addresses)) - oCp := make([]string, len(o.P2P.Addresses)) - copy(aCp, a.P2P.Addresses) - copy(oCp, o.P2P.Addresses) - sort.Strings(aCp) - sort.Strings(oCp) - for i := range aCp { - if aCp[i] != oCp[i] { - return false - } + aCp := slices.Clone(a.P2P.Addresses) + oCp := slices.Clone(o.P2P.Addresses) + slices.Sort(aCp) + slices.Sort(oCp) + if !slices.Equal(aCp, oCp) { + return false } if a.P2P.AttemptConnPeers != o.P2P.AttemptConnPeers || a.P2P.BroadcastFactor != o.P2P.BroadcastFactor || diff --git a/pkg/config/protocol_config.go b/pkg/config/protocol_config.go index fdf0422d5..c72b8ccdb 100644 --- a/pkg/config/protocol_config.go +++ b/pkg/config/protocol_config.go @@ -1,9 +1,11 @@ package config import ( + "cmp" "errors" "fmt" - "sort" + "maps" + "slices" "time" "github.com/nspcc-dev/neo-go/pkg/config/netmode" @@ -166,9 +168,7 @@ func (p *ProtocolConfiguration) Validate() error { // sortCheckZero sorts heightNumber array and checks for zero height presence. func sortCheckZero(arr []heightNumber, field string) error { - sort.Slice(arr, func(i, j int) bool { - return arr[i].h < arr[j].h - }) + slices.SortFunc(arr, func(a, b heightNumber) int { return cmp.Compare(a.h, b.h) }) if arr[0].h != 0 { return fmt.Errorf("invalid %s: no height 0 specified", field) } @@ -231,40 +231,12 @@ func (p *ProtocolConfiguration) Equals(o *ProtocolConfiguration) bool { p.TimePerBlock != o.TimePerBlock || p.ValidatorsCount != o.ValidatorsCount || p.VerifyTransactions != o.VerifyTransactions || - len(p.CommitteeHistory) != len(o.CommitteeHistory) || - len(p.Hardforks) != len(o.Hardforks) || - len(p.SeedList) != len(o.SeedList) || - len(p.StandbyCommittee) != len(o.StandbyCommittee) || - len(p.ValidatorsHistory) != len(o.ValidatorsHistory) { + !maps.Equal(p.CommitteeHistory, o.CommitteeHistory) || + !maps.Equal(p.Hardforks, o.Hardforks) || + !slices.Equal(p.SeedList, o.SeedList) || + !slices.Equal(p.StandbyCommittee, o.StandbyCommittee) || + !maps.Equal(p.ValidatorsHistory, o.ValidatorsHistory) { return false } - for k, v := range p.CommitteeHistory { - vo, ok := o.CommitteeHistory[k] - if !ok || v != vo { - return false - } - } - for k, v := range p.Hardforks { - vo, ok := o.Hardforks[k] - if !ok || v != vo { - return false - } - } - for i := range p.SeedList { - if p.SeedList[i] != o.SeedList[i] { - return false - } - } - for i := range p.StandbyCommittee { - if p.StandbyCommittee[i] != o.StandbyCommittee[i] { - return false - } - } - for k, v := range p.ValidatorsHistory { - vo, ok := o.ValidatorsHistory[k] - if !ok || v != vo { - return false - } - } return true } diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index 6472d46da..4a7d80e09 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -3,7 +3,7 @@ package consensus import ( "errors" "fmt" - "sort" + "slices" "sync/atomic" "time" @@ -166,14 +166,9 @@ func NewService(cfg Config) (Service, error) { } // Check that the wallet password is correct for at least one account. - var ok bool - for _, acc := range srv.wallet.Accounts { - err := acc.Decrypt(srv.Config.Wallet.Password, srv.wallet.Scrypt) - if err == nil { - ok = true - break - } - } + var ok = slices.ContainsFunc(srv.wallet.Accounts, func(acc *wallet.Account) bool { + return acc.Decrypt(srv.Config.Wallet.Password, srv.wallet.Scrypt) == nil + }) if !ok { return nil, errors.New("no account with provided password was found") } @@ -634,9 +629,7 @@ func (s *service) processBlock(b dbft.Block[util.Uint256]) { } func (s *service) postBlock(b *coreb.Block) { - if s.lastTimestamp < b.Timestamp { - s.lastTimestamp = b.Timestamp - } + s.lastTimestamp = max(s.lastTimestamp, b.Timestamp) s.lastProposal = nil } @@ -658,8 +651,6 @@ func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness { return nil } - sort.Sort(keys.PublicKeys(pubs)) - buf := io.NewBufBinWriter() for i, j := 0, 0; i < len(pubs) && j < m; i++ { if sig, ok := sigs[pubs[i]]; ok { @@ -790,9 +781,7 @@ func (s *service) newBlockFromContext(ctx *dbft.Context[util.Uint256]) dbft.Bloc block.Block.PrimaryIndex = primaryIndex // it's OK to have ctx.TransactionsHashes == nil here - hashes := make([]util.Uint256, len(ctx.TransactionHashes)) - copy(hashes, ctx.TransactionHashes) - block.Block.MerkleRoot = hash.CalcMerkleRoot(hashes) + block.Block.MerkleRoot = hash.CalcMerkleRoot(slices.Clone(ctx.TransactionHashes)) return block } diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index f8c591f6b..afa834c56 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -7,7 +7,7 @@ import ( "fmt" "math" "math/big" - "sort" + "slices" "sync" "sync/atomic" "time" @@ -1115,9 +1115,7 @@ func (bc *Blockchain) Run() { } nextSync = dur > persistInterval*2 interval := persistInterval - dur - gcDur - if interval <= 0 { - interval = time.Microsecond // Reset doesn't work with zero value - } + interval = max(interval, time.Microsecond) // Reset doesn't work with zero or negative value. persistTimer.Reset(interval) } } @@ -1134,9 +1132,7 @@ func (bc *Blockchain) tryRunGC(oldHeight uint32) time.Duration { syncP := newHeight / uint32(bc.config.StateSyncInterval) syncP-- syncP *= uint32(bc.config.StateSyncInterval) - if tgtBlock > int64(syncP) { - tgtBlock = int64(syncP) - } + tgtBlock = min(tgtBlock, int64(syncP)) } // Always round to the GCP. tgtBlock /= int64(bc.config.Ledger.GarbageCollectionPeriod) @@ -1619,9 +1615,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error block.Index >= uint32(bc.config.StateSyncInterval)+bc.config.MaxTraceableBlocks && // check this in case if MaxTraceableBlocks>StateSyncInterval int(block.Index)%bc.config.StateSyncInterval == 0 { stop = block.Index - uint32(bc.config.StateSyncInterval) - bc.config.MaxTraceableBlocks - if stop > uint32(bc.config.StateSyncInterval) { - start = stop - uint32(bc.config.StateSyncInterval) - } + start = stop - min(stop, uint32(bc.config.StateSyncInterval)) } } else if block.Index > bc.config.MaxTraceableBlocks { start = block.Index - bc.config.MaxTraceableBlocks // is at least 1 @@ -1844,9 +1838,7 @@ func (bc *Blockchain) updateExtensibleWhitelist(height uint32) error { bc.updateExtensibleList(&newList, stateVals) } - sort.Slice(newList, func(i, j int) bool { - return newList[i].Less(newList[j]) - }) + slices.SortFunc(newList, util.Uint160.Compare) bc.extensible.Store(newList) return nil } @@ -1860,8 +1852,8 @@ func (bc *Blockchain) updateExtensibleList(s *[]util.Uint160, pubs keys.PublicKe // IsExtensibleAllowed determines if script hash is allowed to send extensible payloads. func (bc *Blockchain) IsExtensibleAllowed(u util.Uint160) bool { us := bc.extensible.Load().([]util.Uint160) - n := sort.Search(len(us), func(i int) bool { return !us[i].Less(u) }) - return n < len(us) + _, ok := slices.BinarySearchFunc(us, u, util.Uint160.Compare) + return ok } func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.Simple, trig trigger.Type, v *vm.VM) (*state.AppExecResult, *vm.VM, error) { @@ -2791,7 +2783,7 @@ func (bc *Blockchain) PoolTxWithData(t *transaction.Transaction, data any, mp *m // GetCommittee returns the sorted list of public keys of nodes in committee. func (bc *Blockchain) GetCommittee() (keys.PublicKeys, error) { pubs := bc.contracts.NEO.GetCommitteeMembers(bc.dao) - sort.Sort(pubs) + slices.SortFunc(pubs, (*keys.PublicKey).Cmp) return pubs, nil } @@ -2954,10 +2946,7 @@ func (bc *Blockchain) VerifyWitness(h util.Uint160, c hash.Hashable, w *transact // verifyHashAgainstScript verifies given hash against the given witness and returns the amount of GAS consumed. func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, gas int64) (int64, error) { - gasPolicy := bc.contracts.Policy.GetMaxVerificationGas(interopCtx.DAO) - if gas > gasPolicy { - gas = gasPolicy - } + gas = min(gas, bc.contracts.Policy.GetMaxVerificationGas(interopCtx.DAO)) vm := interopCtx.SpawnVM() vm.GasLimit = gas diff --git a/pkg/core/blockchain_neotest_test.go b/pkg/core/blockchain_neotest_test.go index 10966375c..c5d5b48ee 100644 --- a/pkg/core/blockchain_neotest_test.go +++ b/pkg/core/blockchain_neotest_test.go @@ -6,7 +6,7 @@ import ( "fmt" "math/big" "path/filepath" - "sort" + "slices" "strings" "testing" "time" @@ -334,7 +334,7 @@ func TestBlockchain_InitializeNeoCache_Bug3424(t *testing.T) { standBySorted, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee) require.NoError(t, err) standBySorted = standBySorted[:validatorsCount] - sort.Sort(standBySorted) + slices.SortFunc(standBySorted, (*keys.PublicKey).Cmp) pubs := e.Chain.ComputeNextBlockValidators() require.Equal(t, standBySorted, keys.PublicKeys(pubs)) @@ -384,7 +384,7 @@ func TestBlockchain_InitializeNeoCache_Bug3424(t *testing.T) { for i := range candidates[:validatorsCount] { sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PublicKey() } - sort.Sort(sortedCandidates) + slices.SortFunc(sortedCandidates, (*keys.PublicKey).Cmp) require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs)) // Move to the last block in the epoch and restart the node. diff --git a/pkg/core/headerhashes.go b/pkg/core/headerhashes.go index 7734c4694..fc69bb8f3 100644 --- a/pkg/core/headerhashes.go +++ b/pkg/core/headerhashes.go @@ -2,6 +2,7 @@ package core import ( "fmt" + "slices" "sync" lru "github.com/hashicorp/golang-lru/v2" @@ -85,7 +86,7 @@ func (h *HeaderHashes) init(dao *dao.Simple) error { headers = append(headers, blk.Hash()) hash = blk.PrevHash } - hashSliceReverse(headers) + slices.Reverse(headers) h.latest = append(h.latest, headers...) } return nil diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 23027e3d9..08934238b 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -1,11 +1,12 @@ package interop import ( + "cmp" "context" "encoding/binary" "errors" "fmt" - "sort" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/config" @@ -361,16 +362,14 @@ func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) { md.MD = desc desc.Safe = md.RequiredFlags&(callflag.All^callflag.ReadOnly) == 0 - index := sort.Search(len(c.methods), func(i int) bool { - md := c.methods[i].MD - if md.Name != desc.Name { - return md.Name >= desc.Name + index, _ := slices.BinarySearchFunc(c.methods, *md, func(e, t MethodAndPrice) int { + res := cmp.Compare(e.MD.Name, t.MD.Name) + if res != 0 { + return res } - return len(md.Parameters) > len(desc.Parameters) + return cmp.Compare(len(e.MD.Parameters), len(t.MD.Parameters)) }) - c.methods = append(c.methods, MethodAndPrice{}) - copy(c.methods[index+1:], c.methods[index:]) - c.methods[index] = *md + c.methods = slices.Insert(c.methods, index, *md) if md.ActiveFrom != nil { c.ActiveHFs[*md.ActiveFrom] = struct{}{} @@ -393,21 +392,18 @@ func (c *HFSpecificContractMD) GetMethodByOffset(offset int) (HFSpecificMethodAn // GetMethod returns method `name` with the specified number of parameters. func (c *HFSpecificContractMD) GetMethod(name string, paramCount int) (HFSpecificMethodAndPrice, bool) { - index := sort.Search(len(c.Methods), func(i int) bool { - md := c.Methods[i] - res := strings.Compare(name, md.MD.Name) - switch res { - case -1, 1: - return res == -1 - default: - return paramCount <= len(md.MD.Parameters) + index, ok := slices.BinarySearchFunc(c.Methods, HFSpecificMethodAndPrice{}, func(a, _ HFSpecificMethodAndPrice) int { + res := strings.Compare(a.MD.Name, name) + if res != 0 { + return res } + return cmp.Compare(len(a.MD.Parameters), paramCount) }) - if index < len(c.Methods) { - md := c.Methods[index] - if md.MD.Name == name && (paramCount == -1 || len(md.MD.Parameters) == paramCount) { - return md, true - } + // Exact match is possible only for specific paramCount, but if we're + // searching for _some_ method with this name (-1) we're taking the + // first one. + if ok || (index < len(c.Methods) && c.Methods[index].MD.Name == name && paramCount == -1) { + return c.Methods[index], true } return HFSpecificMethodAndPrice{}, false } @@ -426,7 +422,7 @@ func (c *ContractMD) AddEvent(md Event) { // Sort sorts interop functions by id. func Sort(fs []Function) { - sort.Slice(fs, func(i, j int) bool { return fs[i].ID < fs[j].ID }) + slices.SortFunc(fs, func(a, b Function) int { return cmp.Compare(a.ID, b.ID) }) } // GetContract returns a contract by its hash in the current interop context. @@ -436,13 +432,13 @@ func (ic *Context) GetContract(hash util.Uint160) (*state.Contract, error) { // GetFunction returns metadata for interop with the specified id. func (ic *Context) GetFunction(id uint32) *Function { - n := sort.Search(len(ic.Functions), func(i int) bool { - return ic.Functions[i].ID >= id + n, ok := slices.BinarySearchFunc(ic.Functions, Function{}, func(a, _ Function) int { + return cmp.Compare(a.ID, id) }) - if n < len(ic.Functions) && ic.Functions[n].ID == id { - return &ic.Functions[n] + if !ok { + return nil } - return nil + return &ic.Functions[n] } // BaseExecFee represents factor to multiply syscall prices with. diff --git a/pkg/core/interop/runtime/util.go b/pkg/core/interop/runtime/util.go index 39b124c7b..350962121 100644 --- a/pkg/core/interop/runtime/util.go +++ b/pkg/core/interop/runtime/util.go @@ -4,12 +4,12 @@ import ( "encoding/binary" "errors" "math/big" + "slices" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/encoding/address" - "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" @@ -108,7 +108,9 @@ func GetRandom(ic *interop.Context) error { if !ic.VM.AddGas(ic.BaseExecFee() * price) { return errors.New("gas limit exceeded") } - ic.VM.Estack().PushItem(stackitem.NewBigInteger(bigint.FromBytesUnsigned(res))) + // Resulting data is interpreted as an unsigned LE integer. + slices.Reverse(res) + ic.VM.Estack().PushItem(stackitem.NewBigInteger(new(big.Int).SetBytes(res))) return nil } diff --git a/pkg/core/interop/runtime/witness.go b/pkg/core/interop/runtime/witness.go index 09c4335d4..783e12a71 100644 --- a/pkg/core/interop/runtime/witness.go +++ b/pkg/core/interop/runtime/witness.go @@ -4,6 +4,7 @@ import ( "crypto/elliptic" "errors" "fmt" + "slices" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -79,10 +80,8 @@ func checkScope(ic *interop.Context, hash util.Uint160) (bool, error) { } if c.Scopes&transaction.CustomContracts != 0 { currentScriptHash := ic.VM.GetCurrentScriptHash() - for _, allowedContract := range c.AllowedContracts { - if allowedContract == currentScriptHash { - return true, nil - } + if slices.Contains(c.AllowedContracts, currentScriptHash) { + return true, nil } } if c.Scopes&transaction.CustomGroups != 0 { @@ -91,10 +90,8 @@ func checkScope(ic *interop.Context, hash util.Uint160) (bool, error) { return false, err } // check if the current group is the required one - for _, allowedGroup := range c.AllowedGroups { - if groups.Contains(allowedGroup) { - return true, nil - } + if slices.ContainsFunc(c.AllowedGroups, groups.Contains) { + return true, nil } } if c.Scopes&transaction.Rules != 0 { diff --git a/pkg/core/mempool/bench_test.go b/pkg/core/mempool/bench_test.go new file mode 100644 index 000000000..2775f0837 --- /dev/null +++ b/pkg/core/mempool/bench_test.go @@ -0,0 +1,62 @@ +package mempool + +import ( + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "github.com/nspcc-dev/neo-go/pkg/util" +) + +const ( + poolSize = 10000 +) + +func BenchmarkPool(b *testing.B) { + fe := &FeerStub{ + feePerByte: 1, + blockHeight: 1, + balance: 100_0000_0000, + } + txesSimple := make([]*transaction.Transaction, poolSize) + for i := range txesSimple { + txesSimple[i] = transaction.New([]byte{1, 2, 3}, 100500) + txesSimple[i].Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}} + } + txesIncFee := make([]*transaction.Transaction, poolSize) + for i := range txesIncFee { + txesIncFee[i] = transaction.New([]byte{1, 2, 3}, 100500) + txesIncFee[i].NetworkFee = 10 * int64(i) + txesIncFee[i].Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}} + } + txesMulti := make([]*transaction.Transaction, poolSize) + for i := range txesMulti { + txesMulti[i] = transaction.New([]byte{1, 2, 3}, 100500) + txesMulti[i].Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3, byte(i % 256), byte(i / 256)}}} + } + txesMultiInc := make([]*transaction.Transaction, poolSize) + for i := range txesMultiInc { + txesMultiInc[i] = transaction.New([]byte{1, 2, 3}, 100500) + txesMultiInc[i].NetworkFee = 10 * int64(i) + txesMultiInc[i].Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3, byte(i % 256), byte(i / 256)}}} + } + + senders := make(map[string][]*transaction.Transaction) + senders["one, same fee"] = txesSimple + senders["one, incr fee"] = txesIncFee + senders["many, same fee"] = txesMulti + senders["many, incr fee"] = txesMultiInc + for name, txes := range senders { + b.Run(name, func(b *testing.B) { + p := New(poolSize, 0, false, nil) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := range txes { + if p.Add(txes[j], fe) != nil { + b.Fail() + } + } + p.RemoveStale(func(*transaction.Transaction) bool { return false }, fe) + } + }) + } +} diff --git a/pkg/core/mempool/mem_pool.go b/pkg/core/mempool/mem_pool.go index 54bd31de4..b9fdbbf3c 100644 --- a/pkg/core/mempool/mem_pool.go +++ b/pkg/core/mempool/mem_pool.go @@ -84,13 +84,13 @@ type Pool struct { func (p items) Len() int { return len(p) } func (p items) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p items) Less(i, j int) bool { return p[i].CompareTo(p[j]) < 0 } +func (p items) Less(i, j int) bool { return p[i].Compare(p[j]) < 0 } -// CompareTo returns the difference between two items. +// Compare returns the difference between two items. // difference < 0 implies p < otherP. // difference = 0 implies p = otherP. // difference > 0 implies p > otherP. -func (p item) CompareTo(otherP item) int { +func (p item) Compare(otherP item) int { pHigh := p.txn.HasAttribute(transaction.HighPriority) otherHigh := otherP.txn.HasAttribute(transaction.HighPriority) if pHigh && !otherHigh { @@ -238,8 +238,18 @@ func (mp *Pool) Add(t *transaction.Transaction, fee Feer, data ...any) error { // transactions with the same priority and appending to the end of the // slice is always more efficient. n := sort.Search(len(mp.verifiedTxes), func(n int) bool { - return pItem.CompareTo(mp.verifiedTxes[n]) > 0 + return pItem.Compare(mp.verifiedTxes[n]) > 0 }) + // Changing sort.Search to slices.BinarySearchFunc() is not recommended + // above, as of Go 1.23 this results in + // cpu: AMD Ryzen 7 PRO 7840U w/ Radeon 780M Graphics + // │ pool.current │ pool.new │ + // │ sec/op │ sec/op vs base │ + // Pool/one,_same_fee-16 1.742m ± 1% 1.799m ± 1% +3.29% (p=0.000 n=10) + // Pool/one,_incr_fee-16 12.51m ± 1% 12.63m ± 2% +0.92% (p=0.023 n=10) + // Pool/many,_same_fee-16 3.100m ± 1% 3.099m ± 1% ~ (p=0.631 n=10) + // Pool/many,_incr_fee-16 14.11m ± 1% 14.20m ± 1% ~ (p=0.315 n=10) + // geomean 5.556m 5.624m +1.22% // We've reached our capacity already. if len(mp.verifiedTxes) == mp.capacity { @@ -255,6 +265,17 @@ func (mp *Pool) Add(t *transaction.Transaction, fee Feer, data ...any) error { } else { mp.verifiedTxes = append(mp.verifiedTxes, pItem) } + // While we're obviously doing slices.Insert here (and above a bit), + // code simplification is not advised since slices.Insert works + // slightly slower as of Go 1.23: + // cpu: AMD Ryzen 7 PRO 7840U w/ Radeon 780M Graphics + // │ pool.current │ pool.new2 │ + // │ sec/op │ sec/op vs base │ + // Pool/one,_same_fee-16 1.742m ± 1% 1.801m ± 2% +3.38% (p=0.000 n=10) + // Pool/one,_incr_fee-16 12.51m ± 1% 12.59m ± 2% ~ (p=0.218 n=10) + // Pool/many,_same_fee-16 3.100m ± 1% 3.134m ± 1% +1.11% (p=0.011 n=10) + // Pool/many,_incr_fee-16 14.11m ± 1% 14.09m ± 1% ~ (p=0.393 n=10) + // geomean 5.556m 5.626m +1.25% if n != len(mp.verifiedTxes)-1 { copy(mp.verifiedTxes[n+1:], mp.verifiedTxes[n:]) mp.verifiedTxes[n] = pItem @@ -351,8 +372,8 @@ func (mp *Pool) RemoveStale(isOK func(*transaction.Transaction) bool, feer Feer) // We can reuse already allocated slice // because items are iterated one-by-one in increasing order. newVerifiedTxes := mp.verifiedTxes[:0] - mp.fees = make(map[util.Uint160]utilityBalanceAndFees) // it'd be nice to reuse existing map, but we can't easily clear it - mp.conflicts = make(map[util.Uint256][]util.Uint256) + clear(mp.fees) + clear(mp.conflicts) height := feer.BlockHeight() var ( staleItems []item @@ -466,14 +487,14 @@ func (mp *Pool) TryGetData(hash util.Uint256) (any, bool) { if tx, ok := mp.verifiedMap[hash]; ok { itm := item{txn: tx} n := sort.Search(len(mp.verifiedTxes), func(n int) bool { - return itm.CompareTo(mp.verifiedTxes[n]) >= 0 + return itm.Compare(mp.verifiedTxes[n]) >= 0 }) if n < len(mp.verifiedTxes) { for i := n; i < len(mp.verifiedTxes); i++ { // items may have equal priority, so `n` is the left bound of the items which are as prioritized as the desired `itm`. if mp.verifiedTxes[i].txn.Hash() == hash { return mp.verifiedTxes[i].data, ok } - if itm.CompareTo(mp.verifiedTxes[i]) != 0 { + if itm.Compare(mp.verifiedTxes[i]) != 0 { break } } diff --git a/pkg/core/mempool/mem_pool_test.go b/pkg/core/mempool/mem_pool_test.go index e6abf6821..1bc0ead53 100644 --- a/pkg/core/mempool/mem_pool_test.go +++ b/pkg/core/mempool/mem_pool_test.go @@ -3,7 +3,7 @@ package mempool import ( "fmt" "math/big" - "sort" + "slices" "strings" "testing" "time" @@ -116,6 +116,10 @@ func TestOverCapacity(t *testing.T) { const mempoolSize = 10 mp := New(mempoolSize, 0, false, nil) + var checkPoolIsSorted = func() { + require.True(t, slices.IsSortedFunc(mp.verifiedTxes, func(a, b item) int { return -a.Compare(b) })) + } + for i := 0; i < mempoolSize; i++ { tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0) tx.Nonce = uint32(i) @@ -124,7 +128,7 @@ func TestOverCapacity(t *testing.T) { } txcnt := uint32(mempoolSize) require.Equal(t, mempoolSize, mp.Count()) - require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + checkPoolIsSorted() require.Equal(t, *uint256.NewInt(0), mp.fees[acc].feeSum) bigScript := make([]byte, 64) @@ -140,7 +144,7 @@ func TestOverCapacity(t *testing.T) { // size is ~90, networkFee is 10000 => feePerByte is 119 require.NoError(t, mp.Add(tx, fs)) require.Equal(t, mempoolSize, mp.Count()) - require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + checkPoolIsSorted() } require.Equal(t, *uint256.NewInt(10 * 10000), mp.fees[acc].feeSum) @@ -155,7 +159,7 @@ func TestOverCapacity(t *testing.T) { require.Equal(t, mempoolSize, len(mp.verifiedMap)) require.Equal(t, mempoolSize, len(mp.verifiedTxes)) require.False(t, mp.containsKey(tx.Hash())) - require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + checkPoolIsSorted() require.Equal(t, *uint256.NewInt(100000), mp.fees[acc].feeSum) // Low net fee, but higher per-byte fee is still a better combination. @@ -168,7 +172,7 @@ func TestOverCapacity(t *testing.T) { // => feePerByte is 137 (>119) require.NoError(t, mp.Add(tx, fs)) require.Equal(t, mempoolSize, mp.Count()) - require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + checkPoolIsSorted() require.Equal(t, *uint256.NewInt(9*10000 + 7000), mp.fees[acc].feeSum) // High priority always wins over low priority. @@ -180,7 +184,7 @@ func TestOverCapacity(t *testing.T) { txcnt++ require.NoError(t, mp.Add(tx, fs)) require.Equal(t, mempoolSize, mp.Count()) - require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + checkPoolIsSorted() } require.Equal(t, *uint256.NewInt(10 * 8000), mp.fees[acc].feeSum) // Good luck with low priority now. @@ -190,7 +194,7 @@ func TestOverCapacity(t *testing.T) { tx.Signers = []transaction.Signer{{Account: acc}} require.Error(t, mp.Add(tx, fs)) require.Equal(t, mempoolSize, mp.Count()) - require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + checkPoolIsSorted() } func TestGetVerified(t *testing.T) { @@ -343,18 +347,18 @@ func TestMempoolItemsOrder(t *testing.T) { tx4.Signers = []transaction.Signer{{Account: sender0}} item4 := item{txn: tx4} - require.True(t, item1.CompareTo(item2) > 0) - require.True(t, item2.CompareTo(item1) < 0) - require.True(t, item1.CompareTo(item3) > 0) - require.True(t, item3.CompareTo(item1) < 0) - require.True(t, item1.CompareTo(item4) > 0) - require.True(t, item4.CompareTo(item1) < 0) - require.True(t, item2.CompareTo(item3) > 0) - require.True(t, item3.CompareTo(item2) < 0) - require.True(t, item2.CompareTo(item4) > 0) - require.True(t, item4.CompareTo(item2) < 0) - require.True(t, item3.CompareTo(item4) > 0) - require.True(t, item4.CompareTo(item3) < 0) + require.True(t, item1.Compare(item2) > 0) + require.True(t, item2.Compare(item1) < 0) + require.True(t, item1.Compare(item3) > 0) + require.True(t, item3.Compare(item1) < 0) + require.True(t, item1.Compare(item4) > 0) + require.True(t, item4.Compare(item1) < 0) + require.True(t, item2.Compare(item3) > 0) + require.True(t, item3.Compare(item2) < 0) + require.True(t, item2.Compare(item4) > 0) + require.True(t, item4.Compare(item2) < 0) + require.True(t, item3.Compare(item4) > 0) + require.True(t, item4.Compare(item3) < 0) } func TestMempoolAddRemoveOracleResponse(t *testing.T) { diff --git a/pkg/core/mpt/batch.go b/pkg/core/mpt/batch.go index 420f2ebed..0d9d06db7 100644 --- a/pkg/core/mpt/batch.go +++ b/pkg/core/mpt/batch.go @@ -2,7 +2,7 @@ package mpt import ( "bytes" - "sort" + "slices" ) // Batch is a batch of storage changes. @@ -25,8 +25,8 @@ func MapToMPTBatch(m map[string][]byte) Batch { for k, v := range m { b.kv = append(b.kv, keyValue{strToNibbles(k), v}) // Strip storage prefix. } - sort.Slice(b.kv, func(i, j int) bool { - return bytes.Compare(b.kv[i].key, b.kv[j].key) < 0 + slices.SortFunc(b.kv, func(a, b keyValue) int { + return bytes.Compare(a.key, b.key) }) return b } diff --git a/pkg/core/mpt/trie.go b/pkg/core/mpt/trie.go index 08e9ccab4..0d86d16f0 100644 --- a/pkg/core/mpt/trie.go +++ b/pkg/core/mpt/trie.go @@ -543,7 +543,7 @@ func (t *Trie) Collapse(depth int) { panic("negative depth") } t.root = collapse(depth, t.root) - t.refcount = make(map[util.Uint256]*cachedNode) + clear(t.refcount) } func collapse(depth int, node Node) Node { diff --git a/pkg/core/mpt/trie_store.go b/pkg/core/mpt/trie_store.go index 7c7a158fb..924ea7811 100644 --- a/pkg/core/mpt/trie_store.go +++ b/pkg/core/mpt/trie_store.go @@ -21,10 +21,6 @@ type TrieStore struct { trie *Trie } -// ErrForbiddenTrieStoreOperation is returned when operation is not supposed to -// be performed over MPT-based Store. -var ErrForbiddenTrieStoreOperation = errors.New("operation is not allowed to be performed over TrieStore") - // NewTrieStore returns a new ready to use MPT-backed storage. func NewTrieStore(root util.Uint256, mode TrieMode, backed storage.Store) *TrieStore { cache, ok := backed.(*storage.MemCachedStore) @@ -37,10 +33,11 @@ func NewTrieStore(root util.Uint256, mode TrieMode, backed storage.Store) *TrieS } } -// Get implements the Store interface. +// Get implements the Store interface. It can return [errors.ErrUnsupported] +// for unsupported operations. func (m *TrieStore) Get(key []byte) ([]byte, error) { if len(key) == 0 { - return nil, fmt.Errorf("%w: Get is supported only for contract storage items", ErrForbiddenTrieStoreOperation) + return nil, fmt.Errorf("%w: Get is supported only for contract storage items", errors.ErrUnsupported) } switch storage.KeyPrefix(key[0]) { case storage.STStorage, storage.STTempStorage: @@ -51,22 +48,23 @@ func (m *TrieStore) Get(key []byte) ([]byte, error) { } return res, err default: - return nil, fmt.Errorf("%w: Get is supported only for contract storage items", ErrForbiddenTrieStoreOperation) + return nil, fmt.Errorf("%w: Get is supported only for contract storage items", errors.ErrUnsupported) } } -// PutChangeSet implements the Store interface. +// PutChangeSet implements the Store interface. It's not supported, so it +// always returns [errors.ErrUnsupported]. func (m *TrieStore) PutChangeSet(puts map[string][]byte, stor map[string][]byte) error { // Only Get and Seek should be supported, as TrieStore is read-only and is always // should be wrapped by MemCachedStore to properly support put operations (if any). - return fmt.Errorf("%w: PutChangeSet is not supported", ErrForbiddenTrieStoreOperation) + return fmt.Errorf("%w: PutChangeSet is not supported", errors.ErrUnsupported) } // Seek implements the Store interface. func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) { prefix := storage.KeyPrefix(rng.Prefix[0]) if prefix != storage.STStorage && prefix != storage.STTempStorage { // Prefix is always non-empty. - panic(fmt.Errorf("%w: Seek is supported only for contract storage items", ErrForbiddenTrieStoreOperation)) + panic(fmt.Errorf("%w: Seek is supported only for contract storage items", errors.ErrUnsupported)) } prefixP := toNibbles(rng.Prefix[1:]) fromP := []byte{} @@ -113,9 +111,10 @@ func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) { } } -// SeekGC implements the Store interface. +// SeekGC implements the Store interface. It's not supported, so it always +// returns [errors.ErrUnsupported]. func (m *TrieStore) SeekGC(rng storage.SeekRange, keep func(k, v []byte) bool) error { - return fmt.Errorf("%w: SeekGC is not supported", ErrForbiddenTrieStoreOperation) + return fmt.Errorf("%w: SeekGC is not supported", errors.ErrUnsupported) } // Close implements the Store interface. diff --git a/pkg/core/mpt/trie_store_test.go b/pkg/core/mpt/trie_store_test.go index 063d23c73..94194fabe 100644 --- a/pkg/core/mpt/trie_store_test.go +++ b/pkg/core/mpt/trie_store_test.go @@ -2,6 +2,7 @@ package mpt import ( "bytes" + "errors" "testing" "github.com/nspcc-dev/neo-go/pkg/core/storage" @@ -15,10 +16,10 @@ func TestTrieStore_TestTrieOperations(t *testing.T) { st := NewTrieStore(source.root.Hash(), ModeAll, backed) t.Run("forbidden operations", func(t *testing.T) { - require.ErrorIs(t, st.SeekGC(storage.SeekRange{}, nil), ErrForbiddenTrieStoreOperation) + require.ErrorIs(t, st.SeekGC(storage.SeekRange{}, nil), errors.ErrUnsupported) _, err := st.Get([]byte{byte(storage.STTokenTransferInfo)}) - require.ErrorIs(t, err, ErrForbiddenTrieStoreOperation) - require.ErrorIs(t, st.PutChangeSet(nil, nil), ErrForbiddenTrieStoreOperation) + require.ErrorIs(t, err, errors.ErrUnsupported) + require.ErrorIs(t, st.PutChangeSet(nil, nil), errors.ErrUnsupported) }) t.Run("Get", func(t *testing.T) { diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go index 161cdc6a5..a47fd616f 100644 --- a/pkg/core/native/crypto.go +++ b/pkg/core/native/crypto.go @@ -201,16 +201,16 @@ func curveHasherFromStackitem(si stackitem.Item, allowKeccak bool) (elliptic.Cur return elliptic.P256(), hash.Sha256, nil case int64(Secp256k1Keccak256): if !allowKeccak { - return nil, nil, errors.New("unsupported hash type") + return nil, nil, fmt.Errorf("%w: keccak hash", errors.ErrUnsupported) } return secp256k1.S256(), Keccak256, nil case int64(Secp256r1Keccak256): if !allowKeccak { - return nil, nil, errors.New("unsupported hash type") + return nil, nil, fmt.Errorf("%w: keccak hash", errors.ErrUnsupported) } return elliptic.P256(), Keccak256, nil default: - return nil, nil, errors.New("unsupported curve/hash type") + return nil, nil, fmt.Errorf("%w: unknown curve/hash", errors.ErrUnsupported) } } diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index fde08a158..b0d1f2296 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -6,7 +6,7 @@ import ( "fmt" "math" "math/big" - "sort" + "slices" "sync/atomic" "github.com/nspcc-dev/neo-go/pkg/config" @@ -397,7 +397,7 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs if si != nil { return ErrAlreadyDesignated } - sort.Sort(pubs) + slices.SortFunc(pubs, (*keys.PublicKey).Cmp) nl := NodeList(pubs) err := putConvertibleToDAO(s.ID, ic.DAO, key, &nl) diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 42871fc64..58b22a0be 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -6,8 +6,9 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "math/big" - "sort" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/config" @@ -150,13 +151,8 @@ func copyNeoCache(src, dst *NeoCache) { // 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 // container for updated gasPerBlock values. - dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock)) - copy(dst.gasPerBlock, src.gasPerBlock) - - dst.gasPerVoteCache = make(map[string]big.Int) - for k, v := range src.gasPerVoteCache { - dst.gasPerVoteCache[k] = v - } + dst.gasPerBlock = slices.Clone(src.gasPerBlock) + dst.gasPerVoteCache = maps.Clone(src.gasPerVoteCache) } // makeValidatorKey creates a key from the account script hash. @@ -376,8 +372,7 @@ func (n *NEO) InitializeCache(blockHeight uint32, d *dao.Simple) error { // nextValidators, committee and committee hash are filled in by this moment // via n.updateCache call. cache.newEpochNextValidators = cache.nextValidators.Copy() - cache.newEpochCommittee = make(keysWithVotes, len(cache.committee)) - copy(cache.newEpochCommittee, cache.committee) + cache.newEpochCommittee = slices.Clone(cache.committee) cache.newEpochCommitteeHash = cache.committeeHash } @@ -409,7 +404,7 @@ func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, blockHeight uint32 cache.committeeHash = hash.Hash160(script) nextVals := committee[:n.cfg.GetNumOfCNs(blockHeight+1)].Copy() - sort.Sort(nextVals) + slices.SortFunc(nextVals, (*keys.PublicKey).Cmp) cache.nextValidators = nextVals return nil } @@ -434,7 +429,7 @@ func (n *NEO) updateCachedNewEpochValues(d *dao.Simple, cache *NeoCache, blockHe cache.newEpochCommitteeHash = hash.Hash160(script) nextVals := committee[:numOfCNs].Copy() - sort.Sort(nextVals) + slices.SortFunc(nextVals, (*keys.PublicKey).Cmp) cache.newEpochNextValidators = nextVals return nil } @@ -1032,23 +1027,23 @@ func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool, maxNum int) ([]keyWit // sortByKey assumes to sort by serialized key bytes (that's the way keys // are stored and retrieved from the storage by default). Otherwise, need // to sort using big.Int comparator. - sort.Slice(arr, func(i, j int) bool { + slices.SortFunc(arr, func(a, b keyWithVotes) int { // The most-voted validators should end up in the front of the list. - cmp := arr[i].Votes.Cmp(arr[j].Votes) + cmp := b.Votes.Cmp(a.Votes) if cmp != 0 { - return cmp > 0 + return cmp } // Ties are broken with deserialized public keys. // Sort by ECPoint's (X, Y) components: compare X first, and then compare Y. - cmpX := strings.Compare(arr[i].Key[1:], arr[j].Key[1:]) + cmpX := strings.Compare(a.Key[1:], b.Key[1:]) if cmpX != 0 { - return cmpX == -1 + return cmpX } // The case when X components are the same is extremely rare, thus we perform // key deserialization only if needed. No error can occur. - ki, _ := keys.NewPublicKeyFromBytes([]byte(arr[i].Key), elliptic.P256()) - kj, _ := keys.NewPublicKeyFromBytes([]byte(arr[j].Key), elliptic.P256()) - return ki.Y.Cmp(kj.Y) == -1 + ka, _ := keys.NewPublicKeyFromBytes([]byte(a.Key), elliptic.P256()) + kb, _ := keys.NewPublicKeyFromBytes([]byte(b.Key), elliptic.P256()) + return ka.Y.Cmp(kb.Y) }) } return arr, nil @@ -1176,7 +1171,7 @@ func (n *NEO) ComputeNextBlockValidators(d *dao.Simple) keys.PublicKeys { func (n *NEO) getCommittee(ic *interop.Context, _ []stackitem.Item) stackitem.Item { pubs := n.GetCommitteeMembers(ic.DAO) - sort.Sort(pubs) + slices.SortFunc(pubs, (*keys.PublicKey).Cmp) return pubsToArray(pubs) } diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 0e0dbd10d..9bd7119b8 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -2,7 +2,7 @@ package native_test import ( "math/big" - "sort" + "slices" "testing" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" @@ -602,9 +602,7 @@ func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) { require.NoError(t, err) } // Sort private keys by their public keys. - sort.Slice(pks, func(i, j int) bool { - return pks[i].PublicKey().Cmp(pks[j].PublicKey()) < 0 - }) + slices.SortFunc(pks, func(a, b *keys.PrivateKey) int { return a.PublicKey().Cmp(b.PublicKey()) }) // Firstly, we need to build the N3 multisig account address based on the users' public keys. // Pubs must be sorted, exactly like for the standard CheckMultisig. diff --git a/pkg/core/native/native_test/designate_test.go b/pkg/core/native/native_test/designate_test.go index 2c89f9fe8..e599ab2de 100644 --- a/pkg/core/native/native_test/designate_test.go +++ b/pkg/core/native/native_test/designate_test.go @@ -1,7 +1,7 @@ package native_test import ( - "sort" + "slices" "testing" "github.com/nspcc-dev/neo-go/pkg/config" @@ -157,6 +157,6 @@ func TestDesignate_GenesisRolesExtension(t *testing.T) { c := e.CommitteeInvoker(e.NativeHash(t, nativenames.Designation)) // Check designated node in a separate block. - sort.Sort(pubs) + slices.SortFunc(pubs, (*keys.PublicKey).Cmp) checkNodeRoles(t, c, true, noderoles.StateValidator, e.Chain.BlockHeight()+1, pubs) } diff --git a/pkg/core/native/native_test/management_test.go b/pkg/core/native/native_test/management_test.go index 9870e81f0..546b7f923 100644 --- a/pkg/core/native/native_test/management_test.go +++ b/pkg/core/native/native_test/management_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "slices" "testing" 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) { badManifest := cs1.Manifest - badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) - copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) + badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods) badManifest.ABI.Methods[0].Offset = 100500 // out of bounds manifB, err := json.Marshal(&badManifest) 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) { var badManifest = cs1.Manifest - badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) - copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) + badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods) badManifest.ABI.Methods[0].Offset = len(cs1.NEF.Script) - 2 // Ends with `CALLT(X,X);RET`. 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) { badManifest := cs1.Manifest - badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) - copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) + badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods) badManifest.ABI.Methods[0] = badManifest.ABI.Methods[1] // duplicates manifB, err := json.Marshal(&badManifest) 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) { badManifest := cs1.Manifest - badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) - copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) + badManifest.ABI.Methods = slices.Clone(cs1.Manifest.ABI.Methods) badManifest.ABI.Events = []manifest.Event{{Name: "event"}, {Name: "event"}} // duplicates manifB, err := json.Marshal(&badManifest) require.NoError(t, err) diff --git a/pkg/core/native/native_test/neo_test.go b/pkg/core/native/native_test/neo_test.go index 7f9fb924a..f5e336df4 100644 --- a/pkg/core/native/native_test/neo_test.go +++ b/pkg/core/native/native_test/neo_test.go @@ -6,7 +6,7 @@ import ( "fmt" "math" "math/big" - "sort" + "slices" "strings" "testing" @@ -204,7 +204,7 @@ func TestNEO_Vote(t *testing.T) { standBySorted, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee) require.NoError(t, err) standBySorted = standBySorted[:validatorsCount] - sort.Sort(standBySorted) + slices.SortFunc(standBySorted, (*keys.PublicKey).Cmp) pubs := e.Chain.ComputeNextBlockValidators() require.Equal(t, standBySorted, keys.PublicKeys(pubs)) @@ -269,7 +269,7 @@ func TestNEO_Vote(t *testing.T) { for i := range candidates[:validatorsCount] { sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PublicKey() } - sort.Sort(sortedCandidates) + slices.SortFunc(sortedCandidates, (*keys.PublicKey).Cmp) require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs)) pubs, err = neoCommitteeInvoker.Chain.GetNextBlockValidators() @@ -403,7 +403,7 @@ func TestNEO_GetCommitteeAddress(t *testing.T) { e := neoValidatorInvoker.Executor standByCommitteePublicKeys, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee) require.NoError(t, err) - sort.Sort(standByCommitteePublicKeys) + slices.SortFunc(standByCommitteePublicKeys, (*keys.PublicKey).Cmp) expectedCommitteeAddress, err := smartcontract.CreateMajorityMultiSigRedeemScript(standByCommitteePublicKeys) require.NoError(t, err) stack, err := neoValidatorInvoker.TestInvoke(t, "getCommitteeAddress") @@ -811,8 +811,8 @@ func TestNEO_GetCandidates(t *testing.T) { }) neoCommitteeInvoker.Invoke(t, v, "getCandidateVote", pub) } - sort.Slice(expected, func(i, j int) bool { - return bytes.Compare(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), expected[j].Value().([]stackitem.Item)[0].Value().([]byte)) < 0 + slices.SortFunc(expected, func(a, b stackitem.Item) int { + return bytes.Compare(a.Value().([]stackitem.Item)[0].Value().([]byte), b.Value().([]stackitem.Item)[0].Value().([]byte)) }) neoCommitteeInvoker.Invoke(t, stackitem.NewArray(expected), "getCandidates") diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index 0591fe7b4..be2f9de50 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -3,8 +3,9 @@ package native import ( "encoding/hex" "fmt" + "maps" "math/big" - "sort" + "slices" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core/dao" @@ -91,12 +92,8 @@ func (c *PolicyCache) Copy() dao.NativeContractCache { func copyPolicyCache(src, dst *PolicyCache) { *dst = *src - dst.attributeFee = make(map[transaction.AttrType]uint32, len(src.attributeFee)) - for t, v := range src.attributeFee { - dst.attributeFee[t] = v - } - dst.blockedAccounts = make([]util.Uint160, len(src.blockedAccounts)) - copy(dst.blockedAccounts, src.blockedAccounts) + dst.attributeFee = maps.Clone(src.attributeFee) + dst.blockedAccounts = slices.Clone(src.blockedAccounts) } // newPolicy returns Policy native contract. @@ -329,14 +326,7 @@ func (p *Policy) IsBlocked(dao *dao.Simple, hash util.Uint160) bool { // of the blocked account in the blocked accounts list (or the position it should be // put at). func (p *Policy) isBlockedInternal(roCache *PolicyCache, hash util.Uint160) (int, bool) { - length := len(roCache.blockedAccounts) - i := sort.Search(length, func(i int) bool { - return !roCache.blockedAccounts[i].Less(hash) - }) - if length != 0 && i != length && roCache.blockedAccounts[i].Equals(hash) { - return i, true - } - return i, false + return slices.BinarySearchFunc(roCache.blockedAccounts, hash, util.Uint160.Compare) } func (p *Policy) getStoragePrice(ic *interop.Context, _ []stackitem.Item) stackitem.Item { diff --git a/pkg/core/native/std.go b/pkg/core/native/std.go index bd5a3ed17..453c441ef 100644 --- a/pkg/core/native/std.go +++ b/pkg/core/native/std.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "math/big" + "slices" "strings" "unicode/utf8" @@ -19,7 +20,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" - "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -241,7 +241,7 @@ func (s *Std) itoa(_ *interop.Context, args []stackitem.Item) stackitem.Item { break } bs := bigint.ToBytes(num) - slice.Reverse(bs) + slices.Reverse(bs) str = hex.EncodeToString(bs) if pad := bs[0] & 0xF8; pad == 0 || pad == 0xF8 { str = str[1:] @@ -288,7 +288,7 @@ func (s *Std) atoi(_ *interop.Context, args []stackitem.Item) stackitem.Item { if changed && bs[0]&0x8 != 0 { bs[0] |= 0xF0 } - slice.Reverse(bs) + slices.Reverse(bs) bi = bigint.FromBytes(bs) default: panic(ErrInvalidBase) diff --git a/pkg/core/statesync/mptpool.go b/pkg/core/statesync/mptpool.go index 819188246..c969b8ccd 100644 --- a/pkg/core/statesync/mptpool.go +++ b/pkg/core/statesync/mptpool.go @@ -2,7 +2,7 @@ package statesync import ( "bytes" - "sort" + "slices" "sync" "github.com/nspcc-dev/neo-go/pkg/util" @@ -38,9 +38,7 @@ func (mp *Pool) TryGet(hash util.Uint256) ([][]byte, bool) { paths, ok := mp.hashes[hash] // need to copy here, because we can modify existing array of paths inside the pool. - res := make([][]byte, len(paths)) - copy(res, paths) - return res, ok + return slices.Clone(paths), ok } // GetAll returns all MPT nodes with the corresponding paths from the pool. @@ -95,11 +93,9 @@ func (mp *Pool) Update(remove map[util.Uint256][][]byte, add map[util.Uint256][] for h, paths := range remove { old := mp.hashes[h] for _, path := range paths { - i := sort.Search(len(old), func(i int) bool { - return bytes.Compare(old[i], path) >= 0 - }) - if i < len(old) && bytes.Equal(old[i], path) { - old = append(old[:i], old[i+1:]...) + i, found := slices.BinarySearchFunc(old, path, bytes.Compare) + if found { + old = slices.Delete(old, i, i+1) } } if len(old) == 0 { @@ -117,18 +113,12 @@ func (mp *Pool) Update(remove map[util.Uint256][][]byte, add map[util.Uint256][] func (mp *Pool) addPaths(nodeHash util.Uint256, paths [][]byte) { old := mp.hashes[nodeHash] for _, path := range paths { - i := sort.Search(len(old), func(i int) bool { - return bytes.Compare(old[i], path) >= 0 - }) - if i < len(old) && bytes.Equal(old[i], path) { + i, found := slices.BinarySearchFunc(old, path, bytes.Compare) + if found { // then path is already added continue } - old = append(old, path) - if i != len(old)-1 { - copy(old[i+1:], old[i:]) - old[i] = path - } + old = slices.Insert(old, i, path) } mp.hashes[nodeHash] = old } diff --git a/pkg/core/storage/memcached_store.go b/pkg/core/storage/memcached_store.go index ad476ad3f..70bd48f7b 100644 --- a/pkg/core/storage/memcached_store.go +++ b/pkg/core/storage/memcached_store.go @@ -3,7 +3,7 @@ package storage import ( "bytes" "context" - "sort" + "slices" "strings" "sync" ) @@ -230,13 +230,11 @@ func (s *MemCachedStore) prepareSeekMemSnapshot(rng SeekRange) (Store, []KeyValu // seeking from some point is supported with corresponding `rng` field set. func performSeek(ctx context.Context, ps Store, memRes []KeyValueExists, rng SeekRange, cutPrefix bool, f func(k, v []byte) bool) { lPrefix := len(string(rng.Prefix)) - less := func(k1, k2 []byte) bool { - res := bytes.Compare(k1, k2) - return res != 0 && rng.Backwards == (res > 0) - } + var cmpFunc = getCmpFunc(rng.Backwards) + // Sort memRes items for further comparison with ps items. - sort.Slice(memRes, func(i, j int) bool { - return less(memRes[i].Key, memRes[j].Key) + slices.SortFunc(memRes, func(a, b KeyValueExists) int { + return cmpFunc(a.Key, b.Key) }) var ( @@ -266,7 +264,7 @@ func performSeek(ctx context.Context, ps Store, memRes []KeyValueExists, rng See done = true return false default: - var isMem = haveMem && less(kvMem.Key, kvPs.Key) + var isMem = haveMem && cmpFunc(kvMem.Key, kvPs.Key) < 0 if isMem { if kvMem.Exists { if cutPrefix { diff --git a/pkg/core/storage/memcached_store_test.go b/pkg/core/storage/memcached_store_test.go index 0f2defe65..497add2d8 100644 --- a/pkg/core/storage/memcached_store_test.go +++ b/pkg/core/storage/memcached_store_test.go @@ -3,7 +3,7 @@ package storage import ( "bytes" "fmt" - "sort" + "slices" "testing" "github.com/nspcc-dev/neo-go/internal/random" @@ -424,8 +424,8 @@ func TestCachedSeekSorting(t *testing.T) { }) assert.Equal(t, len(foundKVs), len(lowerKVs)+len(updatedKVs)) expected := append(lowerKVs, updatedKVs...) - sort.Slice(expected, func(i, j int) bool { - return bytes.Compare(expected[i].Key, expected[j].Key) < 0 + slices.SortFunc(expected, func(a, b KeyValue) int { + return bytes.Compare(a.Key, b.Key) }) require.Equal(t, expected, foundKVs) } diff --git a/pkg/core/storage/memory_store.go b/pkg/core/storage/memory_store.go index 84a49e366..e4e8c20d6 100644 --- a/pkg/core/storage/memory_store.go +++ b/pkg/core/storage/memory_store.go @@ -2,7 +2,7 @@ package storage import ( "bytes" - "sort" + "slices" "strings" "sync" ) @@ -107,10 +107,7 @@ func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool, lock func(), return strings.HasPrefix(key, sPrefix) && (lStart == 0 || strings.Compare(key[lPrefix:], sStart) <= 0) } } - less := func(k1, k2 []byte) bool { - res := bytes.Compare(k1, k2) - return res != 0 && rng.Backwards == (res > 0) - } + var cmpFunc = getCmpFunc(rng.Backwards) lock() m := s.chooseMap(rng.Prefix) @@ -123,8 +120,8 @@ func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool, lock func(), } } unlock() - sort.Slice(memList, func(i, j int) bool { - return less(memList[i].Key, memList[j].Key) + slices.SortFunc(memList, func(a, b KeyValue) int { + return cmpFunc(a.Key, b.Key) }) for _, kv := range memList { if !f(kv.Key, kv.Value) { @@ -133,6 +130,13 @@ func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool, lock func(), } } +func getCmpFunc(backwards bool) func(a, b []byte) int { + if !backwards { + return bytes.Compare + } + return func(a, b []byte) int { return -bytes.Compare(a, b) } +} + // Close implements Store interface and clears up memory. Never returns an // error. func (s *MemoryStore) Close() error { diff --git a/pkg/core/storage/storeandbatch_test.go b/pkg/core/storage/storeandbatch_test.go index 7c5f64325..cb670e2c5 100644 --- a/pkg/core/storage/storeandbatch_test.go +++ b/pkg/core/storage/storeandbatch_test.go @@ -4,7 +4,7 @@ import ( "bytes" "reflect" "runtime" - "sort" + "slices" "testing" "github.com/stretchr/testify/assert" @@ -49,15 +49,10 @@ func testStoreSeek(t *testing.T, s Store) { kvs := pushSeekDataSet(t, s) check := func(t *testing.T, goodprefix, start []byte, goodkvs []KeyValue, backwards bool, cont func(k, v []byte) bool) { // Seek result expected to be sorted in an ascending (for forwards seeking) or descending (for backwards seeking) way. - cmpFunc := func(i, j int) bool { - return bytes.Compare(goodkvs[i].Key, goodkvs[j].Key) < 0 - } - if backwards { - cmpFunc = func(i, j int) bool { - return bytes.Compare(goodkvs[i].Key, goodkvs[j].Key) > 0 - } - } - sort.Slice(goodkvs, cmpFunc) + var cmpFunc = getCmpFunc(backwards) + slices.SortFunc(goodkvs, func(a, b KeyValue) int { + return cmpFunc(a.Key, b.Key) + }) rng := SeekRange{ Prefix: goodprefix, diff --git a/pkg/core/transaction/signer.go b/pkg/core/transaction/signer.go index a4290b66b..be2781767 100644 --- a/pkg/core/transaction/signer.go +++ b/pkg/core/transaction/signer.go @@ -3,6 +3,7 @@ package transaction import ( "errors" "math/big" + "slices" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/io" @@ -93,10 +94,7 @@ func (c *Signer) Copy() *Signer { return nil } cp := *c - if c.AllowedContracts != nil { - cp.AllowedContracts = make([]util.Uint160, len(c.AllowedContracts)) - copy(cp.AllowedContracts, c.AllowedContracts) - } + cp.AllowedContracts = slices.Clone(c.AllowedContracts) cp.AllowedGroups = keys.PublicKeys(c.AllowedGroups).Copy() if c.Rules != nil { cp.Rules = make([]WitnessRule, len(c.Rules)) diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 443e75efa..a11285e42 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -14,6 +14,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/util/bitfield" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -428,14 +429,14 @@ func (t *Transaction) isValid() error { } } } - attrs := map[AttrType]bool{} + var attrBits = bitfield.New(256) for i := range t.Attributes { typ := t.Attributes[i].Type if !typ.allowMultiple() { - if attrs[typ] { + if attrBits.IsSet(int(typ)) { return fmt.Errorf("%w: multiple '%s' attributes", ErrInvalidAttribute, typ.String()) } - attrs[typ] = true + attrBits.Set(int(typ)) } } if len(t.Script) == 0 { diff --git a/pkg/core/util.go b/pkg/core/util.go index 196a2c2f4..7d2a07f87 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -115,10 +115,3 @@ func getCommitteeAddress(committee []*keys.PublicKey) (val util.Uint160, err err } return hash.Hash160(raw), nil } - -// hashSliceReverse reverses the given slice of util.Uint256. -func hashSliceReverse(dest []util.Uint256) { - for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 { - dest[i], dest[j] = dest[j], dest[i] - } -} diff --git a/pkg/crypto/keys/nep2.go b/pkg/crypto/keys/nep2.go index dd4ab206d..f0c92eaa5 100644 --- a/pkg/crypto/keys/nep2.go +++ b/pkg/crypto/keys/nep2.go @@ -7,7 +7,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/encoding/base58" - "github.com/nspcc-dev/neo-go/pkg/util/slice" "golang.org/x/crypto/scrypt" "golang.org/x/text/unicode/norm" ) @@ -53,32 +52,28 @@ func NEP2Encrypt(priv *PrivateKey, passphrase string, params ScryptParams) (s st if err != nil { return s, err } - defer slice.Clean(derivedKey) + defer clear(derivedKey) derivedKey1 := derivedKey[:32] derivedKey2 := derivedKey[32:] privBytes := priv.Bytes() - defer slice.Clean(privBytes) + defer clear(privBytes) xr := xor(privBytes, derivedKey1) - defer slice.Clean(xr) + defer clear(xr) encrypted, err := aesEncrypt(xr, derivedKey2) if err != nil { return s, err } - buf := new(bytes.Buffer) - buf.Write(nepHeader) - buf.WriteByte(nepFlag) - buf.Write(addrHash) - buf.Write(encrypted) + var buf = make([]byte, 0, len(nepHeader)+1+len(addrHash)+len(encrypted)) + buf = append(buf, nepHeader...) + buf = append(buf, nepFlag) + buf = append(buf, addrHash...) + buf = append(buf, encrypted...) - if buf.Len() != 39 { - return s, fmt.Errorf("invalid buffer length: expecting 39 bytes got %d", buf.Len()) - } - - return base58.CheckEncode(buf.Bytes()), nil + return base58.CheckEncode(buf), nil } // NEP2Decrypt decrypts an encrypted key using the given passphrase @@ -99,7 +94,7 @@ func NEP2Decrypt(key, passphrase string, params ScryptParams) (*PrivateKey, erro if err != nil { return nil, err } - defer slice.Clean(derivedKey) + defer clear(derivedKey) derivedKey1 := derivedKey[:32] derivedKey2 := derivedKey[32:] @@ -109,10 +104,10 @@ func NEP2Decrypt(key, passphrase string, params ScryptParams) (*PrivateKey, erro if err != nil { return nil, err } - defer slice.Clean(decrypted) + defer clear(decrypted) privBytes := xor(decrypted, derivedKey1) - defer slice.Clean(privBytes) + defer clear(privBytes) // Rebuild the private key. privKey, err := NewPrivateKeyFromBytes(privBytes) diff --git a/pkg/crypto/keys/private_key.go b/pkg/crypto/keys/private_key.go index 541c3c42e..e0d876655 100644 --- a/pkg/crypto/keys/private_key.go +++ b/pkg/crypto/keys/private_key.go @@ -13,7 +13,6 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/rfc6979" ) @@ -49,7 +48,7 @@ func NewPrivateKeyFromHex(str string) (*PrivateKey, error) { if err != nil { return nil, err } - defer slice.Clean(b) + defer clear(b) return NewPrivateKeyFromBytes(b) } @@ -111,7 +110,7 @@ func NewPrivateKeyFromWIF(wif string) (*PrivateKey, error) { // https://en.bitcoin.it/wiki/Wallet_import_format func (p *PrivateKey) WIF() string { pb := p.Bytes() - defer slice.Clean(pb) + defer clear(pb) w, err := WIFEncode(pb, WIFVersion, true) // The only way WIFEncode() can fail is if we're to give it a key of // wrong size, but we have a proper key here, aren't we? @@ -124,10 +123,7 @@ func (p *PrivateKey) WIF() string { // Destroy wipes the contents of the private key from memory. Any operations // with the key after call to Destroy have undefined behavior. func (p *PrivateKey) Destroy() { - bits := p.D.Bits() - for i := range bits { - bits[i] = 0 - } + clear(p.D.Bits()) } // Address derives the public NEO address that is coupled with the private key, and diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index 774623456..3bce10de9 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "math/big" + "slices" "github.com/decred/dcrd/dcrec/secp256k1/v4" lru "github.com/hashicorp/golang-lru/v2" @@ -70,23 +71,13 @@ func (keys *PublicKeys) Bytes() []byte { // Contains checks whether the passed param is contained in PublicKeys. func (keys PublicKeys) Contains(pKey *PublicKey) bool { - for _, key := range keys { - if key.Equal(pKey) { - return true - } - } - return false + return slices.ContainsFunc(keys, pKey.Equal) } // 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. func (keys PublicKeys) Copy() PublicKeys { - if keys == nil { - return nil - } - res := make(PublicKeys, len(keys)) - copy(res, keys) - return res + return slices.Clone(keys) } // Unique returns a set of public keys. @@ -161,7 +152,7 @@ func (p *PublicKey) getBytes(compressed bool) []byte { if compressed { return elliptic.MarshalCompressed(p.Curve, p.X, p.Y) } - return elliptic.Marshal(p.Curve, p.X, p.Y) + return elliptic.Marshal(p.Curve, p.X, p.Y) //nolint:staticcheck // We don't care about ECDH, but UncompressedBytes() should still work. } // Bytes returns byte array representation of the public key in compressed diff --git a/pkg/crypto/keys/publickey_test.go b/pkg/crypto/keys/publickey_test.go index 1f9e5bba9..6fa70fd54 100644 --- a/pkg/crypto/keys/publickey_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "encoding/json" "math/rand" + "slices" "sort" "testing" @@ -145,8 +146,7 @@ func TestSort(t *testing.T) { pubs1[i] = priv.PublicKey() } - pubs2 := make(PublicKeys, len(pubs1)) - copy(pubs2, pubs1) + pubs2 := slices.Clone(pubs1) sort.Sort(pubs1) diff --git a/pkg/crypto/keys/wif.go b/pkg/crypto/keys/wif.go index 1ec908cdd..67689cced 100644 --- a/pkg/crypto/keys/wif.go +++ b/pkg/crypto/keys/wif.go @@ -1,11 +1,9 @@ package keys import ( - "bytes" "fmt" "github.com/nspcc-dev/neo-go/pkg/encoding/base58" - "github.com/nspcc-dev/neo-go/pkg/util/slice" ) const ( @@ -37,14 +35,14 @@ func WIFEncode(key []byte, version byte, compressed bool) (s string, err error) return s, fmt.Errorf("invalid private key length: %d", len(key)) } - buf := new(bytes.Buffer) - buf.WriteByte(version) - buf.Write(key) + var buf = make([]byte, 0, 1+len(key)+1) + buf = append(buf, version) + buf = append(buf, key...) if compressed { - buf.WriteByte(0x01) + buf = append(buf, 0x01) } - s = base58.CheckEncode(buf.Bytes()) + s = base58.CheckEncode(buf) return } @@ -54,7 +52,7 @@ func WIFDecode(wif string, version byte) (*WIF, error) { if err != nil { return nil, err } - defer slice.Clean(b) + defer clear(b) if version == 0x00 { version = WIFVersion diff --git a/pkg/encoding/bigint/bigint.go b/pkg/encoding/bigint/bigint.go index 8274bb684..58d74b255 100644 --- a/pkg/encoding/bigint/bigint.go +++ b/pkg/encoding/bigint/bigint.go @@ -4,8 +4,7 @@ import ( "math" "math/big" "math/bits" - - "github.com/nspcc-dev/neo-go/pkg/util/slice" + "slices" ) const ( @@ -17,12 +16,6 @@ const ( var bigOne = big.NewInt(1) -// FromBytesUnsigned converts data in little-endian format to an unsigned integer. -func FromBytesUnsigned(data []byte) *big.Int { - bs := slice.CopyReverse(data) - return new(big.Int).SetBytes(bs) -} - // FromBytes converts data in little-endian format to // an integer. func FromBytes(data []byte) *big.Int { @@ -148,7 +141,7 @@ func ToPreallocatedBytes(n *big.Int, data []byte) []byte { data = data[:lb] } _ = n.FillBytes(data) - slice.Reverse(data) + slices.Reverse(data) if sign == -1 { for i := range data { diff --git a/pkg/encoding/bigint/bigint_test.go b/pkg/encoding/bigint/bigint_test.go index 39c40d666..56048c253 100644 --- a/pkg/encoding/bigint/bigint_test.go +++ b/pkg/encoding/bigint/bigint_test.go @@ -3,9 +3,9 @@ package bigint import ( "math" "math/big" + "slices" "testing" - "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -128,31 +128,6 @@ func TestBytesToInt(t *testing.T) { }) } -var unsignedCases = []struct { - number int64 - buf []byte -}{ - {0xff00000000, []byte{0x00, 0x00, 0x00, 0x00, 0xff}}, - {0xfd00000000, []byte{0x00, 0x00, 0x00, 0x00, 0xfd}}, - {0x8000000000, []byte{0x00, 0x00, 0x00, 0x00, 0x80}}, - {0xff0200000000, []byte{0x00, 0x00, 0x00, 0x00, 0x02, 0xff}}, - {0xff0100000000, []byte{0x00, 0x00, 0x00, 0x00, 0x01, 0xff}}, - {0xff0100000000, []byte{0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00}}, -} - -func TestBytesToUnsigned(t *testing.T) { - for _, tc := range testCases { - if tc.number > 0 { - num := FromBytesUnsigned(tc.buf) - assert.Equal(t, tc.number, num.Int64(), "expected %x, got %x", tc.number, num.Int64()) - } - } - for _, tc := range unsignedCases { - num := FromBytesUnsigned(tc.buf) - assert.Equal(t, tc.number, num.Int64(), "expected %x, got %x", tc.number, num.Int64()) - } -} - func TestEquivalentRepresentations(t *testing.T) { for _, tc := range testCases { buf := tc.buf @@ -210,7 +185,9 @@ func TestVeryBigInts(t *testing.T) { num, ok := new(big.Int).SetString(tc.numStr, 10) assert.True(t, ok) - result := FromBytes(slice.CopyReverse(tc.buf)) + revb := slices.Clone(tc.buf) + slices.Reverse(revb) + result := FromBytes(revb) assert.Equal(t, num, result, "error while converting %s from bytes", tc.numStr) } } diff --git a/pkg/encoding/fixedn/fixed8.go b/pkg/encoding/fixedn/fixed8.go index ad28d5133..46adfeb21 100644 --- a/pkg/encoding/fixedn/fixed8.go +++ b/pkg/encoding/fixedn/fixed8.go @@ -1,6 +1,7 @@ package fixedn import ( + "cmp" "strconv" "strings" @@ -158,10 +159,10 @@ func (f Fixed8) Equal(g Fixed8) bool { return f == g } -// CompareTo returns the difference between the f and g. -// difference < 0 implies f < g. -// difference = 0 implies f = g. -// difference > 0 implies f > g. -func (f Fixed8) CompareTo(g Fixed8) int { - return int(f - g) +// Compare performs three-way comparison between f and g. +// - -1 implies f < g. +// - 0 implies f = g. +// - 1 implies f > g. +func (f Fixed8) Compare(g Fixed8) int { + return cmp.Compare(f, g) } diff --git a/pkg/encoding/fixedn/fixed8_test.go b/pkg/encoding/fixedn/fixed8_test.go index db94c3062..283374177 100644 --- a/pkg/encoding/fixedn/fixed8_test.go +++ b/pkg/encoding/fixedn/fixed8_test.go @@ -164,8 +164,8 @@ func TestFixed8_Arith(t *testing.T) { assert.True(t, u1.LessThan(u2)) assert.True(t, u2.GreaterThan(u1)) assert.True(t, u1.Equal(u1)) - assert.NotZero(t, u1.CompareTo(u2)) - assert.Zero(t, u1.CompareTo(u1)) + assert.NotZero(t, u1.Compare(u2)) + assert.Zero(t, u1.Compare(u1)) assert.EqualValues(t, Fixed8(2), u2.Div(3)) } diff --git a/pkg/interop/go.mod b/pkg/interop/go.mod index 0d22c16d4..eeda448b6 100644 --- a/pkg/interop/go.mod +++ b/pkg/interop/go.mod @@ -1,3 +1,3 @@ module github.com/nspcc-dev/neo-go/pkg/interop -go 1.20 +go 1.21 diff --git a/pkg/neotest/chain/chain.go b/pkg/neotest/chain/chain.go index 5d0fce09c..ad5b0ecfb 100644 --- a/pkg/neotest/chain/chain.go +++ b/pkg/neotest/chain/chain.go @@ -2,7 +2,7 @@ package chain import ( "encoding/hex" - "sort" + "slices" "testing" "time" @@ -103,12 +103,12 @@ func init() { standByCommittee[5] = pubs[5].StringCompressed() multiValidatorAcc = make([]*wallet.Account, 4) - sort.Sort(pubs[:4]) + slices.SortFunc(pubs[:4], (*keys.PublicKey).Cmp) - sort.Slice(accs[:4], func(i, j int) bool { - p1 := accs[i].PublicKey() - p2 := accs[j].PublicKey() - return p1.Cmp(p2) == -1 + slices.SortFunc(accs[:4], func(a, b *wallet.Account) int { + pa := a.PublicKey() + pb := b.PublicKey() + return pa.Cmp(pb) }) for i := range multiValidatorAcc { multiValidatorAcc[i] = wallet.NewAccountFromPrivateKey(accs[i].PrivateKey()) @@ -119,12 +119,12 @@ func init() { } multiCommitteeAcc = make([]*wallet.Account, len(committeeWIFs)) - sort.Sort(pubs) + slices.SortFunc(pubs, (*keys.PublicKey).Cmp) - sort.Slice(accs, func(i, j int) bool { - p1 := accs[i].PublicKey() - p2 := accs[j].PublicKey() - return p1.Cmp(p2) == -1 + slices.SortFunc(accs, func(a, b *wallet.Account) int { + pa := a.PublicKey() + pb := b.PublicKey() + return pa.Cmp(pb) }) for i := range multiCommitteeAcc { multiCommitteeAcc[i] = wallet.NewAccountFromPrivateKey(accs[i].PrivateKey()) diff --git a/pkg/neotest/signer.go b/pkg/neotest/signer.go index a8793cc6a..b532b461f 100644 --- a/pkg/neotest/signer.go +++ b/pkg/neotest/signer.go @@ -3,7 +3,7 @@ package neotest import ( "bytes" "fmt" - "sort" + "slices" "testing" "github.com/nspcc-dev/neo-go/pkg/config/netmode" @@ -106,10 +106,10 @@ func NewMultiSigner(accs ...*wallet.Account) MultiSigner { panic(fmt.Sprintf("verification script requires %d signatures, "+ "but only %d accounts were provided", m, len(accs))) } - sort.Slice(accs, func(i, j int) bool { - p1 := accs[i].PublicKey() - p2 := accs[j].PublicKey() - return p1.Cmp(p2) == -1 + slices.SortFunc(accs, func(a, b *wallet.Account) int { + pa := a.PublicKey() + pb := b.PublicKey() + return pa.Cmp(pb) }) for _, acc := range accs { if !bytes.Equal(script, acc.Contract.Script) { diff --git a/pkg/neotest/signer_test.go b/pkg/neotest/signer_test.go index 0f14a1512..a40e6a797 100644 --- a/pkg/neotest/signer_test.go +++ b/pkg/neotest/signer_test.go @@ -1,7 +1,7 @@ package neotest import ( - "sort" + "slices" "testing" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -31,7 +31,7 @@ func TestMultiSigner(t *testing.T) { pubs[i] = a.PublicKey() } - sort.Sort(pubs) + slices.SortFunc(pubs, (*keys.PublicKey).Cmp) m := smartcontract.GetDefaultHonestNodeCount(size) for i := range accs { require.NoError(t, accs[i].ConvertMultisig(m, pubs)) diff --git a/pkg/network/discovery_test.go b/pkg/network/discovery_test.go index c27dc5c5d..ad29aed81 100644 --- a/pkg/network/discovery_test.go +++ b/pkg/network/discovery_test.go @@ -3,7 +3,7 @@ package network import ( "errors" "net" - "sort" + "slices" "sync/atomic" "testing" "time" @@ -91,7 +91,7 @@ func TestDefaultDiscoverer(t *testing.T) { tryMaxWait = 1 // Don't waste time. var set1 = []string{"1.1.1.1:10333", "2.2.2.2:10333"} - sort.Strings(set1) + slices.Sort(set1) // Added addresses should end up in the pool and in the unconnected set. // Done twice to check re-adding unconnected addresses, which should be @@ -100,7 +100,7 @@ func TestDefaultDiscoverer(t *testing.T) { d.BackFill(set1...) assert.Equal(t, len(set1), d.PoolCount()) set1D := d.UnconnectedPeers() - sort.Strings(set1D) + slices.Sort(set1D) assert.Equal(t, 0, len(d.GoodPeers())) assert.Equal(t, 0, len(d.BadPeers())) require.Equal(t, set1, set1D) @@ -120,7 +120,7 @@ func TestDefaultDiscoverer(t *testing.T) { } } require.Eventually(t, func() bool { return len(d.UnconnectedPeers()) == 0 }, 2*time.Second, 50*time.Millisecond) - sort.Strings(dialled) + slices.Sort(dialled) assert.Equal(t, 0, d.PoolCount()) assert.Equal(t, 0, len(d.BadPeers())) assert.Equal(t, 0, len(d.GoodPeers())) @@ -150,7 +150,7 @@ func TestDefaultDiscoverer(t *testing.T) { }, addr.Capabilities) gAddrs[i] = addr.Address } - sort.Strings(gAddrs) + slices.Sort(gAddrs) assert.Equal(t, 0, d.PoolCount()) assert.Equal(t, 0, len(d.UnconnectedPeers())) assert.Equal(t, 0, len(d.BadPeers())) @@ -176,7 +176,7 @@ func TestDefaultDiscoverer(t *testing.T) { ts.retFalse.Store(1) assert.Equal(t, len(set1), d.PoolCount()) set1D := d.UnconnectedPeers() - sort.Strings(set1D) + slices.Sort(set1D) assert.Equal(t, 0, len(d.BadPeers())) require.Equal(t, set1, set1D) @@ -193,7 +193,7 @@ func TestDefaultDiscoverer(t *testing.T) { } } require.Eventually(t, func() bool { return d.PoolCount() == 0 }, 2*time.Second, 50*time.Millisecond) - sort.Strings(dialledBad) + slices.Sort(dialledBad) for i := 0; i < len(set1); i++ { for j := 0; j < connRetries; j++ { assert.Equal(t, set1[i], dialledBad[i*connRetries+j]) @@ -216,7 +216,7 @@ func TestSeedDiscovery(t *testing.T) { ts := &fakeTransp{} ts.dialCh = make(chan string) ts.retFalse.Store(1) // Fail all dial requests. - sort.Strings(seeds) + slices.Sort(seeds) d := NewDefaultDiscovery(seeds, time.Second/10, ts) tryMaxWait = 1 // Don't waste time. diff --git a/pkg/network/payload/notary_request_test.go b/pkg/network/payload/notary_request_test.go index f6aa7c9cf..c002c9167 100644 --- a/pkg/network/payload/notary_request_test.go +++ b/pkg/network/payload/notary_request_test.go @@ -17,6 +17,7 @@ func TestNotaryRequestIsValid(t *testing.T) { Script: []byte{0, 1, 2}, ValidUntilBlock: 123, } + emptySingleInvocation := append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...) errorCases := map[string]*P2PNotaryRequest{ "main tx: missing NotaryAssisted attribute": {MainTransaction: &transaction.Transaction{}}, "main tx: zero NKeys": {MainTransaction: &transaction.Transaction{Attributes: []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}}}}}, @@ -53,14 +54,14 @@ func TestNotaryRequestIsValid(t *testing.T) { MainTransaction: mainTx, FallbackTransaction: &transaction.Transaction{ Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 1)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 1)}, {}}, }, }, "fallback tx: missing NotValidBefore attribute": { MainTransaction: mainTx, FallbackTransaction: &transaction.Transaction{ Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, }, "fallback tx: invalid number of Conflicts attributes": { @@ -68,7 +69,7 @@ func TestNotaryRequestIsValid(t *testing.T) { FallbackTransaction: &transaction.Transaction{ Attributes: []transaction.Attribute{{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}}}, Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, }, "fallback tx: does not conflicts with main tx": { @@ -79,7 +80,7 @@ func TestNotaryRequestIsValid(t *testing.T) { {Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: util.Uint256{}}}, }, Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, }, "fallback tx: missing NotaryAssisted attribute": { @@ -90,7 +91,7 @@ func TestNotaryRequestIsValid(t *testing.T) { {Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}}, }, Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, }, "fallback tx: non-zero NKeys": { @@ -102,7 +103,7 @@ func TestNotaryRequestIsValid(t *testing.T) { {Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}, }, Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, }, "fallback tx: ValidUntilBlock mismatch": { @@ -115,7 +116,7 @@ func TestNotaryRequestIsValid(t *testing.T) { {Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}}, }, Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, }, } @@ -135,7 +136,7 @@ func TestNotaryRequestIsValid(t *testing.T) { {Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}}, }, Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}, - Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}}, + Scripts: []transaction.Witness{{InvocationScript: emptySingleInvocation, VerificationScript: make([]byte, 0)}, {}}, }, } require.NoError(t, p.isValid()) diff --git a/pkg/network/server.go b/pkg/network/server.go index 34da851b5..556ac4e37 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -10,7 +10,7 @@ import ( mrand "math/rand" "net" "runtime" - "sort" + "slices" "strconv" "sync" "sync/atomic" @@ -475,11 +475,7 @@ func (s *Server) run() { } else if s.MinPeers > 0 && loopCnt%s.MinPeers == 0 && optimalN > peerN && optimalN < s.MaxPeers && optimalN < netSize { // Having some number of peers, but probably can get some more, the network is big. // It also allows to start picking up new peers proactively, before we suddenly have optimalN-peerN { - connN = optimalN - peerN - } - s.discovery.RequestRemote(connN) + s.discovery.RequestRemote(min(s.AttemptConnPeers, optimalN-peerN)) } if addrCheckTimeout || s.discovery.PoolCount() < s.AttemptConnPeers { @@ -1173,10 +1169,8 @@ txloop: var cbList = s.txCbList.Load() if cbList != nil { var list = cbList.([]util.Uint256) - var i = sort.Search(len(list), func(i int) bool { - return list[i].CompareTo(tx.Hash()) >= 0 - }) - if i < len(list) && list[i].Equals(tx.Hash()) { + _, found := slices.BinarySearchFunc(list, tx.Hash(), util.Uint256.Compare) + if found { txCallback(tx) } } @@ -1443,25 +1437,16 @@ func (s *Server) tryInitStateSync() { return } - var peersNumber int s.lock.RLock() - heights := make([]uint32, 0) + heights := make([]uint32, 0, len(s.peers)) for p := range s.peers { if p.Handshaked() { - peersNumber++ - peerLastBlock := p.LastBlockIndex() - i := sort.Search(len(heights), func(i int) bool { - return heights[i] >= peerLastBlock - }) - heights = append(heights, peerLastBlock) - if i != len(heights)-1 { - copy(heights[i+1:], heights[i:]) - heights[i] = peerLastBlock - } + heights = append(heights, p.LastBlockIndex()) } } s.lock.RUnlock() - if peersNumber >= s.MinPeers && len(heights) > 0 { + slices.Sort(heights) + if len(heights) >= s.MinPeers && len(heights) > 0 { // choose the height of the median peer as the current chain's height h := heights[len(heights)/2] err := s.stateSync.Init(h) @@ -1498,20 +1483,14 @@ func (s *Server) RequestTx(hashes ...util.Uint256) { return } - var sorted = make([]util.Uint256, len(hashes)) - copy(sorted, hashes) - sort.Slice(sorted, func(i, j int) bool { - return sorted[i].CompareTo(sorted[j]) < 0 - }) - + var sorted = slices.Clone(hashes) + slices.SortFunc(sorted, util.Uint256.Compare) s.txCbList.Store(sorted) for i := 0; i <= len(hashes)/payload.MaxHashesCount; i++ { start := i * payload.MaxHashesCount stop := (i + 1) * payload.MaxHashesCount - if stop > len(hashes) { - stop = len(hashes) - } + stop = min(stop, len(hashes)) if start == stop { break } @@ -1660,9 +1639,7 @@ func (s *Server) initStaleMemPools() { threshold := 5 // Not perfect, can change over time, but should be sufficient. numOfCNs := s.config.GetNumOfCNs(s.chain.BlockHeight()) - if numOfCNs*2 > threshold { - threshold = numOfCNs * 2 - } + threshold = max(threshold, numOfCNs*2) s.mempool.SetResendThreshold(uint32(threshold), s.broadcastTX) if s.chain.P2PSigExtensionsEnabled() { @@ -1769,12 +1746,5 @@ func (s *Server) Port(localAddr net.Addr) (uint16, error) { func optimalNumOfThreads() int { // Doing more won't help, mempool is still a contention point. const maxThreads = 16 - var threads = runtime.GOMAXPROCS(0) - if threads > runtime.NumCPU() { - threads = runtime.NumCPU() - } - if threads > maxThreads { - threads = maxThreads - } - return threads + return min(runtime.GOMAXPROCS(0), runtime.NumCPU(), maxThreads) } diff --git a/pkg/rpcclient/invoker/invoker.go b/pkg/rpcclient/invoker/invoker.go index a40a0c2dd..ae7b6aa56 100644 --- a/pkg/rpcclient/invoker/invoker.go +++ b/pkg/rpcclient/invoker/invoker.go @@ -229,9 +229,7 @@ func iterateNext(rpc RPCSessions, sessionID uuid.UUID, iterator *result.Iterator if iterator.ID != nil { return rpc.TraverseIterator(sessionID, *iterator.ID, num) } - if num > len(iterator.Values) { - num = len(iterator.Values) - } + num = min(num, len(iterator.Values)) items := iterator.Values[:num] iterator.Values = iterator.Values[num:] diff --git a/pkg/rpcclient/neo/doc_test.go b/pkg/rpcclient/neo/doc_test.go index 46fa77990..46b6d66b3 100644 --- a/pkg/rpcclient/neo/doc_test.go +++ b/pkg/rpcclient/neo/doc_test.go @@ -1,11 +1,13 @@ package neo_test import ( + "cmp" "context" "math/big" - "sort" + "slices" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/rpcclient" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" @@ -76,7 +78,7 @@ func ExampleContract() { cands, _ := neoToken.GetCandidates() // Sort by votes. - sort.Slice(cands, func(i, j int) bool { return cands[i].Votes < cands[j].Votes }) + slices.SortFunc(cands, func(a, b result.Validator) int { return cmp.Compare(a.Votes, b.Votes) }) // Get the extended NEO-specific balance data. bNeo, _ := neoToken.GetAccountState(a.Sender()) diff --git a/pkg/rpcclient/waiter/waiter.go b/pkg/rpcclient/waiter/waiter.go index a62dc0260..30d40d0de 100644 --- a/pkg/rpcclient/waiter/waiter.go +++ b/pkg/rpcclient/waiter/waiter.go @@ -29,8 +29,8 @@ var ( // of transaction awaiting process and no result was received yet. ErrContextDone = errors.New("waiter context done") // ErrAwaitingNotSupported is returned from Wait method if Waiter instance - // doesn't support transaction awaiting. - ErrAwaitingNotSupported = errors.New("awaiting not supported") + // doesn't support transaction awaiting. It's compatible with [errors.ErrUnsupported]. + ErrAwaitingNotSupported = fmt.Errorf("%w: awaiting", errors.ErrUnsupported) // ErrMissedEvent is returned when RPCEventBased closes receiver channel // which happens if missed event was received from the RPC server. ErrMissedEvent = errors.New("some event was missed") diff --git a/pkg/rpcclient/wsclient_test.go b/pkg/rpcclient/wsclient_test.go index 78805fc15..e1f0dd82e 100644 --- a/pkg/rpcclient/wsclient_test.go +++ b/pkg/rpcclient/wsclient_test.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" "net/http/httptest" - "sort" + "slices" "strconv" "strings" "sync" @@ -866,7 +866,7 @@ func TestWSConcurrentAccess(t *testing.T) { } ids.lock.RUnlock() - sort.Ints(idsList) + slices.Sort(idsList) require.Equal(t, 1, idsList[0]) require.Less(t, idsList[len(idsList)-1], batchCount*3+1) // batchCount*requestsPerBatch+1 diff --git a/pkg/services/notary/node.go b/pkg/services/notary/node.go index 341131006..cc203470a 100644 --- a/pkg/services/notary/node.go +++ b/pkg/services/notary/node.go @@ -1,6 +1,8 @@ package notary import ( + "slices" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/util" @@ -13,12 +15,8 @@ func (n *Notary) UpdateNotaryNodes(notaryNodes keys.PublicKeys) { n.accMtx.Lock() defer n.accMtx.Unlock() - if n.currAccount != nil { - for _, node := range notaryNodes { - if node.Equal(n.currAccount.PublicKey()) { - return - } - } + if n.currAccount != nil && slices.ContainsFunc(notaryNodes, n.currAccount.PublicKey().Equal) { + return } var acc *wallet.Account diff --git a/pkg/services/notary/notary.go b/pkg/services/notary/notary.go index 166890675..6639acbca 100644 --- a/pkg/services/notary/notary.go +++ b/pkg/services/notary/notary.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "slices" "sync" "sync/atomic" @@ -131,18 +132,14 @@ func (r request) isMainCompleted() bool { // NewNotary returns a new Notary module. func NewNotary(cfg Config, net netmode.Magic, mp *mempool.Pool, onTransaction func(tx *transaction.Transaction) error) (*Notary, error) { w := cfg.MainCfg.UnlockWallet - wallet, err := wallet.NewWalletFromFile(w.Path) + wall, err := wallet.NewWalletFromFile(w.Path) if err != nil { return nil, err } - haveAccount := false - for _, acc := range wallet.Accounts { - if err := acc.Decrypt(w.Password, wallet.Scrypt); err == nil { - haveAccount = true - break - } - } + var haveAccount = slices.ContainsFunc(wall.Accounts, func(acc *wallet.Account) bool { + return acc.Decrypt(w.Password, wall.Scrypt) == nil + }) if !haveAccount { return nil, errors.New("no wallet account could be unlocked") } @@ -151,7 +148,7 @@ func NewNotary(cfg Config, net netmode.Magic, mp *mempool.Pool, onTransaction fu requests: make(map[util.Uint256]*request), Config: cfg, Network: net, - wallet: wallet, + wallet: wall, onTransaction: onTransaction, newTxs: make(chan txHashPair, defaultTxChannelCapacity), mp: mp, @@ -260,14 +257,12 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) { defer n.reqMtx.Unlock() r, exists := n.requests[payload.MainTransaction.Hash()] if exists { - for _, fb := range r.fallbacks { - if fb.Hash().Equals(payload.FallbackTransaction.Hash()) { - return // then we already have processed this request - } - } - if nvbFallback < r.minNotValidBefore { - r.minNotValidBefore = nvbFallback + if slices.ContainsFunc(r.fallbacks, func(fb *transaction.Transaction) bool { + return fb.Hash().Equals(payload.FallbackTransaction.Hash()) + }) { + return // then we already have processed this request } + r.minNotValidBefore = min(r.minNotValidBefore, nvbFallback) } else { // Avoid changes in the main transaction witnesses got from the notary request pool to // keep the pooled tx valid. We will update its copy => the copy's size will be changed. @@ -449,13 +444,9 @@ func (n *Notary) newTxCallbackLoop() { } if !isMain { // Ensure that fallback was not already completed. - var isPending bool - for _, fb := range r.fallbacks { - if fb.Hash() == tx.tx.Hash() { - isPending = true - break - } - } + var isPending = slices.ContainsFunc(r.fallbacks, func(fb *transaction.Transaction) bool { + return fb.Hash() == tx.tx.Hash() + }) if !isPending { n.reqMtx.Unlock() continue diff --git a/pkg/services/oracle/jsonpath/jsonpath.go b/pkg/services/oracle/jsonpath/jsonpath.go index 7ccf41bf7..a43c7b62a 100644 --- a/pkg/services/oracle/jsonpath/jsonpath.go +++ b/pkg/services/oracle/jsonpath/jsonpath.go @@ -449,9 +449,7 @@ func (p *pathParser) descendByRange(objs []any, start, end int) ([]any, bool) { subEnd += len(arr) } - if subEnd > len(arr) { - subEnd = len(arr) - } + subEnd = min(subEnd, len(arr)) if subEnd <= subStart { continue diff --git a/pkg/services/oracle/network.go b/pkg/services/oracle/network.go index 4af62d440..cafdbe414 100644 --- a/pkg/services/oracle/network.go +++ b/pkg/services/oracle/network.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "net/http" + "slices" "syscall" "github.com/nspcc-dev/neo-go/pkg/config" @@ -39,12 +40,9 @@ func isReserved(ip net.IP) bool { if !ip.IsGlobalUnicast() { return true } - for i := range privateNets { - if privateNets[i].Contains(ip) { - return true - } - } - return false + return slices.ContainsFunc(privateNets, func(pn net.IPNet) bool { + return pn.Contains(ip) + }) } func getDefaultClient(cfg config.OracleConfiguration) *http.Client { diff --git a/pkg/services/oracle/nodes.go b/pkg/services/oracle/nodes.go index 0331de62d..e720bd8f2 100644 --- a/pkg/services/oracle/nodes.go +++ b/pkg/services/oracle/nodes.go @@ -1,6 +1,8 @@ package oracle import ( + "slices" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -13,17 +15,8 @@ func (o *Oracle) UpdateOracleNodes(oracleNodes keys.PublicKeys) { o.accMtx.Lock() defer o.accMtx.Unlock() - old := o.oracleNodes - if isEqual := len(old) == len(oracleNodes); isEqual { - for i := range old { - if !old[i].Equal(oracleNodes[i]) { - isEqual = false - break - } - } - if isEqual { - return - } + if slices.EqualFunc(o.oracleNodes, oracleNodes, (*keys.PublicKey).Equal) { + return } var acc *wallet.Account diff --git a/pkg/services/oracle/oracle.go b/pkg/services/oracle/oracle.go index 649677bea..e0c0c6906 100644 --- a/pkg/services/oracle/oracle.go +++ b/pkg/services/oracle/oracle.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "net/http" + "slices" "sync" "time" @@ -150,13 +151,9 @@ func NewOracle(cfg Config) (*Oracle, error) { return nil, err } - haveAccount := false - for _, acc := range o.wallet.Accounts { - if err := acc.Decrypt(w.Password, o.wallet.Scrypt); err == nil { - haveAccount = true - break - } - } + var haveAccount = slices.ContainsFunc(o.wallet.Accounts, func(acc *wallet.Account) bool { + return acc.Decrypt(w.Password, o.wallet.Scrypt) == nil + }) if !haveAccount { return nil, errors.New("no wallet account could be unlocked") } diff --git a/pkg/services/oracle/request.go b/pkg/services/oracle/request.go index 1607fa56a..25d9a9107 100644 --- a/pkg/services/oracle/request.go +++ b/pkg/services/oracle/request.go @@ -6,6 +6,7 @@ import ( "mime" "net/http" "net/url" + "slices" "time" "github.com/nspcc-dev/neo-go/pkg/core/state" @@ -284,10 +285,5 @@ func checkMediaType(hdr string, allowed []string) bool { return false } - for _, ct := range allowed { - if ct == typ { - return true - } - } - return false + return slices.Contains(allowed, typ) } diff --git a/pkg/services/rpcsrv/client_test.go b/pkg/services/rpcsrv/client_test.go index 410be2544..017a60b2e 100644 --- a/pkg/services/rpcsrv/client_test.go +++ b/pkg/services/rpcsrv/client_test.go @@ -10,7 +10,7 @@ import ( "math/big" "net/http" "net/http/httptest" - "sort" + "slices" "strings" "sync" "testing" @@ -154,7 +154,7 @@ func TestClientRoleManagement(t *testing.T) { _, err = c.SubmitBlock(*bl) require.NoError(t, err) - sort.Sort(testKeys) + slices.SortFunc(testKeys, (*keys.PublicKey).Cmp) ks, err = rm.GetDesignatedByRole(noderoles.Oracle, height+1) require.NoError(t, err) require.Equal(t, testKeys, ks) @@ -1458,11 +1458,11 @@ func TestClient_IteratorSessions(t *testing.T) { for i := 0; i < storageItemsCount; i++ { expected[i] = stackitem.NewBigInteger(big.NewInt(int64(i))).Bytes() } - sort.Slice(expected, func(i, j int) bool { - if len(expected[i]) != len(expected[j]) { - return len(expected[i]) < len(expected[j]) + slices.SortFunc(expected, func(a, b []byte) int { + if len(a) != len(b) { + return len(a) - len(b) } - return bytes.Compare(expected[i], expected[j]) < 0 + return bytes.Compare(a, b) }) prepareSession := func(t *testing.T) (uuid.UUID, uuid.UUID) { @@ -1699,11 +1699,11 @@ func TestClient_Iterator_SessionConfigVariations(t *testing.T) { for i := 0; i < storageItemsCount; i++ { expected[i] = stackitem.NewBigInteger(big.NewInt(int64(i))).Bytes() } - sort.Slice(expected, func(i, j int) bool { - if len(expected[i]) != len(expected[j]) { - return len(expected[i]) < len(expected[j]) + slices.SortFunc(expected, func(a, b []byte) int { + if len(a) != len(b) { + return len(a) - len(b) } - return bytes.Compare(expected[i], expected[j]) < 0 + return bytes.Compare(a, b) }) checkSessionEnabled(t, c) }) diff --git a/pkg/services/rpcsrv/error.go b/pkg/services/rpcsrv/error.go index 9f740f894..68188ae83 100644 --- a/pkg/services/rpcsrv/error.go +++ b/pkg/services/rpcsrv/error.go @@ -33,9 +33,7 @@ type abstractBatch []abstract // RunForErrors implements abstractResult interface. func (ab abstractBatch) RunForErrors(f func(jsonErr *neorpc.Error)) { for _, a := range ab { - if a.Error != nil { - f(a.Error) - } + a.RunForErrors(f) } } diff --git a/pkg/services/rpcsrv/params/txBuilder.go b/pkg/services/rpcsrv/params/txBuilder.go index 29db92533..fc1091aaa 100644 --- a/pkg/services/rpcsrv/params/txBuilder.go +++ b/pkg/services/rpcsrv/params/txBuilder.go @@ -14,7 +14,8 @@ import ( ) // ExpandFuncParameterIntoScript pushes provided FuncParam parameter -// into the given buffer. +// into the given buffer. Returns [errors.ErrUnsupported] for types it can't +// process. func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error { switch fp.Type { case smartcontract.ByteArrayType: @@ -92,7 +93,7 @@ func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error { emit.Opcodes(script, opcode.PUSHNULL) } default: - return fmt.Errorf("parameter type %v is not supported", fp.Type) + return fmt.Errorf("%w: parameter type %v", errors.ErrUnsupported, fp.Type) } return script.Err } diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go index 24fcf5201..88db50f5f 100644 --- a/pkg/services/rpcsrv/server.go +++ b/pkg/services/rpcsrv/server.go @@ -273,10 +273,7 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server, protoCfg := chain.GetConfig().ProtocolConfiguration if conf.SessionEnabled { if conf.SessionExpirationTime <= 0 { - conf.SessionExpirationTime = int(protoCfg.TimePerBlock / time.Second) - if conf.SessionExpirationTime < 5 { - conf.SessionExpirationTime = 5 - } + conf.SessionExpirationTime = max(int(protoCfg.TimePerBlock/time.Second), 5) log.Info("SessionExpirationTime is not set or wrong, setting default value", zap.Int("SessionExpirationTime", conf.SessionExpirationTime)) } if conf.SessionPoolSize <= 0 { @@ -912,9 +909,10 @@ func (s *Server) getPeers(_ params.Params) (any, *neorpc.Error) { func (s *Server) getRawMempool(reqParams params.Params) (any, *neorpc.Error) { verbose, _ := reqParams.Value(0).GetBoolean() mp := s.chain.GetMemPool() - hashList := make([]util.Uint256, 0) - for _, item := range mp.GetVerifiedTransactions() { - hashList = append(hashList, item.Hash()) + txes := mp.GetVerifiedTransactions() + hashList := make([]util.Uint256, len(txes)) + for i := range txes { + hashList[i] = txes[i].Hash() } if !verbose { return hashList, nil @@ -958,13 +956,9 @@ func (s *Server) calculateNetworkFee(reqParams params.Params) (any, *neorpc.Erro size := len(hashablePart) + io.GetVarSize(len(tx.Signers)) var ( netFee int64 - // Verification GAS cost can't exceed this policy. - gasLimit = s.chain.GetMaxVerificationGAS() + // Verification GAS cost can't exceed chin policy, but RPC config can limit it further. + gasLimit = min(s.chain.GetMaxVerificationGAS(), int64(s.config.MaxGasInvoke)) ) - if gasLimit > int64(s.config.MaxGasInvoke) { - // But we honor instance configuration as well. - gasLimit = int64(s.config.MaxGasInvoke) - } for i, signer := range tx.Signers { w := tx.Scripts[i] if len(w.InvocationScript) == 0 { // No invocation provided, try to infer one. @@ -1683,9 +1677,7 @@ func (s *Server) findStates(ps params.Params) (any, *neorpc.Error) { if err != nil { return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("invalid count: %s", err)) } - if count > s.config.MaxFindResultItems { - count = s.config.MaxFindResultItems - } + count = min(count, s.config.MaxFindResultItems) } cs, respErr := s.getHistoricalContractState(root, csHash) if respErr != nil { @@ -2098,7 +2090,7 @@ func (s *Server) getCandidates(_ params.Params) (any, *neorpc.Error) { if err != nil { return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't get enrollments: %s", err.Error())) } - var res = make([]result.Candidate, 0) + var res = make([]result.Candidate, 0, len(enrollments)) for _, v := range enrollments { res = append(res, result.Candidate{ PublicKey: *v.Key, @@ -2121,7 +2113,7 @@ func (s *Server) getNextBlockValidators(_ params.Params) (any, *neorpc.Error) { if err != nil { return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't get enrollments: %s", err.Error())) } - var res = make([]result.Validator, 0) + var res = make([]result.Validator, 0, len(validators)) for _, v := range enrollments { if !validators.Contains(v.Key) { continue @@ -2379,10 +2371,7 @@ func (s *Server) prepareInvocationContext(t trigger.Type, script []byte, contrac if t == trigger.Verification { // We need this special case because witnesses verification is not the simple System.Contract.Call, // and we need to define exactly the amount of gas consumed for a contract witness verification. - gasPolicy := s.chain.GetMaxVerificationGAS() - if ic.VM.GasLimit > gasPolicy { - ic.VM.GasLimit = gasPolicy - } + ic.VM.GasLimit = min(ic.VM.GasLimit, s.chain.GetMaxVerificationGAS()) err = s.chain.InitVerificationContext(ic, contractScriptHash, &transaction.Witness{InvocationScript: script, VerificationScript: []byte{}}) if err != nil { diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go index 03e493f33..db3e04f1d 100644 --- a/pkg/services/rpcsrv/server_test.go +++ b/pkg/services/rpcsrv/server_test.go @@ -14,7 +14,7 @@ import ( "net/http" "net/http/httptest" "reflect" - "sort" + "slices" "strconv" "strings" "sync/atomic" @@ -1174,7 +1174,7 @@ var rpcTestCases = map[string][]rpcTestCase{ params: "[]", result: func(e *executor) any { expected, _ := e.chain.GetCommittee() - sort.Sort(expected) + slices.SortFunc(expected, (*keys.PublicKey).Cmp) return &expected }, }, diff --git a/pkg/services/stateroot/service.go b/pkg/services/stateroot/service.go index e7123e88c..43eb61f90 100644 --- a/pkg/services/stateroot/service.go +++ b/pkg/services/stateroot/service.go @@ -3,6 +3,7 @@ package stateroot import ( "errors" "fmt" + "slices" "sync" "sync/atomic" "time" @@ -112,13 +113,9 @@ func New(cfg config.StateRoot, sm *stateroot.Module, log *zap.Logger, bc Ledger, return nil, err } - haveAccount := false - for _, acc := range s.wallet.Accounts { - if err := acc.Decrypt(w.Password, s.wallet.Scrypt); err == nil { - haveAccount = true - break - } - } + var haveAccount = slices.ContainsFunc(s.wallet.Accounts, func(acc *wallet.Account) bool { + return acc.Decrypt(w.Password, s.wallet.Scrypt) == nil + }) if !haveAccount { return nil, errors.New("no wallet account could be unlocked") } diff --git a/pkg/services/stateroot/service_test.go b/pkg/services/stateroot/service_test.go index 5f75d4cff..224837423 100644 --- a/pkg/services/stateroot/service_test.go +++ b/pkg/services/stateroot/service_test.go @@ -3,7 +3,7 @@ package stateroot_test import ( "crypto/elliptic" "path/filepath" - "sort" + "slices" "sync/atomic" "testing" "time" @@ -63,10 +63,10 @@ func newMajorityMultisigWithGAS(t *testing.T, n int) (util.Uint160, keys.PublicK require.NoError(t, err) accs[i] = acc } - sort.Slice(accs, func(i, j int) bool { - pi := accs[i].PublicKey() - pj := accs[j].PublicKey() - return pi.Cmp(pj) == -1 + slices.SortFunc(accs, func(a, b *wallet.Account) int { + pa := a.PublicKey() + pb := b.PublicKey() + return pa.Cmp(pb) }) pubs := make(keys.PublicKeys, n) for i := range pubs { diff --git a/pkg/smartcontract/binding/generate.go b/pkg/smartcontract/binding/generate.go index 24939f458..507078a9a 100644 --- a/pkg/smartcontract/binding/generate.go +++ b/pkg/smartcontract/binding/generate.go @@ -6,7 +6,7 @@ import ( "go/format" "go/token" "io" - "sort" + "slices" "strconv" "strings" "text/template" @@ -159,7 +159,7 @@ func Generate(cfg Config) error { if ctr.Hash != "" { ctr.Imports = append(ctr.Imports, "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal") } - sort.Strings(ctr.Imports) + slices.Sort(ctr.Imports) return FExecute(srcTemplate, cfg.Output, ctr) } diff --git a/pkg/smartcontract/context/context.go b/pkg/smartcontract/context/context.go index 2974e2675..fe28c652f 100644 --- a/pkg/smartcontract/context/context.go +++ b/pkg/smartcontract/context/context.go @@ -6,7 +6,7 @@ import ( "encoding/json" "errors" "fmt" - "sort" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/config/netmode" @@ -111,13 +111,9 @@ func (c *ParameterContext) AddSignature(h util.Uint160, ctr *wallet.Contract, pu return errors.New("signature is already added") } pubBytes := pub.Bytes() - var contained bool - for i := range pubs { - if bytes.Equal(pubBytes, pubs[i]) { - contained = true - break - } - } + var contained = slices.ContainsFunc(pubs, func(p []byte) bool { + return bytes.Equal(pubBytes, p) + }) if !contained { return errors.New("public key is not present in script") } @@ -136,8 +132,8 @@ func (c *ParameterContext) AddSignature(h util.Uint160, ctr *wallet.Contract, pu break } } - sort.Slice(sigs, func(i, j int) bool { - return sigs[i].index < sigs[j].index + slices.SortFunc(sigs, func(a, b sigWithIndex) int { + return a.index - b.index }) for i := range sigs { item.Parameters[i] = smartcontract.Parameter{ diff --git a/pkg/smartcontract/contract.go b/pkg/smartcontract/contract.go index 90b34267f..a3397b25e 100644 --- a/pkg/smartcontract/contract.go +++ b/pkg/smartcontract/contract.go @@ -2,7 +2,7 @@ package smartcontract import ( "fmt" - "sort" + "slices" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -11,7 +11,8 @@ import ( ) // CreateMultiSigRedeemScript creates an "m out of n" type verification script -// where n is the length of publicKeys. +// where n is the length of publicKeys. It modifies passed publicKeys by +// sorting them. func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, error) { if m < 1 { return nil, fmt.Errorf("param m cannot be smaller than 1, got %d", m) @@ -25,7 +26,7 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro buf := io.NewBufBinWriter() emit.Int(buf.BinWriter, int64(m)) - sort.Sort(publicKeys) + slices.SortFunc(publicKeys, (*keys.PublicKey).Cmp) for _, pubKey := range publicKeys { emit.Bytes(buf.BinWriter, pubKey.Bytes()) } diff --git a/pkg/smartcontract/manifest/abi.go b/pkg/smartcontract/manifest/abi.go index 3027e5c97..67e28b073 100644 --- a/pkg/smartcontract/manifest/abi.go +++ b/pkg/smartcontract/manifest/abi.go @@ -1,9 +1,9 @@ package manifest import ( + "cmp" "errors" "fmt" - "sort" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -62,33 +62,14 @@ func (a *ABI) IsValid() error { return fmt.Errorf("method %q/%d: %w", a.Methods[i].Name, len(a.Methods[i].Parameters), err) } } - if len(a.Methods) > 1 { - methods := make([]struct { - name string - params int - }, len(a.Methods)) - for i := range methods { - methods[i].name = a.Methods[i].Name - methods[i].params = len(a.Methods[i].Parameters) - } - sort.Slice(methods, func(i, j int) bool { - if methods[i].name < methods[j].name { - return true - } - if methods[i].name == methods[j].name { - return methods[i].params < methods[j].params - } - return false - }) - for i := range methods { - if i == 0 { - continue - } - if methods[i].name == methods[i-1].name && - methods[i].params == methods[i-1].params { - return errors.New("duplicate method specifications") - } + if sliceHasDups(a.Methods, func(a, b Method) int { + res := cmp.Compare(a.Name, b.Name) + if res != 0 { + return res } + return cmp.Compare(len(a.Parameters), len(b.Parameters)) + }) { + return errors.New("duplicate method specifications") } for i := range a.Events { err := a.Events[i].IsValid() @@ -96,14 +77,10 @@ func (a *ABI) IsValid() error { return fmt.Errorf("event %q/%d: %w", a.Events[i].Name, len(a.Events[i].Parameters), err) } } - if len(a.Events) > 1 { - names := make([]string, len(a.Events)) - for i := range a.Events { - names[i] = a.Events[i].Name - } - if stringsHaveDups(names) { - return errors.New("duplicate event names") - } + if sliceHasDups(a.Events, func(a, b Event) int { + return cmp.Compare(a.Name, b.Name) + }) { + return errors.New("duplicate event names") } return nil } diff --git a/pkg/smartcontract/manifest/container.go b/pkg/smartcontract/manifest/container.go index 1e8adaeda..c65df8a59 100644 --- a/pkg/smartcontract/manifest/container.go +++ b/pkg/smartcontract/manifest/container.go @@ -7,6 +7,7 @@ package manifest import ( "bytes" "encoding/json" + "slices" ) // WildStrings represents a string set which can be a wildcard. @@ -25,12 +26,7 @@ func (c *WildStrings) Contains(v string) bool { if c.IsWildcard() { return true } - for _, s := range c.Value { - if v == s { - return true - } - } - return false + return slices.Contains(c.Value, v) } // Contains checks if v is in the container. @@ -38,12 +34,7 @@ func (c *WildPermissionDescs) Contains(v PermissionDesc) bool { if c.IsWildcard() { return true } - for _, u := range c.Value { - if u.Equals(v) { - return true - } - } - return false + return slices.ContainsFunc(c.Value, v.Equals) } // IsWildcard returns true iff the container is a wildcard. diff --git a/pkg/smartcontract/manifest/group.go b/pkg/smartcontract/manifest/group.go index 15485aa3c..9c7b7bd8b 100644 --- a/pkg/smartcontract/manifest/group.go +++ b/pkg/smartcontract/manifest/group.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "encoding/json" "errors" - "sort" + "slices" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -58,7 +58,7 @@ func (g Groups) AreValid(h util.Uint160) error { for i := range g { pkeys[i] = g[i].PublicKey } - sort.Sort(pkeys) + slices.SortFunc(pkeys, (*keys.PublicKey).Cmp) for i := range pkeys { if i == 0 { continue @@ -71,12 +71,9 @@ func (g Groups) AreValid(h util.Uint160) error { } func (g Groups) Contains(k *keys.PublicKey) bool { - for i := range g { - if k.Equal(g[i].PublicKey) { - return true - } - } - return false + return slices.ContainsFunc(g, func(gr Group) bool { + return k.Equal(gr.PublicKey) + }) } // MarshalJSON implements the json.Marshaler interface. diff --git a/pkg/smartcontract/manifest/manifest.go b/pkg/smartcontract/manifest/manifest.go index 95a2f41d3..f709c21ae 100644 --- a/pkg/smartcontract/manifest/manifest.go +++ b/pkg/smartcontract/manifest/manifest.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "math" + "slices" "strings" ojson "github.com/nspcc-dev/go-ordered-json" @@ -76,12 +77,9 @@ func DefaultManifest(name string) *Manifest { // CanCall returns true if the current contract is allowed to call // the method of another contract with the specified hash. func (m *Manifest) CanCall(hash util.Uint160, toCall *Manifest, method string) bool { - for i := range m.Permissions { - if m.Permissions[i].IsAllowed(hash, toCall, method) { - return true - } - } - return false + return slices.ContainsFunc(m.Permissions, func(p Permission) bool { + return p.IsAllowed(hash, toCall, method) + }) } // IsValid checks manifest internal consistency and correctness, one of the @@ -94,17 +92,11 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error { return errors.New("no name") } - for i := range m.SupportedStandards { - if m.SupportedStandards[i] == "" { - return errors.New("invalid nameless supported standard") - } + if slices.Contains(m.SupportedStandards, "") { + return errors.New("invalid nameless supported standard") } - if len(m.SupportedStandards) > 1 { - names := make([]string, len(m.SupportedStandards)) - copy(names, m.SupportedStandards) - if stringsHaveDups(names) { - return errors.New("duplicate supported standards") - } + if sliceHasDups(m.SupportedStandards, strings.Compare) { + return errors.New("duplicate supported standards") } err = m.ABI.IsValid() if err != nil { @@ -127,12 +119,8 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error { if m.Trusts.Value == nil && !m.Trusts.Wildcard { return errors.New("invalid (null?) trusts") } - if len(m.Trusts.Value) > 1 { - hashes := make([]PermissionDesc, len(m.Trusts.Value)) - copy(hashes, m.Trusts.Value) - if permissionDescsHaveDups(hashes) { - return errors.New("duplicate trusted contracts") - } + if sliceHasDups(m.Trusts.Value, PermissionDesc.Compare) { + return errors.New("duplicate trusted contracts") } err = Permissions(m.Permissions).AreValid() if err != nil { @@ -154,12 +142,7 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error { // IsStandardSupported denotes whether the specified standard is supported by the contract. func (m *Manifest) IsStandardSupported(standard string) bool { - for _, st := range m.SupportedStandards { - if st == standard { - return true - } - } - return false + return slices.Contains(m.SupportedStandards, standard) } // ToStackItem converts Manifest to stackitem.Item. diff --git a/pkg/smartcontract/manifest/parameter.go b/pkg/smartcontract/manifest/parameter.go index 3e7424522..7cccb2b22 100644 --- a/pkg/smartcontract/manifest/parameter.go +++ b/pkg/smartcontract/manifest/parameter.go @@ -1,9 +1,10 @@ package manifest import ( + "cmp" "errors" "fmt" - "sort" + "slices" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" @@ -79,58 +80,30 @@ func (p Parameters) AreValid() error { return fmt.Errorf("parameter #%d/%q: %w", i, p[i].Name, err) } } - if len(p) < 2 { - return nil - } - names := make([]string, len(p)) - for i := range p { - names[i] = p[i].Name - } - if stringsHaveDups(names) { + if sliceHasDups(p, func(a, b Parameter) int { + return cmp.Compare(a.Name, b.Name) + }) { return errors.New("duplicate parameter name") } return nil } -// stringsHaveDups checks the given set of strings for duplicates. It modifies the slice given! -func stringsHaveDups(strings []string) bool { - sort.Strings(strings) - for i := range strings { +// sliceHasDups checks the slice for duplicate elements. +func sliceHasDups[S ~[]E, E any](x S, cmp func(a, b E) int) bool { + if len(x) < 2 { + return false + } + if len(x) > 2 { + x = slices.Clone(x) + slices.SortFunc(x, cmp) + } + for i := range x { if i == 0 { continue } - if strings[i] == strings[i-1] { + if cmp(x[i-1], x[i]) == 0 { return true } } return false } - -// permissionDescsHaveDups checks the given set of strings for duplicates. It modifies the slice given! -func permissionDescsHaveDups(descs []PermissionDesc) bool { - sort.Slice(descs, func(i, j int) bool { - return descs[i].Less(descs[j]) - }) - for i := range descs { - if i == 0 { - continue - } - j := i - 1 - if descs[i].Type != descs[j].Type { - continue - } - switch descs[i].Type { - case PermissionWildcard: - return true - case PermissionHash: - if descs[i].Hash() == descs[j].Hash() { - return true - } - case PermissionGroup: - if descs[i].Group().Cmp(descs[j].Group()) == 0 { - return true - } - } - } - return false -} diff --git a/pkg/smartcontract/manifest/permission.go b/pkg/smartcontract/manifest/permission.go index 18b67dd7e..254391981 100644 --- a/pkg/smartcontract/manifest/permission.go +++ b/pkg/smartcontract/manifest/permission.go @@ -1,10 +1,12 @@ package manifest import ( + "cmp" "crypto/elliptic" "encoding/json" "errors" "fmt" + "slices" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/util" @@ -89,48 +91,35 @@ func (d *PermissionDesc) Group() *keys.PublicKey { // Less returns true if this value is less than the given PermissionDesc value. func (d *PermissionDesc) Less(d1 PermissionDesc) bool { - if d.Type < d1.Type { - return true - } - if d.Type != d1.Type { - return false + return d.Compare(d1) < 0 +} + +// Compare performs three-way comparison of two [PermissionDesc] values. +func (d PermissionDesc) Compare(d1 PermissionDesc) int { + r := cmp.Compare(d.Type, d1.Type) + if r != 0 { + return r } switch d.Type { case PermissionHash: - return d.Hash().Less(d1.Hash()) + return d.Hash().Compare(d1.Hash()) case PermissionGroup: - return d.Group().Cmp(d1.Group()) < 0 + return d.Group().Cmp(d1.Group()) } - return false + return 0 // wildcard or type that we can't compare. } // Equals returns true if both PermissionDesc values are the same. func (d *PermissionDesc) Equals(v PermissionDesc) bool { - if d.Type != v.Type { - return false - } - switch d.Type { - case PermissionHash: - return d.Hash().Equals(v.Hash()) - case PermissionGroup: - return d.Group().Cmp(v.Group()) == 0 - } - return false + return d.Compare(v) == 0 } // IsValid checks if Permission is correct. func (p *Permission) IsValid() error { - for i := range p.Methods.Value { - if p.Methods.Value[i] == "" { - return errors.New("empty method name") - } + if slices.Contains(p.Methods.Value, "") { + return errors.New("empty method name") } - if len(p.Methods.Value) < 2 { - return nil - } - names := make([]string, len(p.Methods.Value)) - copy(names, p.Methods.Value) - if stringsHaveDups(names) { + if sliceHasDups(p.Methods.Value, cmp.Compare) { return errors.New("duplicate method names") } return nil @@ -144,14 +133,9 @@ func (ps Permissions) AreValid() error { return err } } - if len(ps) < 2 { - return nil - } - contracts := make([]PermissionDesc, 0, len(ps)) - for i := range ps { - contracts = append(contracts, ps[i].Contract) - } - if permissionDescsHaveDups(contracts) { + if sliceHasDups(ps, func(a, b Permission) int { + return a.Contract.Compare(b.Contract) + }) { return errors.New("contracts have duplicates") } return nil @@ -166,17 +150,10 @@ func (p *Permission) IsAllowed(hash util.Uint160, m *Manifest, method string) bo return false } case PermissionGroup: - has := false - g := p.Contract.Group() - for i := range m.Groups { - if g.Equal(m.Groups[i].PublicKey) { - has = true - break - } - } - if !has { - return false - } + contractG := p.Contract.Group() + return slices.ContainsFunc(m.Groups, func(manifestG Group) bool { + return contractG.Equal(manifestG.PublicKey) + }) default: panic(fmt.Sprintf("unexpected permission: %d", p.Contract.Type)) } diff --git a/pkg/smartcontract/parameter.go b/pkg/smartcontract/parameter.go index 24577d854..0b1bb96ab 100644 --- a/pkg/smartcontract/parameter.go +++ b/pkg/smartcontract/parameter.go @@ -9,6 +9,7 @@ import ( "fmt" "math/big" "os" + "slices" "strings" "unicode/utf8" @@ -199,7 +200,8 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) { // NewParameterFromString returns a new Parameter initialized from the given // string in neo-go-specific format. It is intended to be used in user-facing // interfaces and has some heuristics in it to simplify parameter passing. The exact -// syntax is documented in the cli documentation. +// syntax is documented in the cli documentation. [errors.ErrUnsupported] will be +// returned in case of unsupported parameter types. func NewParameterFromString(in string) (*Parameter, error) { var ( char rune @@ -226,7 +228,7 @@ func NewParameterFromString(in string) (*Parameter, error) { } // We currently do not support following types: if res.Type == ArrayType || res.Type == MapType || res.Type == InteropInterfaceType || res.Type == VoidType { - return nil, fmt.Errorf("unsupported parameter type %s", res.Type) + return nil, fmt.Errorf("%w: type %s", errors.ErrUnsupported, res.Type) } buf.Reset() hadType = true @@ -263,7 +265,8 @@ func NewParameterFromString(in string) (*Parameter, error) { // NewParameterFromValue infers Parameter type from the value given and adjusts // the value if needed. It does not copy the value if it can avoid doing so. All // regular integers, util.*, keys.PublicKey*, string and bool types are supported, -// slice of byte slices is accepted and converted as well. +// slice of byte slices is accepted and converted as well. [errors.ErrUnsupported] +// will be returned for types that can't be used now. func NewParameterFromValue(value any) (Parameter, error) { var result = Parameter{ Value: value, @@ -349,10 +352,8 @@ func NewParameterFromValue(value any) (Parameter, error) { result.Type = ArrayType result.Value = arr case []Parameter: - arr := make([]Parameter, len(v)) - copy(arr, v) result.Type = ArrayType - result.Value = arr + result.Value = slices.Clone(v) case []*keys.PublicKey: return NewParameterFromValue(keys.PublicKeys(v)) case keys.PublicKeys: @@ -374,7 +375,7 @@ func NewParameterFromValue(value any) (Parameter, error) { case nil: result.Type = AnyType default: - return result, fmt.Errorf("unsupported parameter %T", value) + return result, fmt.Errorf("%w: %T type", errors.ErrUnsupported, value) } return result, nil @@ -397,6 +398,7 @@ func NewParametersFromValues(values ...any) ([]Parameter, error) { // ExpandParameterToEmitable converts a parameter to a type which can be handled as // an array item by emit.Array. It correlates with the way an RPC server handles // FuncParams for invoke* calls inside the request.ExpandArrayIntoScript function. +// [errors.ErrUnsupported] is returned for unsupported types. func ExpandParameterToEmitable(param Parameter) (any, error) { var err error switch t := param.Type; t { @@ -411,7 +413,7 @@ func ExpandParameterToEmitable(param Parameter) (any, error) { } return res, nil case MapType, InteropInterfaceType, UnknownType, VoidType: - return nil, fmt.Errorf("unsupported parameter type: %s", t.String()) + return nil, fmt.Errorf("%w: %s type", errors.ErrUnsupported, t.String()) default: return param.Value, nil } diff --git a/pkg/smartcontract/parameter_test.go b/pkg/smartcontract/parameter_test.go index 1413b246e..d9cd889df 100644 --- a/pkg/smartcontract/parameter_test.go +++ b/pkg/smartcontract/parameter_test.go @@ -787,11 +787,11 @@ func TestParameterFromValue(t *testing.T) { }, { value: make(map[string]int), - err: "unsupported parameter map[string]int", + err: "unsupported operation: map[string]int type", }, { value: []any{1, 2, make(map[string]int)}, - err: "unsupported parameter map[string]int", + err: "unsupported operation: map[string]int type", }, } diff --git a/pkg/smartcontract/rpcbinding/binding.go b/pkg/smartcontract/rpcbinding/binding.go index 02f363496..5d98f2e18 100644 --- a/pkg/smartcontract/rpcbinding/binding.go +++ b/pkg/smartcontract/rpcbinding/binding.go @@ -2,7 +2,7 @@ package rpcbinding import ( "fmt" - "sort" + "slices" "strings" "text/template" "unicode" @@ -390,8 +390,7 @@ func NewConfig() binding.Config { func Generate(cfg binding.Config) error { // Avoid changing *cfg.Manifest. mfst := *cfg.Manifest - mfst.ABI.Methods = make([]manifest.Method, len(mfst.ABI.Methods)) - copy(mfst.ABI.Methods, cfg.Manifest.ABI.Methods) + mfst.ABI.Methods = slices.Clone(mfst.ABI.Methods) cfg.Manifest = &mfst var imports = make(map[string]struct{}) @@ -434,9 +433,7 @@ func Generate(cfg binding.Config) error { for k := range cfg.NamedTypes { ctr.NamedTypes = append(ctr.NamedTypes, cfg.NamedTypes[k]) } - sort.Slice(ctr.NamedTypes, func(i, j int) bool { - return strings.Compare(ctr.NamedTypes[i].Name, ctr.NamedTypes[j].Name) < 0 - }) + slices.SortFunc(ctr.NamedTypes, func(a, b binding.ExtendedType) int { return strings.Compare(a.Name, b.Name) }) // Check resulting named types and events don't have duplicating field names. for _, t := range ctr.NamedTypes { @@ -848,7 +845,7 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st for imp := range imports { ctr.Imports = append(ctr.Imports, imp) } - sort.Strings(ctr.Imports) + slices.Sort(ctr.Imports) return ctr } diff --git a/pkg/smartcontract/zkpbinding/binding.go b/pkg/smartcontract/zkpbinding/binding.go index 91ab10ba1..bfb1b1a19 100644 --- a/pkg/smartcontract/zkpbinding/binding.go +++ b/pkg/smartcontract/zkpbinding/binding.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "io" + "slices" "text/template" "github.com/consensys/gnark-crypto/ecc" @@ -22,7 +23,6 @@ import ( curve "github.com/consensys/gnark/backend/groth16/bls12-381" "github.com/consensys/gnark/backend/witness" "github.com/nspcc-dev/neo-go/pkg/smartcontract/binding" - "github.com/nspcc-dev/neo-go/pkg/util/slice" ) // Config represents a configuration for Verifier Go smart contract generator. @@ -165,7 +165,7 @@ supportedstandards: []` // and dependency packages version needed for smart contract compilation. verifyGomod = `module verify -go 1.20 +go 1.21 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231004150345-8849ccde2524 ` @@ -320,7 +320,7 @@ func GetVerifyProofArgs(proof groth16.Proof, publicWitness witness.Witness) (*Ve for i := range input { // firstly - public witnesses, after that - private ones (but they are missing from publicWitness anyway). start := offset + i*fr.Bytes end := start + fr.Bytes - slice.Reverse(publicWitnessBytes[start:end]) // gnark stores witnesses in the BE form, but native CryptoLib accepts LE-encoded fields elements (not a canonical form). + slices.Reverse(publicWitnessBytes[start:end]) // gnark stores witnesses in the BE form, but native CryptoLib accepts LE-encoded fields elements (not a canonical form). input[i] = publicWitnessBytes[start:end] } return &VerifyProofArgs{ diff --git a/pkg/util/bitfield/bitfield.go b/pkg/util/bitfield/bitfield.go index 62f51c5da..ee5f84fb8 100644 --- a/pkg/util/bitfield/bitfield.go +++ b/pkg/util/bitfield/bitfield.go @@ -5,6 +5,8 @@ providing only things used by neo-go. */ package bitfield +import "slices" + // Field is a bit field represented as a slice of uint64 values. type Field []uint64 @@ -32,9 +34,7 @@ func (f Field) IsSet(i int) bool { // Copy makes a copy of the current Field. func (f Field) Copy() Field { - fn := make(Field, len(f)) - copy(fn, f) - return fn + return slices.Clone(f) } // And implements logical AND between f's and m's bits saving the result into f. @@ -51,15 +51,7 @@ func (f Field) And(m Field) { // Equals compares two Fields and returns true if they're equal. func (f Field) Equals(o Field) bool { - if len(f) != len(o) { - return false - } - for i := range f { - if f[i] != o[i] { - return false - } - } - return true + return slices.Equal(f, o) } // IsSubset returns true when f is a subset of o (only has bits set that are diff --git a/pkg/util/slice/array.go b/pkg/util/slice/array.go deleted file mode 100644 index 9be387e45..000000000 --- a/pkg/util/slice/array.go +++ /dev/null @@ -1,30 +0,0 @@ -/* -Package slice contains byte slice helpers. -*/ -package slice - -// CopyReverse returns a new byte slice containing reversed version of the -// original. -func CopyReverse(b []byte) []byte { - dest := make([]byte, len(b)) - reverse(dest, b) - return dest -} - -// Reverse does in-place reversing of byte slice. -func Reverse(b []byte) { - reverse(b, b) -} - -func reverse(dst []byte, src []byte) { - for i, j := 0, len(src)-1; i <= j; i, j = i+1, j-1 { - dst[i], dst[j] = src[j], src[i] - } -} - -// Clean wipes the data in b by filling it with zeros. -func Clean(b []byte) { - for i := range b { - b[i] = 0 - } -} diff --git a/pkg/util/slice/array_test.go b/pkg/util/slice/array_test.go deleted file mode 100644 index ae7ccd162..000000000 --- a/pkg/util/slice/array_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package slice - -import ( - "bytes" - "testing" - - "github.com/stretchr/testify/require" -) - -var testCases = []struct { - arr []byte - rev []byte -}{ - { - arr: []byte{}, - rev: []byte{}, - }, - { - arr: []byte{0x01}, - rev: []byte{0x01}, - }, - { - arr: []byte{0x01, 0x02, 0x03, 0x04}, - rev: []byte{0x04, 0x03, 0x02, 0x01}, - }, - { - arr: []byte{0x01, 0x02, 0x03, 0x04, 0x05}, - rev: []byte{0x05, 0x04, 0x03, 0x02, 0x01}, - }, -} - -func TestCopyReverse(t *testing.T) { - for _, tc := range testCases { - arg := bytes.Clone(tc.arr) - require.Equal(t, tc.arr, arg) - - have := CopyReverse(arg) - require.Equal(t, tc.rev, have) - - // test that argument was copied - for i := range have { - have[i] = ^have[i] - } - require.Equal(t, tc.arr, arg) - - Reverse(arg) - require.Equal(t, tc.rev, arg) - if len(tc.arr) > 1 { - require.NotEqual(t, tc.arr, arg) - } - } -} - -func TestClean(t *testing.T) { - for _, tc := range testCases[1:] { // Empty one will be equal. - cp := bytes.Clone(tc.arr) - Clean(cp) - require.NotEqual(t, tc.arr, cp) - } -} diff --git a/pkg/util/uint160.go b/pkg/util/uint160.go index a7d9bcb48..9d1d362f3 100644 --- a/pkg/util/uint160.go +++ b/pkg/util/uint160.go @@ -1,13 +1,14 @@ package util import ( + "bytes" "encoding/hex" "encoding/json" "fmt" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/util/slice" ) // Uint160Size is the size of Uint160 in bytes. @@ -74,7 +75,8 @@ func (u Uint160) BytesBE() []byte { // BytesLE returns a little-endian byte representation of u. func (u Uint160) BytesLE() []byte { - return slice.CopyReverse(u.BytesBE()) + slices.Reverse(u[:]) // u is a copy, can be changed. + return u[:] } // String implements the stringer interface. @@ -118,6 +120,11 @@ func (u Uint160) Less(other Uint160) bool { return false } +// Compare performs three-way comparison of one Uint160 to another. +func (u Uint160) Compare(other Uint160) int { + return bytes.Compare(u[:], other[:]) +} + // UnmarshalJSON implements the json unmarshaller interface. func (u *Uint160) UnmarshalJSON(data []byte) (err error) { var js string @@ -134,7 +141,7 @@ func (u Uint160) MarshalJSON() ([]byte, error) { r := make([]byte, 3+Uint160Size*2+1) copy(r, `"0x`) r[len(r)-1] = '"' - slice.Reverse(u[:]) // u is a copy, so we can mangle it in any way. + slices.Reverse(u[:]) // u is a copy, so we can mangle it in any way. hex.Encode(r[3:], u[:]) return r, nil } diff --git a/pkg/util/uint160_test.go b/pkg/util/uint160_test.go index 4d3cb3a44..4d670101e 100644 --- a/pkg/util/uint160_test.go +++ b/pkg/util/uint160_test.go @@ -114,6 +114,10 @@ func TestUInt160Less(t *testing.T) { assert.Equal(t, true, ua.Less(ub)) assert.Equal(t, false, ua.Less(ua2)) assert.Equal(t, false, ub.Less(ua)) + assert.Equal(t, -1, ua.Compare(ub)) + assert.Equal(t, 1, ub.Compare(ua)) + assert.Equal(t, 0, ua.Compare(ua)) + assert.Equal(t, 0, ub.Compare(ub)) } func TestUInt160String(t *testing.T) { diff --git a/pkg/util/uint256.go b/pkg/util/uint256.go index 73e89ee88..b6d7cf68a 100644 --- a/pkg/util/uint256.go +++ b/pkg/util/uint256.go @@ -5,10 +5,10 @@ import ( "encoding/hex" "encoding/json" "fmt" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/util/slice" ) // Uint256Size is the size of Uint256 in bytes. @@ -26,7 +26,7 @@ func Uint256DecodeStringLE(s string) (u Uint256, err error) { if err != nil { return u, err } - slice.Reverse(b) + slices.Reverse(b) return Uint256DecodeBytesBE(b) } @@ -55,8 +55,12 @@ func Uint256DecodeBytesBE(b []byte) (u Uint256, err error) { // Uint256DecodeBytesLE attempts to decode the given string (in LE representation) into a Uint256. func Uint256DecodeBytesLE(b []byte) (u Uint256, err error) { - b = slice.CopyReverse(b) - return Uint256DecodeBytesBE(b) + if len(b) != Uint256Size { + return u, fmt.Errorf("expected []byte of size %d got %d", Uint256Size, len(b)) + } + u = Uint256(b) + slices.Reverse(u[:]) + return u, nil } // BytesBE returns a byte slice representation of u. @@ -72,7 +76,8 @@ func (u Uint256) Reverse() Uint256 { // BytesLE return a little-endian byte representation of u. func (u Uint256) BytesLE() []byte { - return slice.CopyReverse(u.BytesBE()) + slices.Reverse(u[:]) // u is a copy, can be changed. + return u[:] } // Equals returns true if both Uint256 values are the same. @@ -111,17 +116,17 @@ func (u Uint256) MarshalJSON() ([]byte, error) { r := make([]byte, 3+Uint256Size*2+1) copy(r, `"0x`) r[len(r)-1] = '"' - slice.Reverse(u[:]) // u is a copy, so we can mangle it in any way. + slices.Reverse(u[:]) // u is a copy, so we can mangle it in any way. hex.Encode(r[3:], u[:]) return r, nil } -// CompareTo compares two Uint256 with each other. Possible output: 1, -1, 0 +// Compare performs three-way comparison of two Uint256. Possible output: 1, -1, 0 // // 1 implies u > other. // -1 implies u < other. // 0 implies u = other. -func (u Uint256) CompareTo(other Uint256) int { return bytes.Compare(u[:], other[:]) } +func (u Uint256) Compare(other Uint256) int { return bytes.Compare(u[:], other[:]) } // EncodeBinary implements the io.Serializable interface. func (u *Uint256) EncodeBinary(w *io.BinWriter) { diff --git a/pkg/util/uint256_test.go b/pkg/util/uint256_test.go index cbbeda216..c4e943240 100644 --- a/pkg/util/uint256_test.go +++ b/pkg/util/uint256_test.go @@ -83,7 +83,7 @@ func TestUInt256Equals(t *testing.T) { require.NoError(t, err) assert.False(t, ua.Equals(ub), "%s and %s cannot be equal", ua, ub) assert.True(t, ua.Equals(ua), "%s and %s must be equal", ua, ua) - assert.Zero(t, ua.CompareTo(ua), "%s and %s must be equal", ua, ua) + assert.Zero(t, ua.Compare(ua), "%s and %s must be equal", ua, ua) } func TestUint256_Serializable(t *testing.T) { diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 9a5be2a1e..ca21d6d30 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "slices" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "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. func (c *Context) BreakPoints() []int { - res := make([]int, len(c.sc.breakPoints)) - copy(res, c.sc.breakPoints) - return res + return slices.Clone(c.sc.breakPoints) } diff --git a/pkg/vm/contract_checks_test.go b/pkg/vm/contract_checks_test.go index 7bb9ef08a..3a3007131 100644 --- a/pkg/vm/contract_checks_test.go +++ b/pkg/vm/contract_checks_test.go @@ -2,6 +2,7 @@ package vm import ( "encoding/binary" + "slices" "testing" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -143,54 +144,48 @@ func TestIsScriptCorrect(t *testing.T) { good := w.Bytes() - getScript := func() []byte { - s := make([]byte, len(good)) - copy(s, good) - return s - } - t.Run("good", func(t *testing.T) { require.NoError(t, IsScriptCorrect(good, nil)) }) t.Run("bad instruction", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[retOff] = 0xff require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("out of bounds JMP 1", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[jmpOff+1] = 0x80 // -128 require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("out of bounds JMP 2", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[jmpOff+1] = 0x7f require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("bad JMP offset 1", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[jmpOff+1] = 0xff // into "something" require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("bad JMP offset 2", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[jmpOff+1] = byte(pushOff - jmpOff + 1) require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("out of bounds JMPL 1", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[jmplOff+1] = byte(-jmplOff - 1) require.Error(t, IsScriptCorrect(bad, nil)) }) 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+2] = 0 bad[jmplOff+3] = 0 @@ -206,25 +201,25 @@ func TestIsScriptCorrect(t *testing.T) { }) t.Run("bad JMPL offset", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[jmplOff+1] = 0xfe // into JMP require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("out of bounds TRY 1", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[tryOff+1] = byte(-tryOff - 1) require.Error(t, IsScriptCorrect(bad, nil)) }) 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 require.Error(t, IsScriptCorrect(bad, nil)) }) 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 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) { - bad := getScript() + bad := slices.Clone(good) bad[trylOff+1] = byte(-(trylOff - jmpOff) - 1) // into "something" require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("bad TRYL offset 2", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[trylOff+5] = byte(len(bad) - trylOff - 1) require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("bad ISTYPE type", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[istypeOff+1] = byte(0xff) require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("bad ISTYPE type (Any)", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[istypeOff+1] = byte(stackitem.AnyT) require.Error(t, IsScriptCorrect(bad, nil)) }) t.Run("good NEWARRAY_T type", func(t *testing.T) { - bad := getScript() + bad := slices.Clone(good) bad[istypeOff] = byte(opcode.NEWARRAYT) bad[istypeOff+1] = byte(stackitem.AnyT) require.NoError(t, IsScriptCorrect(bad, nil)) diff --git a/pkg/vm/debug_test.go b/pkg/vm/debug_test.go index ca5df493a..5441d5de6 100644 --- a/pkg/vm/debug_test.go +++ b/pkg/vm/debug_test.go @@ -57,5 +57,5 @@ func TestContext_BreakPoints(t *testing.T) { // New context -> clean breakpoints. 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()) } diff --git a/pkg/vm/emit/emit.go b/pkg/vm/emit/emit.go index 7a2b1033c..838281325 100644 --- a/pkg/vm/emit/emit.go +++ b/pkg/vm/emit/emit.go @@ -127,6 +127,8 @@ func Array(w *io.BinWriter, es ...any) { // - stackitem.Convertible, stackitem.Item // - nil // - []any +// +// [errors.ErrUnsupported] is returned for unsupported types. func Any(w *io.BinWriter, something any) { switch e := something.(type) { case []any: @@ -181,7 +183,7 @@ func Any(w *io.BinWriter, something any) { StackItem(w, e) default: if something != nil { - w.Err = fmt.Errorf("unsupported type: %T", e) + w.Err = fmt.Errorf("%w: %T type", errors.ErrUnsupported, e) return } Opcodes(w, opcode.PUSHNULL) @@ -199,14 +201,15 @@ func Convertible(w *io.BinWriter, c stackitem.Convertible) { StackItem(w, si) } -// StackItem emits provided stackitem.Item to the given buffer. +// StackItem emits provided stackitem.Item to the given buffer. If it can't +// be emitted [errors.ErrUnsupported] is returned. func StackItem(w *io.BinWriter, si stackitem.Item) { switch t := si.Type(); t { case stackitem.AnyT: if si.Value() == nil { Opcodes(w, opcode.PUSHNULL) } else { - w.Err = fmt.Errorf("only nil value supported for %s", t) + w.Err = fmt.Errorf("%w: %s can only be nil", errors.ErrUnsupported, t) return } case stackitem.BooleanT: @@ -240,7 +243,7 @@ func StackItem(w *io.BinWriter, si stackitem.Item) { Int(w, int64(len(arr))) Opcodes(w, opcode.PACKMAP) default: - w.Err = fmt.Errorf("%s is unsuppoted", t) + w.Err = fmt.Errorf("%w: %s type", errors.ErrUnsupported, t) return } } diff --git a/pkg/vm/emit/emit_test.go b/pkg/vm/emit/emit_test.go index 697a79b3b..962676aac 100644 --- a/pkg/vm/emit/emit_test.go +++ b/pkg/vm/emit/emit_test.go @@ -547,7 +547,7 @@ func TestEmitStackitem(t *testing.T) { for _, si := range itms { buf := io.NewBufBinWriter() StackItem(buf.BinWriter, si) - require.Error(t, buf.Err) + require.ErrorIs(t, buf.Err, errors.ErrUnsupported) } }) @@ -555,8 +555,8 @@ func TestEmitStackitem(t *testing.T) { buf := io.NewBufBinWriter() StackItem(buf.BinWriter, StrangeStackItem{}) actualErr := buf.Err - require.Error(t, actualErr) - require.True(t, strings.Contains(actualErr.Error(), "only nil value supported"), actualErr.Error()) + require.ErrorIs(t, actualErr, errors.ErrUnsupported) + require.True(t, strings.Contains(actualErr.Error(), "Any can only be nil"), actualErr.Error()) }) } diff --git a/pkg/vm/stack.go b/pkg/vm/stack.go index e8f3463ee..f098dfc55 100644 --- a/pkg/vm/stack.go +++ b/pkg/vm/stack.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "slices" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -293,9 +294,7 @@ func (s *Stack) ReverseTop(n int) error { return nil } - for i, j := l-n, l-1; i <= j; i, j = i+1, j-1 { - s.elems[i], s.elems[j] = s.elems[j], s.elems[i] - } + slices.Reverse(s.elems[l-n : l]) return nil } diff --git a/pkg/vm/stackitem/item.go b/pkg/vm/stackitem/item.go index 6eacbea18..0b793d291 100644 --- a/pkg/vm/stackitem/item.go +++ b/pkg/vm/stackitem/item.go @@ -9,6 +9,7 @@ import ( "math" "math/big" "reflect" + "slices" "unicode/utf8" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" @@ -123,17 +124,17 @@ func Make(v any) Item { case Item: return val case []int: - var a []Item - for _, i := range val { - a = append(a, Make(i)) + var res = make([]Item, len(val)) + for i := range val { + res[i] = Make(val[i]) } - return Make(a) + return Make(res) case []string: - var a []Item - for _, i := range val { - a = append(a, Make(i)) + var res = make([]Item, len(val)) + for i := range val { + res[i] = Make(val[i]) } - return Make(a) + return Make(res) case []any: res := make([]Item, len(val)) for i := range val { @@ -348,9 +349,7 @@ func (i *Struct) Convert(typ Type) (Item, error) { case StructT: return i, nil case ArrayT: - arr := make([]Item, len(i.value)) - copy(arr, i.value) - return NewArray(arr), nil + return NewArray(slices.Clone(i.value)), nil case BooleanT: return NewBool(true), nil default: @@ -676,11 +675,9 @@ func (i *ByteArray) equalsLimited(s Item, limit *int) bool { if !ok { return false } - comparedSize = lCurr lOther := len(*val) - if lOther > comparedSize { - comparedSize = lOther - } + comparedSize = max(lCurr, lOther) + if i == val { return true } @@ -795,9 +792,7 @@ func (i *Array) Convert(typ Type) (Item, error) { case ArrayT: return i, nil case StructT: - arr := make([]Item, len(i.value)) - copy(arr, i.value) - return NewStruct(arr), nil + return NewStruct(slices.Clone(i.value)), nil case BooleanT: return NewBool(true), nil default: @@ -881,12 +876,9 @@ func (i *Map) String() string { // Index returns an index of the key in map. func (i *Map) Index(key Item) int { - for k := range i.value { - if i.value[k].Key.Equals(key) { - return k - } - } - return -1 + return slices.IndexFunc(i.value, func(e MapElement) bool { + return e.Key.Equals(key) + }) } // Has checks if the map has the specified key. diff --git a/pkg/vm/stackitem/serialization.go b/pkg/vm/stackitem/serialization.go index 35e4d0713..190ca8640 100644 --- a/pkg/vm/stackitem/serialization.go +++ b/pkg/vm/stackitem/serialization.go @@ -133,9 +133,7 @@ func (w *SerializationContext) Serialize(item Item, protected bool) ([]byte, err if w.data != nil { w.data = w.data[:0] } - for k := range w.seen { - delete(w.seen, k) - } + clear(w.seen) err := w.serialize(item) if err != nil && protected { if w.data == nil { diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index cee81b9cc..39ea54124 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -10,6 +10,7 @@ import ( "math" "math/big" "os" + "slices" "text/tabwriter" "unicode/utf8" @@ -22,7 +23,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/vm/invocations" "github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" @@ -1352,13 +1352,10 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro if t.(stackitem.Immutable).IsReadOnly() { panic(stackitem.ErrReadOnly) } - a := t.Value().([]stackitem.Item) - for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { - a[i], a[j] = a[j], a[i] - } + slices.Reverse(t.Value().([]stackitem.Item)) case *stackitem.Buffer: b := t.Value().([]byte) - slice.Reverse(b) + slices.Reverse(b) default: panic(fmt.Sprintf("invalid item type %s", t)) } @@ -1876,7 +1873,10 @@ func (v *VM) ContractHasTryBlock() bool { // CheckMultisigPar checks if the sigs contains sufficient valid signatures. func CheckMultisigPar(v *VM, curve elliptic.Curve, h []byte, pkeys [][]byte, sigs [][]byte) bool { if len(sigs) == 1 { - return checkMultisig1(v, curve, h, pkeys, sigs[0]) + return slices.ContainsFunc(pkeys, func(keyb []byte) bool { + pkey := bytesToPublicKey(keyb, curve) + return pkey.Verify(sigs[0], h) + }) } k1, k2 := 0, len(pkeys)-1 @@ -1966,17 +1966,6 @@ loop: return sigok } -func checkMultisig1(v *VM, curve elliptic.Curve, h []byte, pkeys [][]byte, sig []byte) bool { - for i := range pkeys { - pkey := bytesToPublicKey(pkeys[i], curve) - if pkey.Verify(sig, h) { - return true - } - } - - return false -} - func cloneIfStruct(item stackitem.Item) stackitem.Item { switch it := item.(type) { case *stackitem.Struct: diff --git a/pkg/wallet/account.go b/pkg/wallet/account.go index 558e4449a..0702dc6e0 100644 --- a/pkg/wallet/account.go +++ b/pkg/wallet/account.go @@ -3,6 +3,7 @@ package wallet import ( "errors" "fmt" + "slices" "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -111,24 +112,16 @@ func NewContractAccount(hash util.Uint160, args ...any) *Account { // SignTx signs transaction t and updates it's Witnesses. func (a *Account) SignTx(net netmode.Magic, t *transaction.Transaction) error { - var ( - haveAcc bool - pos int - ) if a.Locked { return errors.New("account is locked") } if a.Contract == nil { return errors.New("account has no contract") } - for i := range t.Signers { - if t.Signers[i].Account.Equals(a.ScriptHash()) { - haveAcc = true - pos = i - break - } - } - if !haveAcc { + var pos = slices.IndexFunc(t.Signers, func(s transaction.Signer) bool { + return s.Account.Equals(a.ScriptHash()) + }) + if pos == -1 { return errors.New("transaction is not signed by this account") } if len(t.Scripts) < pos { @@ -150,14 +143,12 @@ func (a *Account) SignTx(net netmode.Magic, t *transaction.Transaction) error { if a.privateKey == nil { return errors.New("account key is not available (need to decrypt?)") } - sign := a.privateKey.SignHashable(uint32(net), t) - invoc := append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, sign...) - if len(a.Contract.Parameters) == 1 { - t.Scripts[pos].InvocationScript = invoc - } else { - t.Scripts[pos].InvocationScript = append(t.Scripts[pos].InvocationScript, invoc...) + if len(a.Contract.Parameters) == 1 && t.Scripts[pos].InvocationScript != nil { + t.Scripts[pos].InvocationScript = t.Scripts[pos].InvocationScript[:0] } + t.Scripts[pos].InvocationScript = append(t.Scripts[pos].InvocationScript, byte(opcode.PUSHDATA1), keys.SignatureLen) + t.Scripts[pos].InvocationScript = append(t.Scripts[pos].InvocationScript, a.privateKey.SignHashable(uint32(net), t)...) return nil } @@ -291,15 +282,7 @@ func (a *Account) ConvertMultisig(m int, pubs []*keys.PublicKey) error { // with m sufficient signatures. The encrypted private key is not modified and // remains the same. func (a *Account) ConvertMultisigEncrypted(accKey *keys.PublicKey, m int, pubs []*keys.PublicKey) error { - var found bool - for i := range pubs { - if accKey.Equal(pubs[i]) { - found = true - break - } - } - - if !found { + if !slices.ContainsFunc(pubs, accKey.Equal) { return errors.New("own public key was not found among multisig keys") } diff --git a/scripts/compare-dumps/compare-dumps.go b/scripts/compare-dumps/compare-dumps.go index 4e5621498..bbed4f6bc 100644 --- a/scripts/compare-dumps/compare-dumps.go +++ b/scripts/compare-dumps/compare-dumps.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "cmp" "encoding/base64" "encoding/binary" "encoding/hex" @@ -10,7 +11,7 @@ import ( "fmt" "os" "path/filepath" - "sort" + "slices" "github.com/urfave/cli/v2" ) @@ -61,9 +62,7 @@ func (d dump) normalize() { } newStorage = append(newStorage, d[i].Storage[j]) } - sort.Slice(newStorage, func(k, l int) bool { - return newStorage[k].Key < newStorage[l].Key - }) + slices.SortFunc(newStorage, func(a, b storageOp) int { return cmp.Compare(a.Key, b.Key) }) d[i].Storage = newStorage } // assume that d is already sorted by Block