Compare commits

..

4 commits

Author SHA1 Message Date
Anna Shaleva
c49dba2db0 notary: add an example of attack on notary service 2023-07-19 19:24:21 +03:00
Anna Shaleva
133082ed58 core: check signers of on-chained conflict during new tx verification
During new transaction verification if there's an on-chain conflicting
transaction, we should check the signers of this conflicting transaction.
If the signers intersect with signers of the incoming transaction, then
the conflict is treated as valid and verification for new incoming
transaction should fail. Otherwise, the conflict is treated as the
malicious attack attempt and will not be taken into account;
verification for the new incoming transaction should continue.

This commint implements the scheme described at
https://github.com/neo-project/neo/pull/2818#issuecomment-1632972055,
thanks to @shargon for digging.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-19 14:52:59 +03:00
Anna Shaleva
cf4001d31c core: fix formatted error on transaction verification
Witnesses are not yet created by the moment we return this error,
thus, it was always 0 as an actual number of witnesses in
ErrInvalidWitnessNum.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-14 11:42:27 +03:00
Anna Shaleva
edd4f390ad core: remove unused blockchain API
`(*Blockchain).HasTransaction` is one of the oldest methods in our
codebase, and currently it's completely unused. I also doubt that
this method works as expected because it returns `true` if transaction
in the mempool.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-14 10:53:35 +03:00
494 changed files with 11453 additions and 20815 deletions

View file

@ -16,7 +16,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
},
{
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
}
],
"scrypt": {

View file

@ -16,7 +16,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
},
{
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
},
{
"address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP",
@ -58,7 +58,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
}
],
"scrypt": {

View file

@ -16,7 +16,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
},
{
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
}
],
"scrypt": {

View file

@ -16,7 +16,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
},
{
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
}
],
"scrypt": {

View file

@ -16,7 +16,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
},
{
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false
},
"lock": false,
"isDefault": false
"isdefault": false
}
],
"scrypt": {

2
.github/CODEOWNERS vendored
View file

@ -1 +1 @@
* @AnnaShaleva @roman-khimov
* @AnnaShaleva @roman-khimov @fyrchik

View file

@ -37,23 +37,29 @@ jobs:
runs-on: ${{matrix.os.name}}
strategy:
matrix:
os: [{ name: ubuntu-22.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }]
os: [{ name: ubuntu-20.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }]
arch: [amd64, arm64]
exclude:
- os: { name: windows-2022, bin-name: windows }
arch: 'arm64'
- os: { name: macos-12, bin-name: darwin }
arch: 'amd64'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.ref }}
# Allows to fetch all history for all branches and tags. Need this for proper versioning.
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22'
go-version: '1.20'
cache: true
- name: Update Go modules
run: go mod download -json
- name: Build CLI
run: make build
@ -64,7 +70,7 @@ jobs:
run: mv ./bin/neo-go* ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}
path: ./bin/neo-go*
@ -79,23 +85,23 @@ jobs:
build_image:
needs: build_cli
name: Build and push docker image
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.ref }}
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
@ -110,7 +116,7 @@ jobs:
run: echo "latest=,${{ steps.setvars.outputs.repo }}:latest" >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
@ -126,20 +132,21 @@ jobs:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.ref }}
fetch-depth: 0
# For proper `deps` make target execution.
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22'
go-version: '1.20'
cache: true
- name: Login to DockerHub
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

View file

@ -1,11 +0,0 @@
name: Contribution guidelines
on:
pull_request:
branches:
- master
jobs:
commits_check_job:
name: DCO check
uses: nspcc-dev/.github/.github/workflows/dco.yml@master

21
.github/workflows/dco.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: DCO check
on:
pull_request:
branches:
- master
jobs:
commits_check_job:
runs-on: ubuntu-latest
name: Commits Check
steps:
- name: Get PR Commits
id: 'get-pr-commits'
uses: tim-actions/get-pr-commits@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: DCO Check
uses: tim-actions/dco@master
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}

View file

@ -8,7 +8,7 @@ on:
- master
types: [opened, synchronize]
paths-ignore:
- 'scripts/*.sh'
- 'scripts/**'
- '**/*.md'
workflow_dispatch:
@ -18,61 +18,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/setup-go@v4
with:
go-version-file: 'go.mod'
go-version: '1.18'
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v3
with:
version: latest
skip-pkg-cache: true # golangci-lint can't work with this cache enabled, ref. https://github.com/golangci/golangci-lint-action/issues/135.
gomodcheck:
name: Check internal dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check dependencies
run: |
./scripts/check_deps.sh
- name: Check go.mod is tidy
run: |
go mod tidy
if [[ $(git diff --name-only go.* | grep '' -c) != 0 ]]; then
echo "go mod tidy should be executed before the merge, following packages are unused or out of date:";
git diff go.*;
exit 1;
fi
codegencheck:
name: Check code generated with 'go generate' is up-to-date
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Install stringer
run: go install golang.org/x/tools/cmd/stringer@latest
- name: Run go generate
run: go generate ./...
- name: Check that autogenerated code is up-to-date
run: |
if [[ $(git diff --name-only | grep '' -c) != 0 ]]; then
echo "Fresh version of autogenerated code should be committed for the following files:";
git diff --name-only;
exit 1;
fi
codeql:
name: CodeQL
@ -88,11 +53,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -103,7 +68,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -117,37 +82,41 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2
test_cover:
name: Coverage
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
env:
CGO_ENABLED: 0
GOEXPERIMENT: nocoverageredesign
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: 'true'
- name: Sync VM submodule
run: |
git submodule sync
git submodule update --init
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22'
go-version: '1.20'
cache: true
- name: Update Go modules
run: go mod download -json
- name: Write coverage profile
run: go test -timeout 15m -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
run: go test -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
- name: Upload coverage results to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v2
with:
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
files: ./coverage.txt
slug: nspcc-dev/neo-go
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
tests:
@ -155,36 +124,40 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, windows-2022, macos-12, macos-14]
go_versions: [ '1.20', '1.21', '1.22' ]
os: [ubuntu-20.04, windows-2022, macos-12]
go_versions: [ '1.18', '1.19', '1.20' ]
exclude:
# Only latest Go version for Windows and MacOS.
- os: windows-2022
go_versions: '1.20'
go_versions: '1.18'
- os: windows-2022
go_versions: '1.21'
go_versions: '1.19'
- os: macos-12
go_versions: '1.20'
go_versions: '1.18'
- os: macos-12
go_versions: '1.21'
- os: macos-14
go_versions: '1.20'
- os: macos-14
go_versions: '1.21'
go_versions: '1.19'
# Exclude latest Go version for Ubuntu as Coverage uses it.
- os: ubuntu-22.04
go_versions: '1.22'
- os: ubuntu-20.04
go_versions: '1.20'
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: 'true'
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '${{ matrix.go_versions }}'
cache: true
- name: Update Go modules
run: go mod download -json
- name: Sync VM submodule
run: |
git submodule sync
git submodule update --init
- name: Run tests
run: go test -timeout 15m -v -race ./...
run: go test -v -race ./...

View file

@ -2,479 +2,6 @@
This document outlines major changes between releases.
## 0.106.1 "Implication" (3 Jun 2024)
An urgent release that fixes mainnet state difference at block 5462944 which halts
blocks processing starting from the height 5468658. This release requires full node
DB resynchronization for mainnet nodes. T5 testnet DB state is not affected by this
bug (at least up to the current 4087361 height). Thus, DB resynchronisation may be
skipped for testnet nodes. No configuration changes implied.
Bugs fixed:
* mainnet state difference at block 5462944 caused by runtime notification
permissions check against the updated contract state instead of executing state
(#3472)
* unused neofs-contract dependency in the node modules (#3458)
## 0.106.0 "Zephyranthes" (21 May 2024)
We're rolling out a large set of updates including all of Neo 3.7.4 protocol changes:
native contracts update functionality and extended native contract APIs united under
the upcoming Cockatrice hardfork. For smart contract developers an ability to
generate smart contract bindings with dynamic hash is supported as well as a number
of useful extensions for `unwrap` package, compatible NNS smart contract RPC binding
and a lot of other handy enhancements. This release also includes a couple of severe
regression bug fixes affecting the node state. As a bonus of fixing a wide range of
failing tests, we've refactored the node services start and shutdown procedures to
make it more stable. This version drops support for Go 1.19 and requires 1.20+ to
build (with Go 1.22 supported).
Notice that this release requires full node resynchronization for both mainnet
and testnet nodes. Please pay a special attention to the Cockatrice hardfork schedule
and check your configurations. It should be configured for 3967000 of T5 testnet and
5450000 of mainnet. To ensure compatibility your node must be configured
appropriately.
New features:
* native contracts update functionality bound to hardforks (#3402, #3444)
* Cockatrice hardfork planned for 5450000 block of mainnet and 3967000 block of T5
testnet (#3402, #3448, #3402, #3446)
* `CommitteeChanged` events are emitted by NeoToken native contract starting from
Cockatrice hardfork (#3351, #3448)
* `getCommitteeAddress` method of NeoToken native contract is available starting
from Cockatrice hardfork (#3362, #3402)
* `keccak256` method of CryptoLib native contract is available starting from
Cockatrice hardfork (#3301, #3402)
* dynamic contract hash support for smart contract bindings (#3405)
* support `StringCompressed` API for `crypto.PublicKey` (#3408)
* support `Copy` API for `transaction.Transaction` and `payload.P2PNotaryRequest`
(#3407)
* extend `verifyWithECDsa` method of native CryptoLib contract with Keccak256 hasher
starting from Cockatrice and add an example of custom Koblitz-based and
Keccak256-based transaction witness verification (#3425)
* autogenerated `nativehashes` package (#3402, #3431)
* introduce `unwrap.Exception` type for better RPC invocation result exceptions
detection (#3438)
Behavior changes:
* Neo Name Service smart contract RPC binding follows the official N3 implementation
(#3291)
* clear LastGasPerVote NeoToken account info on unvoting (#3349)
* return fault exception (if any) in `unwrap` RPC client helpers (#3356)
* move P2PNotary designation role out of P2PSigExtensions (#3452)
Improvements:
* support `smartcontract.Convertible` interface as RPC Actor and Invoker call
parameters (#3297)
* allow to import multisignature account into wallet without WIF and password
specified (#3293)
* upgrade go-ordered-json dependency to avoid possible node state incompatibility
issues caused by smart contract manifest marshalling (#3331, #3333)
* Go 1.22 support, bump minimum required Go version up to Go 1.20 (#3336)
* a number of dependent libraries are updated to the fresh versions (#3338, #3418)
* improve error message of `System.Crypto.CheckMultisig` interop API handler (#3374)
* upgrade dBFT library to v0.2.0 (#3371, #3413)
* increase `ValidUntilBlock` value for transactions generated by CLI commands
(#3376)
* documentation updates (#3375, #3382)
* let default Notary Actor options be customizable (#3394)
* extend `getversion` RPC response with RPC server settings (#3386)
* make errors related to wallet opening more detailed (#3389)
* adjust error messages of `setExecFeeFactor` and `setStoragePrice` methods of
native PolicyContract (#3406)
* make neotest chain constructor options customizable (#3404)
* format improvements for CLI commands description (#3410)
* make state dumps comparator script more verbose (#3411)
* refactor storage `Get` implementation for BoltDB (#3441)
* add `updatecounter` field to the resulting items of `getnativecontracts` RPC API
call (#3439)
Bugs fixed:
* node panic on committee missing from node configuration (#3294)
* autogenerated RPC bindings do not follow Go naming convention (#3299)
* a batch of failing tests is fixed (#3306, #3313, #3321, #3332, #3337, #3335,
#3344, #3340, #3350, #3355, #3364, #3368, #3377, #3393, #3397, #3392, #3398,
#3400)
* outdated minimum required Go version of boilerplate contract generated by
`neo-go contract init` (#3318)
* outdated address used as an example in RPC client documentation (#3327)
* ungraceful node services shutdown procedure (#3307)
* logging data race on node services shutdown (#3307)
* Map parameter support is missing from RPC server handlers (#3329)
* smart contract storage iterator prefix wasn't copied while iterating over values
(#3336)
* RPC error with -511 code (insufficient funds) returned on `sendrawtransaction` RPC
request should cover multiple cases of sender's insufficient funds (#3360, #3361)
* reentrancy possibility for Notary deposit withdrawal (#3357)
* null `findstorage` RPC response in case of missing storage items (#3385)
* uninitialized named return variables in compiler (#3401)
* wrong debug sequence points after `JUMP*` instructions shortening by compiler
(#3412)
* corrupted genesis block record and application log caused by improper Conflicts
attribute processing (#3437)
* false positive DB-based blocked accounts detection in native PolicyContract leaded
to invalid committee computations and reward distribution made by NeoToken (#3443)
## 0.105.1 "Enumeration" (12 Jan 2024)
This is another v3.6.2-compatible release that fixes mainnet state difference at
block 4688591. It is confirmed to have the same state up to 4723K height (which
is current), but to get proper mainnet state you need to resynchronize your node
from the genesis. T5 testnet state is not affected (at least up to the current
3323K height), thus DB resynchronisation may be skipped for testnet nodes.
Improvements:
* better network services logging (#3287, #3290)
Bugs fixed:
* state difference at block 4688591 of N3 mainnet caused by difference at
characters escaping during manifest's `Extra` field JSON serialisation (#3286)
## 0.105.0 "Designation" (29 Dec 2023)
We're rolling out an update for NeoGo nodes that contains a number of user-facing
API improvements for RPC web-socket notification subsystem, CLI utility, wallet
related packages and not only. Try out our new `--await` CLI option for those
commands that relay transactions to the network to automatically wait for the
on-chain transaction execution result. Subscribe for new block headers with
extended RPC notification subsystem interface. Use contract-based accounts
provided by `wallet` package and `neotest` framework to sign transactions. These
and a set of other improvements are available to our users while this release is
staying compatible with 3.6.2 version of C# node.
This version also delivers a bug fix for consensus node panic caused by improper
native NeoToken cache initialisation. Moreover, there's a set of RPC server side
improvements, thus, we recommend to upgrade both consensus and RPC nodes to
provide more stable consensus node functioning and extended user APIs functionality.
No database resynchronisation is needed.
New features:
* block headers RPC web-socket subscription (#3252)
* --await option to synchronize on transaction execution for CLI commands (#3265)
* partial session-based RPC iterator unwrapping (#3274)
* contract-based transaction signers in neotest framework (#3233)
* AMD64 release binaries for macOS (#3251)
* complex contract signature schemes in wallet.Account (#3256)
Behavior changes:
* basic RPC subscription filter validity checks are implemented on both RPC
client and RPC server sides (#3258)
* filter of notary request event RPC subscription is extended with `type` field
(#3236)
* if available, use block headers RPC web-socket subscription for transaction
awaiting via `waiter` package API (#3283)
Improvements:
* add smart contract storage limits to interop utilities (#3232)
* extend ZKP examples documentation with additional links to PoT ceremony
response files (#3234)
* support Go types in VM emitter API (#3237)
* documentation update (#3239, #3242, #3246)
* BoltDB (go.etcd.io/bbolt) dependency upgrade (#3250)
* CLI code refactoring (#2682)
* extend wallet package to work with byte slice based wallets (#3255)
* export RPC client side transaction awaiting functionality via `waiter` package
(#3265, #3283)
Bugs fixed:
* remove stale `updatehistory` section of `getnativecontracts` RPC response (#3240)
* immediately check RPC client initialisation on access to blocks RPC subscription
API (#3257, #3261)
* fix CN panic caused by unexpected call to native NeoToken cache (#3253)
* make "automatically generated" warning of all automatically generated files
follow the standard (#3280)
## 0.104.0 "Globalization" (27 Nov 2023)
We're updating NeoGo to push out a number of useful updates and protocol
extensions as well as make it compatible with 3.6.2 version of C# node. The most
invasive behaviour changes are VM-level protocol constraints imposed on the size
of serialized stackitems and `NativeActivation` node setting removal. This version
also delivers a set of smaller useful changes in the interoperability layer and
native contract functionality including System.Runtime.CurrentSigners interop,
`strLen` StdLib method and PolicyContract-based transaction attributes pricing
as far as a user-facing `canceltx` CLI command and community-requested
`--relative-path` CLI option.
Node operators must resynchronize their nodes to get fully compatible state
(which is confirmed to be compatible with 3.6.2 for current mainnet up to
block 4483627 and T5 testnet up to block 3078762). Please, ensure your node
configuration doesn't contain `NativeActivations` protocol configuration section
as this logic is hidden under Hardforks starting from the current release.
New features:
* System.Runtime.CurrentSigners interop allowing to get signers of the currently
loaded transaction (#3058)
* `strLen` method to native StdLib contract (#3208)
* transaction attributes pricing regulation via native PolicyContract (#3155)
* `canceltx` CLI command as an alternative to unsupported `canceltransaction` RPC
request (#3223, #3214)
Behaviour changes:
* reduce maximum allowed stackitem.Item size (#3185)
* restrict maximum allowed NEF file size and prohibit large contracts deployment (#3186)
* bind `NativeActivations` node setting to the `Hardforks` setting (#3212)
* introduce serialization limit to stackitem.Item and fail large contracts deploy
wrt this setting (#3218)
* add customizable `MaxRequestBodyBytes` and `MaxRequestHeaderBytes` RPC server
configuration setting (#3221)
Improvements:
* provide more detailed error on attempt to read non-existent service wallet
provided via node configuration file (#3210)
* optimize emit of imported code for autogenerated RPC bindings (#3215)
* documentation update (#3203, #3222)
* add `--relative-path` CLI flag allowing to override configuration-specific relative
paths (#3206)
* update code owners (#3216, @fyrchik will live in our hearts forever)
Bugs fixed:
* unify messages of RPC errors according to the RPC errors NEP (#3199)
* limit maximum allowed number ad depth of transaction signers and witnesses per
RPC request that accept transaction (#3207, #3221)
* forbid unknown fields usage in the node configuration file (#3209)
* enable hardfork-dependant code starting exactly from the block height specified
in the node configuration (#3211)
* require Notary native deposit to be valid for at least one subsequent block after
deposit transaction acceptance (#3211)
* deduplicate unnamed event types for autogenerated RPC bindings and make the
binding generation order strictly defined and stable (#3215, #3220)
* do not panic on trying to compile an import cycle (#3215)
* state difference at block 3002333 of T5 testnet caused by difference at characters
escaping during manifest's `Extra` field JSON serialisation (#3225)
* properly start node services that depend on native RoleManagement contract data
with genesis `Roles` protocol configuration setting specified (#3229)
## 0.103.1 "Verification" (09 Nov 2023)
An urgent 3.6.0-compatible version that contains a hotfix for the bug that
prevents node from starting from the existing database every new dBFT epoch.
Also, the release includes a bugfix that fails any non-zero NEO and GAS
roundtrips from accounts with zero balance.
Although the DB format and storage states were not affected by this release,
the node resynchronization is still recommended for those who want to keep
correct application logs. Resynchronization can be skipped if you're ok with
wrong application logs for some transactions (e.g. CN doesn't care, and RPC node
cares a lot).
Bugs fixed:
* properly initialize cache of native NeoToken contract every new dBFT epoch (#3187)
* forbid non-zero NEO and GAS roundtrips from accounts with zero balance (#3191)
## 0.103.0 "Backwardation" (20 Oct 2023)
A minor 3.6.0-compatible version of NeoGo with new salty ZKP-related
functionality, a large batch of deprecated APIs removal and an experimental
genesis block extension. Build Groth-16 circuits, generate proofs and deploy
verification contracts easily with the new end-to-end ZKP example and `zkpbinding`
NeoGo API. Setup node roles via the node configuration starting from the genesis
block without any painful multisignature transaction forming and invoke any
custom script in the genesis-level transaction with the new `Genesis` protocol
configuration extension. And don't forget to move from deprecated RPC client
APIs, as a lot of them have been removed.
New node configuration format is finally adapted and the deprecated configuration
sections are permanently removed according to the schedule. Pay attention to the
`SecondsPerBlock` protocol configuration section that was replaced by
`TimePerBlock`, a set of node and services address- and port- related configuration
section that were replaced by the new `Addresses` format, direct `UnlockWallet`
consensus configuration that was replaced by a separate `Consensus` section and
a set of node-specific protocol configurations that were moved under a separate
`P2P` section.
This release fixes a set of bugs including a vulnerability introduced by changes
in the transaction conflicts storage scheme implemented in #3061 (a part of
0.102.0 release). With the patch presented, it's impossible to uncontrollably
pollute the storage with malicious conflicting records.
This version is fully compatible with C# node 3.6.0. However, it requires
complete resynchronization on upgrade due to the database storage scheme changes.
New features:
* API for Groth-16 verification contracts autogeneration and end-to-end example for
proving and verifying statements on NeoGo (#3043, #3146)
* introduce genesis protocol extensions: default node roles designation and genesis
transactions (#3168)
Behaviour changes:
* a lot of deprecated functionality is dropped: RPC client old APIs, shared
Notifications channel of WebSocket client, SecondsPerBlock protocol
configuration, old way of services and node address and port configuration, old
P2P related application settings configuration, direct UnlockWallet consensus
configuration, direct node-specific protocol configuration (#3150)
* database scheme is changed by new way of storing the transaction conflicting
records (#3138)
Improvements:
* NeoFS SDK dependency upgrade (#3129)
* gnark and gnark-crypto dependencies upgrade (#3145, #3162, #3163)
* introduce timeout restriction for BoltDB opening (#3148)
* bump code coverage uploading action version (#3153)
* Go 1.21 support, bump minimum required Go version up to Go 1.19 (#3157)
* upgrade golang.org/x/net version (#3158)
* add protocol hardforks configuration to the `getversion` RPC response (#3160)
* format autogenerated smart contract bindings with accordance to standard `go fmt` rules (#3164)
* add "DO NOT EDIT" warning to the autogenerated smart contract bindings (#3167)
Bugs fixed:
* avoid race between `getnextblockvalidators` RPC call handler and blockchain's
block handler routine, significantly refactor native validators caching scheme
(#3110)
* do not panic on failed NeoFS oracle requests (#3129)
* enable Notary subsystem in NeoFS mainnet configuration (#3136)
* reorganize storage scheme for transaction conflicting records to avoid possible attack (#3138)
* properly deserialize wildcard trusts field of smart contract manifest (#3140)
* use more strict GAS limit for transaction network fee calculation via RPC call (#3141)
* avoid WebSocket client request blocking (#3142)
* properly emit big uint64 constants during smart contract compilation (#3147)
* avoid race access to the node version by tests (#3149)
* make FindStorage* RPC client APIs to be always compatible with NeoC# RPC server (#3166)
## 0.102.0 "Aberration" (06 Sep 2023)
Long-awaited feature-packed 3.6.0-compatible version of NeoGo with all the
appropriate protocol updates and a set of tasty improvements and bug
fixes. Groth16 ZKP proof checks are there for contract developers as well as
new opcodes. A huge number of improvements went into the RPC server and
client, new RPCs, improved contract binding generator and standardized
extended error codes make developing dApps much easier.
Users of smart contract utilities and RPC-related Prometheus metrics are
advised to take a look at the deprecated APIs removal schedule
(ROADMAP.md). This version was delayed for quite some time (waiting for 3.6),
so the next minor release (0.103.0) will remove a substantial amount of
compatibility code. It's expected to be released in November with 3.6 protocol
compatibility (3.7 cycle is likely to require more time).
This is also the first version that drops support for Go 1.17 and requires
1.18+ to build (with Go 1.20 supported). Using generics in smart contracts is
not supported yet, but some elements of this support can be implemented in
future versions.
Mainnet and testnet node operators, please pay attention to the Basilisk
hardfork schedule and check your configurations. It will happen at block
2680000 for T5 testnet and 4120000 for mainnet. To ensure compatibility your
node must be configured appropriately. This version requires DB
resynchronization, so schedule your updates accordingly.
New features:
* ZKP proof checking support via CryptoLib native contract (operations with
BLS12-381 curve points) (#2940, #3042)
* System.Storage.Find interop now support "Backwards" flag to iterate in the
opposite direction (#2952)
* `util ops` CLI utility that pretty-prints VM script (#2965)
* `notarypool_unsorted_tx` Prometheus metric for notary-enabled nodes (#2696)
* `CloseNotificationChannelIfFull` WSClient option allowing the client to
close notification channel on overflow (#2988)
* autogenerated RPC bindings for contract events and conversion code from
stackitem.Item to structure (#3008, #3035, #3036, #3087)
* event type inference from contract code (#3008)
* dynamic contract hashes support for RPC bindings (#3012)
* "Basilisk" protocol hardfork support (#3056, #3080, #3086, #3104)
* ABORTMSG and ASSERTMSG VM opcodes (#3066)
* standardized RPC error codes (#3063)
* `findstorage` and `findstoragehistoric` RPC support (#3099)
* `getstoragehistoric` RPC support (#3099)
* `getrawnotarypool` and `getrawnotarytransaction` RPC (#3098)
Behaviour changes:
* deprecated `FromAddress` smart contract helper is dropped from the `util`
interop package (#2941)
* a number of deprecated RPC-related Prometheus counters are permanently
removed (#2941)
* NEP-2 account label will be asked on account import via CLI (#2889)
* hashes and states of native contracts are now accessible via native
ContractManagement API (#2991)
* `serv_node_version` gauge Prometheus metric is marked as deprecated and
replaced by `neogo_version` and `server_id` (#3009)
* strict contract script check is back with Basilisk hardfork, it was
previously removed in 0.101.3 for 3.5 protocol compatibility (#3056)
* JSON number deserialization (via StdLib.jsonDeserialize) changes with
Basilisk hardfork allowing for more precision and handling more corner
cases (#3080)
* notification type errors are treated as fatal after Basilisk hardfork,
before it they're just logged (#3086)
* NULL and non-UTF8 items are not allowed for String event types (#3086)
* `Conflicts` and `NotValidBefore` transaction attributes are no longer NeoGo
extensions, they can be used on regular networks (#2962)
Improvements:
* documentation and example improvements (#2945, #2972, #2979, #3020, #3084,
#3099, #3114, #3116, #3119, #3121)
* `getproof` and `verifyproof` RPC API support in RPC client (#2942)
* Go 1.20 support, bump minimum required Go version up to Go 1.18 (#2908)
* faster state reset process (#2819)
* optimized voting data storage scheme for NEO contract (#2892, #2893)
* NeoFS SDK dependency upgrades (#2995, #3032)
* special exported error returned in case of WSClient disconnection (#3000)
* automatic guessing of contract and manifest filenames for `contract
compile` CLI command and `loadnef` VM CLI command (#3013)
* support for pushing stackitem.Convertible objects via VM script emitter (#3016)
* economic adjustment for ranking of transactions with `Conflicts` attribute (#3031)
* `google.golang.org/grpc` dependency upgrade fixing high severity security
vulnerability (#3055, gRPC is only used to communicate with NeoFS nodes in
the oracle service)
* enforce default RPC server values when it's used as an independent package
(not a part of node) (#3107)
* unwrap.Nothing function for RPC clients (#3117)
* address and reverse hash display in opcode dumps (#3115)
Bugs fixed:
* invalid peer port type returned by `getpeers` RPC response (#2914)
* invalid data source for `mempool_unsorted_tx` Prometheus metric (#2969)
* dBFT library upgrade fixing the ability of a single node to speed up the
process of new blocks creation for the whole network (#3018,
nspcc-dev/dbft#75)
* failing CALLT instructions in VM CLI for loaded NEF files (#3020)
* missing signers check for on-chain conflicting transactions (#3061)
* incorrect sequence point boundaries in debug data (#3074)
* compiler panic on encountering generic code (#3041)
* potential pooled fallback notary transaction changes (#3108)
* lost LastGasPerVote value on NEO state deserialization for non-voting
accounts (#3122)
## 0.101.4 "Yarborough" (01 Aug 2023)
Another one 3.5.0-compatible version that is aimed to fix T5 testnet state
difference that has happened at block 2336911 which leads to inability to process
new blocks since 2418703. The issue is fixed by allowing JSON numbers
unmarshalling from scientific notation to Integer stackitem. Maximum parsing
precision for such numbers is currently restricted by 53 bits. This is a
temporary C#-compatible solution that is likely to change in the future versions
when an appropriate C# node bug is fixed (neo-project/neo#2879).
A set of minor bug fixes is included as well to flush some of the long-awaited
changes that were blocked by the 0.102.0 release delay (caused by v3.6.0 C# node
release delay). In particular, invalid headers returned by an RPC server for
error responses, invalid format of incremental dumps created by CLI and deadlock
on unhealthy RPC server shutdown. Long-awaited `--config-file` CLI option to
start the node providing a single configuration file is added.
T5 testnet chain requires a complete resynchronization for this version. Mainnet
chain resynchronization is recommended, but not required.
New features:
* `--config-file` CLI option allowing to start the node with a single configuration file (#3014)
Improvements:
* blockchain Notary and Oracle services documentation improvement (#2972)
* BoltDB (`go.etcd.io/bbolt`) dependency upgrade that fixes a number of Windows-related issues (#3034)
Bugs fixed:
* panic on node start with invalid configuration (#2968)
* deadlock on unhealthy RPC server shutdown (#2966)
* improper WSClient notification channels managing after disconnection (#2980)
* missing Prometheus metric initialisation on node start (#2992)
* invalid initialisation of native contracts cache (#2994)
* incorrect way of incremental DB dumps creation (#3047)
* Notary contract is allowed to be a sender of main Notary request transaction (#3065)
* discrepancy in signer's witness scope parsing on the RPC server side (#3060)
* Invoker calling API isn't allowed to accept nil parameter (#3067)
* contract RPC Client unwrapper helper can't handle missing contract case (#3072)
* JSON numbers can't be unmarshalled to stackitem from scientific notation (#3073)
* invalid content-type header returned by RPC server on error responses (#3075)
## 0.101.3 "Yuckiness" (08 Jul 2023)
Yet another 3.5.0-compatible emergency version that removes scrupulous
@ -2609,7 +2136,7 @@ Behavior changes:
* contracts no longer have single entry point, rather they export a set of
methods with specific offsets. Go smart contract compiler has been changed
accordingly to add all exported (as in Go) methods to the manifest
(but with the first letter being lowercased to match NEP-5 expectations,
(but with the first letter being lowercased to match NEP-5 expections,
#1228). Please also refer to examples changes to better see how it affects
contracts, manifests and configuration files (#1296)
* native contracts are now called via Neo.Native.Call syscall (#1191)

View file

@ -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.20-alpine as builder
# Display go version for information purposes.
RUN go version

View file

@ -1,6 +1,75 @@
# Builder image
FROM mcr.microsoft.com/windows/servercore:ltsc2022 as builder
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';", "$ProgressPreference = 'SilentlyContinue';"]
ENV GIT_VERSION=2.23.0
ENV GIT_TAG=v2.23.0.windows.1
ENV GIT_DOWNLOAD_URL=https://github.com/git-for-windows/git/releases/download/v2.23.0.windows.1/MinGit-2.23.0-64-bit.zip
ENV GIT_DOWNLOAD_SHA256=8f65208f92c0b4c3ae4c0cf02d4b5f6791d539cd1a07b2df62b7116467724735
RUN Write-Host ('Downloading {0} ...' -f $env:GIT_DOWNLOAD_URL); \
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest -Uri $env:GIT_DOWNLOAD_URL -OutFile 'git.zip'; \
\
Write-Host ('Verifying sha256 ({0}) ...' -f $env:GIT_DOWNLOAD_SHA256); \
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_DOWNLOAD_SHA256) { \
Write-Host 'FAILED!'; \
exit 1; \
}; \
\
Write-Host 'Expanding ...'; \
Expand-Archive -Path git.zip -DestinationPath C:\git\.; \
\
Write-Host 'Removing ...'; \
Remove-Item git.zip -Force; \
\
Write-Host 'Updating PATH ...'; \
$env:PATH = 'C:\git\cmd;C:\git\mingw64\bin;C:\git\usr\bin;' + $env:PATH; \
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine); \
\
Write-Host 'Verifying install ("git version") ...'; \
git version; \
\
Write-Host 'Complete.';
ENV GOPATH=C:\\go
RUN $newPath = ('{0}\bin;C:\Program Files\Go\bin;{1}' -f $env:GOPATH, $env:PATH); \
Write-Host ('Updating PATH: {0}' -f $newPath); \
[Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine);
# Keep go version in sync with Build GA job.
FROM golang:1.22.0-windowsservercore-ltsc2022 as builder
ENV GOLANG_VERSION=1.20
RUN $url = 'https://go.dev/dl/go1.20.windows-amd64.zip'; \
Write-Host ('Downloading {0} ...' -f $url); \
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest -Uri $url -OutFile 'go.zip'; \
\
$sha256 = 'e8f6d8bbcf3df58d2ba29818e13b04c2e42ba2e4d90d580720b21c34d10bbf68'; \
Write-Host ('Verifying sha256 ({0}) ...' -f $sha256); \
if ((Get-FileHash go.zip -Algorithm sha256).Hash -ne $sha256) { \
Write-Host 'FAILED!'; \
exit 1; \
}; \
\
Write-Host 'Expanding ...'; \
Expand-Archive go.zip -DestinationPath C:\; \
\
Write-Host 'Moving ...'; \
Move-Item -Path C:\go -Destination 'C:\Program Files\Go'; \
\
Write-Host 'Removing ...'; \
Remove-Item go.zip -Force; \
\
Write-Host 'Verifying install ("go version") ...'; \
go version; \
\
Write-Host 'Complete.';
COPY . /neo-go

View file

@ -1,6 +1,7 @@
MIT License
Copyright (c) 2018-2023 NeoSPCC (@nspcc-dev), Anthony De Meulemeester (@anthdm), City of Zion community (@CityOfZion)
Copyright (c) 2018-2022 Anthony De Meulemeester (@anthdm), City of Zion
community (@CityOfZion), NeoSPCC (@nspcc-dev)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -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.18
DESTDIR = ""
SYSCONFIGDIR = "/etc"
BINDIR = "/usr/bin"

View file

@ -12,7 +12,7 @@
<hr />
[![codecov](https://codecov.io/gh/nspcc-dev/neo-go/branch/master/graph/badge.svg)](https://codecov.io/gh/nspcc-dev/neo-go)
[![GithubWorkflows Tests](https://github.com/nspcc-dev/neo-go/actions/workflows/tests.yml/badge.svg)](https://github.com/nspcc-dev/neo-go/actions/workflows/tests.yml)
[![GithubWorkflows Tests](https://github.com/nspcc-dev/neo-go/actions/workflows/run_tests.yml/badge.svg)](https://github.com/nspcc-dev/neo-go/actions/workflows/run_tests.yml)
[![Report](https://goreportcard.com/badge/github.com/nspcc-dev/neo-go)](https://goreportcard.com/report/github.com/nspcc-dev/neo-go)
[![GoDoc](https://godoc.org/github.com/nspcc-dev/neo-go?status.svg)](https://godoc.org/github.com/nspcc-dev/neo-go)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/nspcc-dev/neo-go?sort=semver)
@ -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.18+ and `make`:
```
make
@ -180,8 +180,9 @@ describing the feature/topic you are going to implement.
# Contact
- [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub
- [@roman-khimov](https://github.com/roman-khimov) on GitHub
- [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub
- [@fyrchik](https://github.com/fyrchik) on GitHub
- Reach out to us on the [Neo Discord](https://discordapp.com/invite/R8v48YA) channel
# License

View file

@ -7,13 +7,14 @@ functionality.
## Versions 0.7X.Y (as needed)
* Neo 2.0 support (bug fixes, minor functionality additions)
## Version 0.107.0 (~Jun-Jul 2024)
* protocol updates
* bug fixes
* node resynchronisation from local DB
* CLI library upgrade
## Version 0.102.0 (~March 2022)
* 3.6.0 compatibility
## Version 1.0 (2024, TBD)
## Version 0.102.1 (~April 2022)
* improved RPC error codes
* extended data types for iterators to be used by RPC wrapper generator
## Version 1.0 (2023, TBD)
* stable version
# Deprecated functionality
@ -25,21 +26,110 @@ APIs/commands/configurations will be removed and here is a list of scheduled
breaking changes. Consider changing your code/scripts/configurations if you're
using anything mentioned here.
## Old RPC client APIs
A huge set of RPC client APIs was deprecated in versions 0.99.2 and 0.99.3
(August-September 2022), including very frequently used ones like
SignAndPushInvocationTx, AddNetworkFee, TransferNEP17. A new set of
invoker/actor/unwrap/nep17/etc packages was introduced decoupling these
functions from RPC client and simplifying typical backend code. Please refer
to rpcclient package documentation for specific replacements for each of these
APIs and convert your code to using them.
While a lot of the code is already converted to new APIs, old ones still can
be used in some code not known to us. Therefore we will remove old APIs not
earlier than May 2023, with 0.103.0 release.
## WSClient Notifications channel and SubscribeFor* APIs
Version 0.99.5 of NeoGo introduces a new set of subscription APIs that gives
more control to the WSClient user that can pass specific channels to be used
for specific subscriptions now. Old APIs and generic Notifications channel are
still available, but will be removed, so please convert your code to using new
Receive* APIs.
Removal of these APIs is scheduled for May 2023 (~0.103.0 release).
## SecondsPerBlock protocol configuration
With 0.100.0 version SecondsPerBlock protocol configuration setting was
deprecated and replaced by a bit more generic and precise TimePerBlock
(allowing for subsecond time). An informational message is printed on node
startup to inform about this, it's very easy to deal with this configuration
change, just replace one line.
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
## Services/node address and port configuration
Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to
the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof) and
the node itself. It allows to specify several listen addresses/ports using an
array of "address:port" pairs in the service's `Addresses` config section and
array of "address:port:announcedPort" tuples in the `ApplicationConfiguration`'s
`Addresses` node config section. Deprecated `Address` and `Port` sections of
`RPC`, `Prometheus`, `Pprof` subsections of the `ApplicationConfiguration`
as far as the one of RPC server's `TLSConfig` are still available, but will be
removed, so please convert your node configuration file to use new `P2P`-level
`Addresses` section for the node services. Deprecated `Address`, `NodePort` and
`AnnouncedPort` sections of `ApplicationConfiguration` will also be removed
eventually, so please update your node configuration file to use `Addresses`
section for the P2P addresses configuration.
Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release).
## P2P application settings configuration
Version 0.100.0 of NeoGo marks the following P2P application settings as
deprecated: `AttemptConnPeers`, `BroadcastFactor`, `DialTimeout`,
`ExtensiblePoolSize`, `MaxPeers`, `MinPeers`, `PingInterval`, `PingTimeout`,
`ProtoTickInterval`. These settings are moved to a separate `P2P` section of
`ApplicationConfiguration`. The `DialTimeout`, `PingInterval`, `PingTimeout`,
`ProtoTickInterval` settings are converted to more precise `Duration` format
(allowing for subsecond time). Please, update your node configuration (all you
need is to move specified settings under the `P2P` section and convert
time-related settings to `Duration` format).
Removal of deprecated P2P related application settings is scheduled for May-June
2023 (~0.103.0 release).
## Direct UnlockWallet consensus configuration
Top-level UnlockWallet section in ApplicationConfiguration was used as an
implicit consensus service configuration, now this setting (with Enabled flag)
is moved into a section of its own (Consensus). Old configurations are still
supported, but this support will eventually be removed.
Removal of this compatibility code is scheduled for May-June 2023 (~0.103.0
release).
## Node-specific configuration moved from Protocol to Application
GarbageCollectionPeriod, KeepOnlyLatestState, RemoveUntraceableBlocks,
SaveStorageBatch and VerifyBlocks settings were moved from
ProtocolConfiguration to ApplicationConfiguration in version 0.100.0. Old
configurations are still supported, except for VerifyBlocks which is replaced
by SkipBlockVerification with inverted meaning (and hence an inverted default)
for security reasons.
Removal of these options from ProtocolConfiguration is scheduled for May-June
2023 (~0.103.0 release).
## GetPeers RPC server response type changes and RPC client support
GetPeers RPC command returns a list of Peers where the port type has changed from
string to uint16 to match C#. The RPC client currently supports unmarshalling both
formats.
Removal of Peer unmarshalling with string based ports is scheduled for Jun-Jul 2024
(~0.107.0 release).
Removal of Peer unmarshalling with string based ports is scheduled for ~September 2023
(~0.105.0 release).
## `NEOBalance` from stack item
We check struct items count before convert LastGasPerVote to let RPC client be compatible with
old versions.
Removal of this compatiblility code is scheduled for Jun-Jul 2024.
Removal of this compatiblility code is scheduled for Sep-Oct 2023.
## `serv_node_version` Prometheus gauge metric
@ -48,24 +138,4 @@ metrics with proper version formatting. `neogo_version` contains NeoGo version
hidden under `version` label and `server_id` contains network server ID hidden
under `server_id` label.
Removal of `serv_node_version` is scheduled for Jun-Jul 2024 (~0.107.0 release).
## RPC error codes returned by old versions and C#-nodes
NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`,
`neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the
neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions).
Removal of the deprecated RPC error codes is planned for Jun-Jul 2024 (~0.107.0
release).
## Block based web-socket waiter transaction awaiting
Web-socket RPC based `waiter.EventWaiter` uses `header_of_added_block` notifications
subscription to manage transaction awaiting. To support old NeoGo RPC servers
(older than 0.105.0) that do not have block headers subscription ability,
event-based waiter fallbacks to the old way of block monitoring with
`block_added` notifications subscription.
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
scheduled for Jun-Jul 2024 (~0.107.0 release).
Removal of `serv_node_version` is scheduled for Sep-Oct 2023 (~0.105.0 release).

View file

@ -4,12 +4,11 @@ import (
"testing"
"github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/config"
)
func TestCLIVersion(t *testing.T) {
config.Version = versionutil.TestVersion // Zero-length version string disables '--version' completely.
config.Version = "0.90.0-test" // Zero-length version string disables '--version' completely.
e := testcli.NewExecutor(t, false)
e.Run(t, "neo-go", "--version")
e.CheckNextLine(t, "^NeoGo")

View file

@ -1,6 +1,7 @@
package cmdargs
import (
"encoding/hex"
"strings"
"testing"
@ -44,7 +45,7 @@ func TestParseCosigner(t *testing.T) {
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
AllowedContracts: []util.Uint160{c1, c2},
},
acc.StringLE() + ":CustomGroups:" + priv.PublicKey().StringCompressed(): {
acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): {
Account: acc,
Scopes: transaction.CustomGroups,
AllowedGroups: keys.PublicKeys{priv.PublicKey()},

View file

@ -14,7 +14,6 @@ import (
"testing"
"github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -30,9 +29,6 @@ const (
nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
nftOwnerWallet = "../../examples/my_wallet.json"
nftOwnerPass = "qwerty"
// Keep contract NEFs consistent between runs.
_ = versionutil.TestVersion
)
func TestNEP11Import(t *testing.T) {
@ -328,14 +324,6 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
checkBalanceResult(t, nftOwnerAddr, tokenID1)
// check --await flag
tokenID2 := mint(t)
e.In.WriteString(nftOwnerPass + "\r")
e.Run(t, append(cmdTransfer, "--await", "--id", hex.EncodeToString(tokenID2))...)
e.CheckAwaitableTxPersisted(t)
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
checkBalanceResult(t, nftOwnerAddr, tokenID1)
// transfer: good, to NEP-11-Payable contract, with data
verifyH := deployVerifyContract(t, e)
cmdTransfer = []string{

View file

@ -19,34 +19,19 @@ import (
func TestNEP17Balance(t *testing.T) {
e := testcli.NewExecutor(t, true)
args := []string{
"neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--from", testcli.ValidatorAddr,
"GAS:" + testcli.TestWalletMultiAccount1 + ":1",
"NEO:" + testcli.TestWalletMultiAccount1 + ":10",
"GAS:" + testcli.TestWalletMultiAccount3 + ":3",
"--force",
}
e.In.WriteString("one\r")
e.Run(t, args...)
e.CheckTxPersisted(t)
cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
cmdbase := append(cmdbalance,
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.TestWalletMultiPath,
"--wallet", testcli.ValidatorWallet,
)
cmd := append(cmdbase, "--address", testcli.TestWalletMultiAccount1)
cmd := append(cmdbase, "--address", testcli.ValidatorAddr)
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
})
t.Run("NEO", func(t *testing.T) {
b, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
b, index := e.Chain.GetGoverningTokenBalance(testcli.ValidatorHash)
checkResult := func(t *testing.T) {
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr)
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
@ -63,53 +48,65 @@ func TestNEP17Balance(t *testing.T) {
})
t.Run("GAS", func(t *testing.T) {
e.Run(t, append(cmd, "--token", "GAS")...)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr)
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
b := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
b := e.Chain.GetUtilityTokenBalance(testcli.ValidatorHash)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
})
t.Run("zero balance of known token", func(t *testing.T) {
e.Run(t, append(cmdbase, []string{"--token", "NEO", "--address", testcli.TestWalletMultiAccount2}...)...)
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
e.Run(t, append(cmdbase, []string{"--token", "NEO"}...)...)
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr1))
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:")
e.CheckEOF(t)
e.CheckNextLine(t, "^\\s*$")
})
t.Run("all accounts", func(t *testing.T) {
e.Run(t, cmdbase...)
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr1))
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
balance := e.Chain.GetUtilityTokenBalance(addr1)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:")
e.CheckNextLine(t, "^\\s*$")
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount1)
addr2, err := address.StringToUint160("NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq")
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr2))
e.CheckNextLine(t, "^\\s*$")
addr3, err := address.StringToUint160("NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP")
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr3))
// The order of assets is undefined.
for i := 0; i < 2; i++ {
line := e.GetNextLine(t)
if strings.Contains(line, "GAS") {
e.CheckLine(t, line, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
balance = e.Chain.GetUtilityTokenBalance(addr3)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:")
} else {
balance, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
balance, index := e.Chain.GetGoverningTokenBalance(testcli.ValidatorHash)
e.CheckLine(t, line, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+balance.String()+"$")
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
}
}
e.CheckNextLine(t, "^\\s*$")
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
e.CheckNextLine(t, "^\\s*$")
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount3)
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount3Hash)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:")
addr4, err := address.StringToUint160("NiFxRcC5Anz9pmqQyMHh5vamBUZDbRRRzA") // deployed verify.go contract
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr4))
e.CheckEOF(t)
})
t.Run("Bad token", func(t *testing.T) {
e.Run(t, append(cmd, "--token", "kek")...)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr)
e.CheckNextLine(t, `^\s*Can't find data for "kek" token\s*`)
e.CheckEOF(t)
})
@ -226,19 +223,12 @@ func TestNEP17Transfer(t *testing.T) {
"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
"--token", "GAS",
"--amount", "1",
"--from", testcli.ValidatorAddr,
"--force",
"--from", testcli.ValidatorAddr}
t.Run("with await", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, append(cmd, "--to", nftOwnerAddr, "--await")...)
e.CheckAwaitableTxPersisted(t)
})
cmd = append(cmd, "--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]")
"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]"}
t.Run("with data", func(t *testing.T) {
e.In.WriteString("one\r")

View file

@ -11,50 +11,27 @@ import (
"os"
"runtime"
"strconv"
"strings"
"time"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io"
"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"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"golang.org/x/term"
"gopkg.in/yaml.v3"
)
const (
// DefaultTimeout is the default timeout used for RPC requests.
DefaultTimeout = 10 * time.Second
// DefaultAwaitableTimeout is the default timeout used for RPC requests that
// require transaction awaiting. It is set to the approximate time of three
// Neo N3 mainnet blocks accepting.
DefaultAwaitableTimeout = 3 * 15 * time.Second
)
// DefaultTimeout is the default timeout used for RPC requests.
const DefaultTimeout = 10 * time.Second
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
// check for flag presence in the context.
const RPCEndpointFlag = "rpc-endpoint"
// Wallet is a set of flags used for wallet operations.
var Wallet = []cli.Flag{cli.StringFlag{
Name: "wallet, w",
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
}, cli.StringFlag{
Name: "wallet-config",
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag"},
}
// Network is a set of flags for choosing the network to operate on
// (privnet/mainnet/testnet).
var Network = []cli.Flag{
@ -96,13 +73,6 @@ var ConfigFile = cli.StringFlag{
Usage: "path to the node configuration file (overrides --config-path option)",
}
// RelativePath is a flag for commands that use node configuration and provide
// a prefix to all relative paths in config files.
var RelativePath = cli.StringFlag{
Name: "relative-path",
Usage: "a prefix to all relative paths in the node configuration file",
}
// Debug is a flag for commands that allow node in debug mode usage.
var Debug = cli.BoolFlag{
Name: "debug, d",
@ -111,8 +81,6 @@ var Debug = cli.BoolFlag{
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
// GetNetwork examines Context's flags and returns the appropriate network. It
// defaults to PrivNet if no flags are given.
@ -136,9 +104,6 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
if dur == 0 {
dur = DefaultTimeout
}
if !ctx.IsSet("timeout") && ctx.Bool("await") {
dur = DefaultAwaitableTimeout
}
return context.WithTimeout(context.Background(), dur)
}
@ -194,18 +159,15 @@ func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transac
// GetConfigFromContext looks at the path and the mode flags in the given config and
// returns an appropriate config.
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
var (
configFile = ctx.String("config-file")
relativePath = ctx.String("relative-path")
)
var configFile = ctx.String("config-file")
if len(configFile) != 0 {
return config.LoadFile(configFile, relativePath)
return config.LoadFile(configFile)
}
var configPath = "./config"
if argCp := ctx.String("config-path"); argCp != "" {
configPath = argCp
}
return config.Load(configPath, GetNetwork(ctx), relativePath)
return config.Load(configPath, GetNetwork(ctx))
}
var (
@ -220,7 +182,6 @@ var (
// If logPath is configured -- function creates a dir and a file for logging.
// If logPath is configured on Windows -- function returns closer to be
// able to close sink for the opened log output file.
// If the program is run in TTY then logger adds timestamp to its entries.
func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
var (
level = zapcore.InfoLevel
@ -241,11 +202,7 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
cc.DisableStacktrace = true
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
if term.IsTerminal(int(os.Stdout.Fd())) {
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
} else {
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
}
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
cc.Encoding = "console"
cc.Level = zap.NewAtomicLevelAt(level)
cc.Sampling = nil
@ -303,108 +260,3 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
log, err := cc.Build()
return log, &cc.Level, _winfileSinkCloser, err
}
// GetRPCWithActor returns an RPC client instance and Actor instance for the given context.
func GetRPCWithActor(gctx context.Context, ctx *cli.Context, signers []actor.SignerAccount) (*rpcclient.Client, *actor.Actor, cli.ExitCoder) {
c, err := GetRPCClient(gctx, ctx)
if err != nil {
return nil, nil, err
}
a, actorErr := actor.New(c, signers)
if actorErr != nil {
c.Close()
return nil, nil, cli.NewExitError(fmt.Errorf("failed to create Actor: %w", actorErr), 1)
}
return c, a, nil
}
// GetAccFromContext returns account and wallet from context. If address is not set, default address is used.
func GetAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
var addr util.Uint160
wPath := ctx.String("wallet")
walletConfigPath := ctx.String("wallet-config")
if len(wPath) != 0 && len(walletConfigPath) != 0 {
return nil, nil, errConflictingWalletFlags
}
if len(wPath) == 0 && len(walletConfigPath) == 0 {
return nil, nil, errNoWallet
}
var pass *string
if len(walletConfigPath) != 0 {
cfg, err := ReadWalletConfig(walletConfigPath)
if err != nil {
return nil, nil, err
}
wPath = cfg.Path
pass = &cfg.Password
}
wall, err := wallet.NewWalletFromFile(wPath)
if err != nil {
return nil, nil, err
}
addrFlag := ctx.Generic("address").(*flags.Address)
if addrFlag.IsSet {
addr = addrFlag.Uint160()
} else {
addr = wall.GetChangeAddress()
if addr.Equals(util.Uint160{}) {
return nil, wall, errors.New("can't get default address")
}
}
acc, err := GetUnlockedAccount(wall, addr, pass)
return acc, wall, err
}
// GetUnlockedAccount returns account from wallet, address and uses pass to unlock specified account if given.
// If the password is not given, then it is requested from user.
func GetUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
}
if acc.CanSign() || acc.EncryptedWIF == "" {
return acc, nil
}
if pass == nil {
rawPass, err := input.ReadPassword(
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
if err != nil {
return nil, fmt.Errorf("Error reading password: %w", err)
}
trimmed := strings.TrimRight(string(rawPass), "\n")
pass = &trimmed
}
err := acc.Decrypt(*pass, wall.Scrypt)
if err != nil {
return nil, err
}
return acc, nil
}
// ReadWalletConfig reads wallet config from the given path.
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
file, err := os.Open(configPath)
if err != nil {
return nil, err
}
defer file.Close()
configData, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("unable to read wallet config: %w", err)
}
cfg := &config.Wallet{}
err = yaml.Unmarshal(configData, &cfg)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
}
return cfg, nil
}

View file

@ -3,6 +3,7 @@ package query
import (
"bytes"
"encoding/base64"
"encoding/hex"
"fmt"
"sort"
"strconv"
@ -110,10 +111,7 @@ func queryTx(ctx *cli.Context) error {
}
}
err = DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
if err != nil {
return cli.NewExitError(err, 1)
}
DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
return nil
}
@ -122,49 +120,47 @@ func DumpApplicationLog(
res *result.ApplicationLog,
tx *transaction.Transaction,
txMeta *result.TransactionMetadata,
verbose bool) error {
var buf []byte
verbose bool) {
buf := bytes.NewBuffer(nil)
buf = fmt.Appendf(buf, "Hash:\t%s\n", tx.Hash().StringLE())
buf = fmt.Appendf(buf, "OnChain:\t%t\n", res != nil)
// Ignore the errors below because `Write` to buffer doesn't return error.
tw := tabwriter.NewWriter(buf, 0, 4, 4, '\t', 0)
_, _ = tw.Write([]byte("Hash:\t" + tx.Hash().StringLE() + "\n"))
_, _ = tw.Write([]byte(fmt.Sprintf("OnChain:\t%t\n", res != nil)))
if res == nil {
buf = fmt.Appendf(buf, "ValidUntil:\t%s\n", strconv.FormatUint(uint64(tx.ValidUntilBlock), 10))
_, _ = tw.Write([]byte("ValidUntil:\t" + strconv.FormatUint(uint64(tx.ValidUntilBlock), 10) + "\n"))
} else {
if txMeta != nil {
buf = fmt.Appendf(buf, "BlockHash:\t%s\n", txMeta.Blockhash.StringLE())
_, _ = tw.Write([]byte("BlockHash:\t" + txMeta.Blockhash.StringLE() + "\n"))
}
if len(res.Executions) != 1 {
buf = fmt.Appendf(buf, "Success:\tunknown (no execution data)\n")
_, _ = tw.Write([]byte("Success:\tunknown (no execution data)\n"))
} else {
buf = fmt.Appendf(buf, "Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt)
_, _ = tw.Write([]byte(fmt.Sprintf("Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt)))
}
}
if verbose {
for _, sig := range tx.Signers {
buf = fmt.Appendf(buf, "Signer:\t%s (%s)\n", address.Uint160ToString(sig.Account), sig.Scopes)
_, _ = tw.Write([]byte(fmt.Sprintf("Signer:\t%s (%s)",
address.Uint160ToString(sig.Account),
sig.Scopes) + "\n"))
}
buf = fmt.Appendf(buf, "SystemFee:\t%s GAS\n", fixedn.Fixed8(tx.SystemFee).String())
buf = fmt.Appendf(buf, "NetworkFee:\t%s GAS\n", fixedn.Fixed8(tx.NetworkFee).String())
buf = fmt.Appendf(buf, "Script:\t%s\n", base64.StdEncoding.EncodeToString(tx.Script))
_, _ = tw.Write([]byte("SystemFee:\t" + fixedn.Fixed8(tx.SystemFee).String() + " GAS\n"))
_, _ = tw.Write([]byte("NetworkFee:\t" + fixedn.Fixed8(tx.NetworkFee).String() + " GAS\n"))
_, _ = tw.Write([]byte("Script:\t" + base64.StdEncoding.EncodeToString(tx.Script) + "\n"))
v := vm.New()
v.Load(tx.Script)
opts := bytes.NewBuffer(nil)
v.PrintOps(opts)
buf = append(buf, opts.Bytes()...)
v.PrintOps(tw)
if res != nil {
for _, e := range res.Executions {
if e.VMState != vmstate.Halt {
buf = fmt.Appendf(buf, "Exception:\t%s\n", e.FaultException)
_, _ = tw.Write([]byte("Exception:\t" + e.FaultException + "\n"))
}
}
}
}
tw := tabwriter.NewWriter(ctx.App.Writer, 0, 4, 4, '\t', 0)
_, err := tw.Write(buf)
if err != nil {
return err
}
return tw.Flush()
_ = tw.Flush()
fmt.Fprint(ctx.App.Writer, buf.String())
}
func queryCandidates(ctx *cli.Context) error {
@ -200,17 +196,15 @@ func queryCandidates(ctx *cli.Context) error {
}
return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1
})
var res []byte
res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n")
buf := bytes.NewBuffer(nil)
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
_, _ = tw.Write([]byte("Key\tVotes\tCommittee\tConsensus\n"))
for _, val := range vals {
res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", val.PublicKey.StringCompressed(), val.Votes, comm.Contains(&val.PublicKey), val.Active)
_, _ = tw.Write([]byte(fmt.Sprintf("%s\t%d\t%t\t%t\n", hex.EncodeToString(val.PublicKey.Bytes()), val.Votes, comm.Contains(&val.PublicKey), val.Active)))
}
tw := tabwriter.NewWriter(ctx.App.Writer, 0, 2, 2, ' ', 0)
_, err = tw.Write(res)
if err != nil {
return err
}
return tw.Flush()
_ = tw.Flush()
fmt.Fprint(ctx.App.Writer, buf.String())
return nil
}
func queryCommittee(ctx *cli.Context) error {
@ -234,7 +228,7 @@ func queryCommittee(ctx *cli.Context) error {
}
for _, k := range comm {
fmt.Fprintln(ctx.App.Writer, k.StringCompressed())
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes()))
}
return nil
}
@ -305,7 +299,7 @@ func queryVoter(ctx *cli.Context) error {
}
voted := "null"
if st.VoteTo != nil {
voted = fmt.Sprintf("%s (%s)", st.VoteTo.StringCompressed(), address.Uint160ToString(st.VoteTo.GetScriptHash()))
voted = fmt.Sprintf("%s (%s)", hex.EncodeToString(st.VoteTo.Bytes()), address.Uint160ToString(st.VoteTo.GetScriptHash()))
}
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))

View file

@ -77,8 +77,7 @@ func TestServerStart(t *testing.T) {
})
t.Run("invalid consensus config", func(t *testing.T) {
saveCfg(t, func(cfg *config.Config) {
cfg.ApplicationConfiguration.Consensus.Enabled = true
cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path = "bad_consensus_wallet.json"
cfg.ApplicationConfiguration.UnlockWallet.Path = "bad_consensus_wallet.json"
})
e.RunWithError(t, baseCmd...)
})

View file

@ -34,7 +34,7 @@ import (
// NewCommands returns 'node' command.
func NewCommands() []cli.Command {
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags := []cli.Flag{options.Config, options.ConfigFile}
cfgFlags = append(cfgFlags, options.Network...)
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
copy(cfgWithCountFlags, cfgFlags)
@ -136,6 +136,7 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m
if err != nil {
return nil, nil, nil, cli.NewExitError(err, 1)
}
configureAddresses(&cfg.ApplicationConfiguration)
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
@ -358,14 +359,7 @@ func resetDB(ctx *cli.Context) error {
return nil
}
// oracleService is an interface representing Oracle service with network.Service
// capabilities and ability to submit oracle responses.
type oracleService interface {
rpcsrv.OracleHandler
network.Service
}
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (oracleService, error) {
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (*oracle.Oracle, error) {
if !config.Enabled {
return nil, nil
}
@ -422,7 +416,7 @@ func mkP2PNotary(config config.P2PNotary, chain *core.Blockchain, serv *network.
}
n, err := notary.NewNotary(cfg, serv.Net, serv.GetNotaryPool(), func(tx *transaction.Transaction) error {
err := serv.RelayTxn(tx)
if err != nil && !errors.Is(err, core.ErrAlreadyExists) && !errors.Is(err, core.ErrAlreadyInPool) {
if err != nil && !errors.Is(err, core.ErrAlreadyExists) {
return fmt.Errorf("can't relay completed notary transaction: hash %s, error: %w", tx.Hash().StringLE(), err)
}
return nil
@ -498,7 +492,7 @@ func startServer(ctx *cli.Context) error {
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
serv.AddService(&rpcServer)
serv.Start()
go serv.Start()
if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized {
// Run RPC server in a separate routine. This is necessary to avoid a potential
// deadlock: Start() can write errors to errChan which is not yet read in the
@ -546,6 +540,7 @@ Main:
break // Continue working.
}
}
configureAddresses(&cfgnew.ApplicationConfiguration)
switch sig {
case sighup:
if newLogLevel != zapcore.InvalidLevel {
@ -646,6 +641,24 @@ Main:
return nil
}
// configureAddresses sets up addresses for RPC, Prometheus and Pprof depending from the provided config.
// In case RPC or Prometheus or Pprof Address provided each of them will use it.
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
func configureAddresses(cfg *config.ApplicationConfiguration) {
if cfg.Address != nil && *cfg.Address != "" { //nolint:staticcheck // SA1019: cfg.Address is deprecated
if cfg.RPC.Address == nil || *cfg.RPC.Address == "" { //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
cfg.RPC.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
}
if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" { //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
cfg.Prometheus.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
}
if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" { //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
cfg.Pprof.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
}
}
}
// initBlockChain initializes BlockChain with preselected DB.
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)

View file

@ -5,7 +5,6 @@ import (
"flag"
"os"
"path/filepath"
"runtime"
"testing"
"go.uber.org/zap/zapcore"
@ -50,39 +49,6 @@ func TestGetConfigFromContext(t *testing.T) {
require.NoError(t, err)
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
})
t.Run("relative-path windows", func(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("skipping Windows specific test")
}
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.String("relative-path", "..\\..\\config", "")
set.Bool("testnet", true, "")
set.String("config-file", ".\\testdata\\protocol.testnet.windows.yml", "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err)
require.Equal(t, filepath.Join("..", "..", "config", "chains", "testnet"), cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
require.Equal(t, "C:\\someFolder\\cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
require.Equal(t, "C:\\someFolder\\notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
})
t.Run("relative-path non-windows", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping non-Windows specific test")
}
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.String("relative-path", "../../config", "")
set.Bool("testnet", true, "")
set.String("config-file", "../../config/protocol.testnet.yml", "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err)
require.Equal(t, filepath.Join("..", "..", "config", "chains", "testnet"), cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
require.Equal(t, "/cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
require.Equal(t, "/notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
})
}
func TestHandleLoggingParams(t *testing.T) {
@ -358,6 +324,64 @@ func TestRestoreDB(t *testing.T) {
require.NoError(t, restoreDB(ctx))
}
// TestConfigureAddresses checks deprecated code compatibility, it should be removed
// along with deprecated `Address` field removal.
func TestConfigureAddresses(t *testing.T) {
defaultAddress := "http://localhost:10333"
customAddress := "http://localhost:10334"
t.Run("default addresses", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
}
configureAddresses(cfg)
require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, defaultAddress, *cfg.Prometheus.Address) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, defaultAddress, *cfg.Pprof.Address) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
t.Run("custom RPC address", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
RPC: config.RPC{
BasicService: config.BasicService{
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
},
},
}
configureAddresses(cfg)
require.Equal(t, *cfg.RPC.Address, customAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
t.Run("custom Pprof address", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
Pprof: config.BasicService{
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
},
}
configureAddresses(cfg)
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, *cfg.Pprof.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
t.Run("custom Prometheus address", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
Prometheus: config.BasicService{
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
},
}
configureAddresses(cfg)
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, *cfg.Prometheus.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
}
func TestInitBlockChain(t *testing.T) {
t.Run("bad storage", func(t *testing.T) {
_, _, err := initBlockChain(config.Config{}, nil)

View file

@ -1,96 +0,0 @@
ProtocolConfiguration:
Magic: 894710606
MaxBlockSize: 2097152
MaxBlockSystemFee: 150000000000
MaxTraceableBlocks: 2102400
MaxTransactionsPerBlock: 5000
InitialGASSupply: 52000000
TimePerBlock: 15s
MemPoolSize: 50000
StandbyCommittee:
- 023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d
- 03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2
- 02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd
- 03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806
- 02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b
- 0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01
- 030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba
- 025831cee3708e87d78211bec0d1bfee9f4c85ae784762f042e7f31c0d40c329b8
- 02cf9dc6e85d581480d91e88e8cbeaa0c153a046e89ded08b4cefd851e1d7325b5
- 03840415b0a0fcf066bcc3dc92d8349ebd33a6ab1402ef649bae00e5d9f5840828
- 026328aae34f149853430f526ecaa9cf9c8d78a4ea82d08bdf63dd03c4d0693be6
- 02c69a8d084ee7319cfecf5161ff257aa2d1f53e79bf6c6f164cff5d94675c38b3
- 0207da870cedb777fceff948641021714ec815110ca111ccc7a54c168e065bda70
- 035056669864feea401d8c31e447fb82dd29f342a9476cfd449584ce2a6165e4d7
- 0370c75c54445565df62cfe2e76fbec4ba00d1298867972213530cae6d418da636
- 03957af9e77282ae3263544b7b2458903624adc3f5dee303957cb6570524a5f254
- 03d84d22b8753cf225d263a3a782a4e16ca72ef323cfde04977c74f14873ab1e4c
- 02147c1b1d5728e1954958daff2f88ee2fa50a06890a8a9db3fa9e972b66ae559f
- 03c609bea5a4825908027e4ab217e7efc06e311f19ecad9d417089f14927a173d5
- 0231edee3978d46c335e851c76059166eb8878516f459e085c0dd092f0f1d51c21
- 03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9
ValidatorsCount: 7
SeedList:
- seed1t5.neo.org:20333
- seed2t5.neo.org:20333
- seed3t5.neo.org:20333
- seed4t5.neo.org:20333
- seed5t5.neo.org:20333
VerifyTransactions: false
P2PSigExtensions: false
Hardforks:
Aspidochelone: 210000
Basilisk: 2680000
ApplicationConfiguration:
SkipBlockVerification: false
DBConfiguration:
Type: "leveldb" #other options: 'inmemory','boltdb'
# DB type options. Uncomment those you need in case you want to switch DB type.
LevelDBOptions:
DataDirectoryPath: ".\\chains\\testnet"
P2P:
Addresses:
- ":20333" # in form of "[host]:[port][:announcedPort]"
DialTimeout: 3s
ProtoTickInterval: 2s
PingInterval: 30s
PingTimeout: 90s
MaxPeers: 100
AttemptConnPeers: 20
MinPeers: 10
Relay: true
Consensus:
Enabled: false
UnlockWallet:
Path: "C:\\someFolder\\cn_wallet.json"
Password: "pass"
Oracle:
Enabled: false
AllowedContentTypes:
- application/json
P2PNotary:
Enabled: false
UnlockWallet:
Path: "C:\\someFolder\\notary_wallet.json"
Password: "pass"
RPC:
Enabled: true
Addresses:
- ":20332"
MaxGasInvoke: 15
EnableCORSWorkaround: false
TLSConfig:
Enabled: false
Addresses:
- ":20331"
CertFile: serv.crt
KeyFile: serv.key
Prometheus:
Enabled: true
Addresses:
- ":2112"
Pprof:
Enabled: false
Addresses:
- ":2113"

View file

@ -4,7 +4,6 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
@ -14,7 +13,6 @@ import (
"github.com/nspcc-dev/neo-go/cli/smartcontract"
"github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/core/state"
@ -25,7 +23,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"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/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
@ -34,9 +31,6 @@ import (
"gopkg.in/yaml.v3"
)
// Keep contract NEFs consistent between runs.
const _ = versionutil.TestVersion
func TestCalcHash(t *testing.T) {
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, false)
@ -103,6 +97,9 @@ func TestCalcHash(t *testing.T) {
}
func TestContractBindings(t *testing.T) {
// For proper nef generation.
config.Version = "v0.98.1-test"
// For proper contract init. The actual version as it will be replaced.
smartcontract.ModVersion = "v0.0.0"
@ -146,7 +143,18 @@ func Blocks() []*alias.Block {
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
goMod := filepath.Join(ctrPath, "go.mod")
data, err := os.ReadFile(goMod)
require.NoError(t, err)
i := bytes.IndexByte(data, '\n')
data = append([]byte("module myimport.com/testcontract"), data[i:]...)
wd, err := os.Getwd()
require.NoError(t, err)
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
cmd = append(cmd, "--config", cfgPath,
"--out", filepath.Join(tmpDir, "out.nef"),
@ -166,9 +174,7 @@ func Blocks() []*alias.Block {
bs, err := os.ReadFile(outPath)
require.NoError(t, err)
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package testcontract contains wrappers for testcontract contract.
require.Equal(t, `// Package testcontract contains wrappers for testcontract contract.
package testcontract
import (
@ -203,85 +209,10 @@ func ToMap(a []testcontract.MyPair) map[int]string {
`, string(bs))
}
// updateGoMod updates the go.mod file located in the specified directory.
// It sets the module name and replaces the neo-go interop package path with
// the provided one to avoid getting an actual module version.
func updateGoMod(dir, moduleName, neoGoPath string) error {
goModPath := filepath.Join(dir, "go.mod")
data, err := os.ReadFile(goModPath)
if err != nil {
return fmt.Errorf("failed to read go.mod: %w", err)
}
i := bytes.IndexByte(data, '\n')
if i == -1 {
return fmt.Errorf("unexpected go.mod format")
}
updatedData := append([]byte("module "+moduleName), data[i:]...)
wd, err := os.Getwd()
if err != nil {
return fmt.Errorf("failed to get working directory: %w", err)
}
replacementPath := filepath.Join(wd, neoGoPath)
updatedData = append(updatedData, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "+replacementPath+" \n"...)
if err := os.WriteFile(goModPath, updatedData, os.ModePerm); err != nil {
return fmt.Errorf("failed to write updated go.mod: %w", err)
}
return nil
}
func TestDynamicWrapper(t *testing.T) {
// For proper contract init. The actual version as it will be replaced.
smartcontract.ModVersion = "v0.0.0"
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, true)
ctrPath := "../smartcontract/testdata"
verifyHash := testcli.DeployContract(t, e, filepath.Join(ctrPath, "verify.go"), filepath.Join(ctrPath, "verify.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
helperContract := `package testcontract
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
verify "myimport.com/testcontract/bindings"
)
func CallVerifyContract(h interop.Hash160) bool{
contractInstance := verify.NewContract(h)
return contractInstance.Verify()
}`
helperDir := filepath.Join(tmpDir, "helper")
e.Run(t, "neo-go", "contract", "init", "--name", helperDir)
require.NoError(t, updateGoMod(helperDir, "myimport.com/testcontract", "../../pkg/interop"))
require.NoError(t, os.WriteFile(filepath.Join(helperDir, "main.go"), []byte(helperContract), os.ModePerm))
require.NoError(t, os.Mkdir(filepath.Join(helperDir, "bindings"), os.ModePerm))
e.Run(t, "neo-go", "contract", "generate-wrapper",
"--config", filepath.Join(ctrPath, "verify.bindings.yml"), "--manifest", filepath.Join(ctrPath, "verify.manifest.json"),
"--out", filepath.Join(helperDir, "bindings", "testdata.go"))
e.Run(t, "neo-go", "contract", "compile", "--in", filepath.Join(helperDir, "main.go"), "--config", filepath.Join(helperDir, "neo-go.yml"))
helperHash := testcli.DeployContract(t, e, filepath.Join(helperDir, "main.go"), filepath.Join(helperDir, "neo-go.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "contract", "invokefunction",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", "--await", helperHash.StringLE(), "callVerifyContract", verifyHash.StringLE())
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, aer[0].Stack[0].Value().(bool), true)
}
func TestContractInitAndCompile(t *testing.T) {
// For proper nef generation.
config.Version = "v0.98.1-test"
// For proper contract init. The actual version as it will be replaced.
smartcontract.ModVersion = "v0.0.0"
@ -333,7 +264,15 @@ func TestContractInitAndCompile(t *testing.T) {
})
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
goMod := filepath.Join(ctrPath, "go.mod")
data, err := os.ReadFile(goMod)
require.NoError(t, err)
wd, err := os.Getwd()
require.NoError(t, err)
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
cmd = append(cmd, "--config", cfgPath)
@ -371,6 +310,9 @@ func TestDeployBigContract(t *testing.T) {
e := testcli.NewExecutorWithConfig(t, true, true, func(c *config.Config) {
c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1)
})
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef")
@ -389,6 +331,9 @@ func TestDeployBigContract(t *testing.T) {
func TestContractDeployWithData(t *testing.T) {
eCompile := testcli.NewExecutor(t, false)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef")
@ -398,7 +343,7 @@ func TestContractDeployWithData(t *testing.T) {
"--config", "testdata/deploy/neo-go.yml",
"--out", nefName, "--manifest", manifestName)
deployContract := func(t *testing.T, haveData bool, scope string, await bool) {
deployContract := func(t *testing.T, haveData bool, scope string) {
e := testcli.NewExecutor(t, true)
cmd := []string{
"neo-go", "contract", "deploy",
@ -408,9 +353,6 @@ func TestContractDeployWithData(t *testing.T) {
"--force",
}
if await {
cmd = append(cmd, "--await")
}
if haveData {
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
}
@ -421,13 +363,8 @@ func TestContractDeployWithData(t *testing.T) {
}
e.In.WriteString(testcli.ValidatorPass + "\r")
e.Run(t, cmd...)
var tx *transaction.Transaction
if await {
tx, _ = e.CheckAwaitableTxPersisted(t)
} else {
tx, _ = e.CheckTxPersisted(t)
}
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
require.Equal(t, scope, tx.Signers[0].Scopes.String())
if !haveData {
return
@ -464,16 +401,16 @@ func TestContractDeployWithData(t *testing.T) {
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
}
deployContract(t, true, "", false)
deployContract(t, false, "Global", false)
deployContract(t, true, "Global", false)
deployContract(t, false, "", true)
deployContract(t, true, "Global", true)
deployContract(t, true, "", true)
deployContract(t, true, "")
deployContract(t, false, "Global")
deployContract(t, true, "Global")
}
func TestDeployWithSigners(t *testing.T) {
e := testcli.NewExecutor(t, true)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef")
@ -535,6 +472,9 @@ func TestDeployWithSigners(t *testing.T) {
func TestContractManifestGroups(t *testing.T) {
e := testcli.NewExecutor(t, true)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir()
_, err := wallet.NewWalletFromFile(testcli.TestWalletPath)
@ -691,6 +631,9 @@ func TestContract_TestInvokeScript(t *testing.T) {
func TestComlileAndInvokeFunction(t *testing.T) {
e := testcli.NewExecutor(t, true)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef")
@ -843,12 +786,6 @@ func TestComlileAndInvokeFunction(t *testing.T) {
e.Run(t, append(cmd, h.StringLE(), "getValue",
"--", testcli.ValidatorAddr, hVerify.StringLE())...)
})
t.Run("with await", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, append(cmd, "--force", "--await", h.StringLE(), "getValue")...)
e.CheckAwaitableTxPersisted(t)
})
})
t.Run("real invoke and save tx", func(t *testing.T) {
@ -1026,6 +963,9 @@ func TestComlileAndInvokeFunction(t *testing.T) {
func TestContractInspect(t *testing.T) {
e := testcli.NewExecutor(t, false)
// For proper nef generation.
config.Version = "0.90.0-test"
const srcPath = "testdata/deploy/main.go"
tmpDir := t.TempDir()
@ -1060,6 +1000,9 @@ func TestCompileExamples(t *testing.T) {
infos, err := os.ReadDir(examplePath)
require.NoError(t, err)
// For proper nef generation.
config.Version = "0.90.0-test"
e := testcli.NewExecutor(t, false)
for _, info := range infos {
@ -1068,10 +1011,6 @@ func TestCompileExamples(t *testing.T) {
// there are also a couple of files inside the `/examples` which doesn't need to be compiled
continue
}
if info.Name() == "zkp" {
// A set of special ZKP-related examples, they have their own tests.
continue
}
t.Run(info.Name(), func(t *testing.T) {
infos, err := os.ReadDir(filepath.Join(examplePath, info.Name()))
require.NoError(t, err)
@ -1148,27 +1087,3 @@ func filterFilename(infos []os.DirEntry, ext string) string {
}
return ""
}
func TestContractCompile_NEFSizeCheck(t *testing.T) {
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, false)
src := `package nefconstraints
var data = "%s"
func Main() string {
return data
}`
data := make([]byte, stackitem.MaxSize-10)
for i := range data {
data[i] = byte('a')
}
in := filepath.Join(tmpDir, "main.go")
cfg := filepath.Join(tmpDir, "main.yml")
require.NoError(t, os.WriteFile(cfg, []byte("name: main"), os.ModePerm))
require.NoError(t, os.WriteFile(in, []byte(fmt.Sprintf(src, data)), os.ModePerm))
e.RunWithError(t, "neo-go", "contract", "compile", "--in", in)
require.NoFileExists(t, filepath.Join(tmpDir, "main.nef"))
}

View file

@ -30,42 +30,37 @@ var generatorFlags = []cli.Flag{
},
cli.StringFlag{
Name: "hash",
Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
Usage: "Smart-contract hash",
},
}
var generateWrapperCmd = cli.Command{
Name: "generate-wrapper",
Usage: "generate wrapper to use in other contracts",
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
Description: `Generates a Go wrapper to use it in other smart contracts. If the
--hash flag is provided, CALLT instruction is used for the target contract
invocation as an optimization of the wrapper contract code. If omitted, the
generated wrapper will be designed for dynamic hash usage, allowing
the hash to be specified at runtime.
`,
Action: contractGenerateWrapper,
Flags: generatorFlags,
Name: "generate-wrapper",
Usage: "generate wrapper to use in other contracts",
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]",
Description: ``,
Action: contractGenerateWrapper,
Flags: generatorFlags,
}
var generateRPCWrapperCmd = cli.Command{
Name: "generate-rpcwrapper",
Usage: "generate RPC wrapper to use for data reads",
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]",
Action: contractGenerateRPCWrapper,
Flags: generatorFlags,
}
func contractGenerateWrapper(ctx *cli.Context) error {
return contractGenerateSomething(ctx, binding.Generate)
return contractGenerateSomething(ctx, binding.Generate, false)
}
func contractGenerateRPCWrapper(ctx *cli.Context) error {
return contractGenerateSomething(ctx, rpcbinding.Generate)
return contractGenerateSomething(ctx, rpcbinding.Generate, true)
}
// contractGenerateSomething reads generator parameters and calls the given callback.
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) error {
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error, allowEmptyHash bool) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
@ -78,6 +73,8 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
}
} else if !allowEmptyHash {
return cli.NewExitError("contract hash must be provided via --hash flag", 1)
}
m, _, err := readManifest(ctx.String("manifest"), h)
if err != nil {

View file

@ -151,9 +151,7 @@ callflags:
"--hash", h.StringLE(),
}))
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package wrapper contains wrappers for MyContract contract.
const expected = `// Package wrapper contains wrappers for MyContract contract.
package wrapper
import (
@ -174,8 +172,8 @@ func Sum(first int, second int) int {
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int)
}
// Sum2 invokes ` + "`sum`" + ` method of contract.
func Sum2(first int, second int, third int) int {
// Sum_3 invokes ` + "`sum`" + ` method of contract.
func Sum_3(first int, second int, third int) int {
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int)
}
@ -233,99 +231,6 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
data, err := os.ReadFile(outFile)
require.NoError(t, err)
require.Equal(t, expected, string(data))
require.NoError(t, app.Run([]string{"", "generate-wrapper",
"--manifest", manifestFile,
"--config", cfgPath,
"--out", outFile,
}))
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package wrapper contains wrappers for MyContract contract.
package wrapper
import (
"github.com/heyitsme/mycontract"
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
)
// Contract represents the MyContract smart contract.
type Contract struct {
Hash interop.Hash160
}
// NewContract returns a new Contract instance with the specified hash.
func NewContract(hash interop.Hash160) Contract {
return Contract{Hash: hash}
}
// Sum invokes ` + "`sum`" + ` method of contract.
func (c Contract) Sum(first int, second int) int {
return contract.Call(c.Hash, "sum", contract.All, first, second).(int)
}
// Sum2 invokes ` + "`sum`" + ` method of contract.
func (c Contract) Sum2(first int, second int, third int) int {
return contract.Call(c.Hash, "sum", contract.All, first, second, third).(int)
}
// Sum3 invokes ` + "`sum3`" + ` method of contract.
func (c Contract) Sum3() int {
return contract.Call(c.Hash, "sum3", contract.ReadOnly).(int)
}
// Zum invokes ` + "`zum`" + ` method of contract.
func (c Contract) Zum(typev int, typev_ int, funcv int) int {
return contract.Call(c.Hash, "zum", contract.All, typev, typev_, funcv).(int)
}
// JustExecute invokes ` + "`justExecute`" + ` method of contract.
func (c Contract) JustExecute(arr []any) {
contract.Call(c.Hash, "justExecute", contract.All, arr)
}
// GetPublicKey invokes ` + "`getPublicKey`" + ` method of contract.
func (c Contract) GetPublicKey() interop.PublicKey {
return contract.Call(c.Hash, "getPublicKey", contract.All).(interop.PublicKey)
}
// OtherTypes invokes ` + "`otherTypes`" + ` method of contract.
func (c Contract) OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data any) bool {
return contract.Call(c.Hash, "otherTypes", contract.All, ctr, tx, sig, data).(bool)
}
// SearchStorage invokes ` + "`searchStorage`" + ` method of contract.
func (c Contract) SearchStorage(ctx storage.Context) iterator.Iterator {
return contract.Call(c.Hash, "searchStorage", contract.All, ctx).(iterator.Iterator)
}
// GetFromMap invokes ` + "`getFromMap`" + ` method of contract.
func (c Contract) GetFromMap(intMap map[string]int, indices []string) []int {
return contract.Call(c.Hash, "getFromMap", contract.All, intMap, indices).([]int)
}
// DoSomething invokes ` + "`doSomething`" + ` method of contract.
func (c Contract) DoSomething(bytes []byte, str string) any {
return contract.Call(c.Hash, "doSomething", contract.ReadStates, bytes, str).(any)
}
// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract.
func (c Contract) GetBlockWrapper() ledger.Block {
return contract.Call(c.Hash, "getBlockWrapper", contract.All).(ledger.Block)
}
// MyFunc invokes ` + "`myFunc`" + ` method of contract.
func (c Contract) MyFunc(in map[int]mycontract.Input) []mycontract.Output {
return contract.Call(c.Hash, "myFunc", contract.All, in).([]mycontract.Output)
}
`
data, err = os.ReadFile(outFile)
require.NoError(t, err)
require.Equal(t, expectedWithDynamicHash, string(data))
}
func TestGenerateValidPackageName(t *testing.T) {
@ -360,9 +265,7 @@ func TestGenerateValidPackageName(t *testing.T) {
data, err := os.ReadFile(outFile)
require.NoError(t, err)
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package myspacecontract contains wrappers for My space contract contract.
require.Equal(t, `// Package myspacecontract contains wrappers for My space contract contract.
package myspacecontract
import (
@ -386,9 +289,7 @@ func Get() int {
data, err = os.ReadFile(outFile)
require.NoError(t, err)
require.Equal(t, `// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package myspacecontract contains RPC wrappers for My space contract contract.
require.Equal(t, `// Package myspacecontract contains RPC wrappers for My space contract contract.
package myspacecontract
import (
@ -409,7 +310,7 @@ type Invoker interface {
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
@ -488,7 +389,6 @@ func TestAssistedRPCBindings(t *testing.T) {
}
testName += fmt.Sprintf(", predefined hash: %t", hasDefinedHash)
t.Run(testName, func(t *testing.T) {
outFile := filepath.Join(tmpDir, "out.go")
configFile := filepath.Join(source, "config.yml")
expectedFile := filepath.Join(source, "rpcbindings.out")
if len(suffix) != 0 {
@ -515,14 +415,14 @@ func TestAssistedRPCBindings(t *testing.T) {
cmds := []string{"", "contract", "generate-rpcwrapper",
"--config", bindingF,
"--manifest", manifestF,
"--out", outFile,
"--out", expectedFile,
}
if hasDefinedHash {
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
}
require.NoError(t, app.Run(cmds))
data, err := os.ReadFile(outFile)
data, err := os.ReadFile(expectedFile)
require.NoError(t, err)
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
if rewriteExpectedOutputs {
@ -537,12 +437,12 @@ func TestAssistedRPCBindings(t *testing.T) {
}
for _, hasDefinedHash := range []bool{true, false} {
checkBinding(filepath.Join("testdata", "rpcbindings", "types"), hasDefinedHash, false)
checkBinding(filepath.Join("testdata", "rpcbindings", "structs"), hasDefinedHash, false)
checkBinding(filepath.Join("testdata", "types"), hasDefinedHash, false)
checkBinding(filepath.Join("testdata", "structs"), hasDefinedHash, false)
}
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false)
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false, "_extended")
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, true, "_guessed")
checkBinding(filepath.Join("testdata", "notifications"), true, false)
checkBinding(filepath.Join("testdata", "notifications"), true, false, "_extended")
checkBinding(filepath.Join("testdata", "notifications"), true, true, "_guessed")
require.False(t, rewriteExpectedOutputs)
}
@ -640,10 +540,10 @@ func TestCompile_GuessEventTypes(t *testing.T) {
}
t.Run("not declared in manifest", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid1"), "inconsistent usages of event `Non declared event`: not declared in the contract config")
check(t, filepath.Join("testdata", "invalid5"), "inconsistent usages of event `Non declared event`: not declared in the contract config")
})
t.Run("invalid number of params", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid2"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
check(t, filepath.Join("testdata", "invalid6"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
})
/*
// TODO: this on is a controversial one. If event information is provided in the config file, then conversion code
@ -652,61 +552,13 @@ func TestCompile_GuessEventTypes(t *testing.T) {
// Thus, this testcase is always failing (no compilation error occures).
// Question: do we want to compare `RealType` of the emitted parameter with the one expected in the manifest?
t.Run("SC parameter type mismatch", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid3"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
check(t, filepath.Join("testdata", "invalid7"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
})
*/
t.Run("extended types mismatch", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid4"), "inconsistent usages of event `SomeEvent`: extended type of param #0 mismatch")
check(t, filepath.Join("testdata", "invalid8"), "inconsistent usages of event `SomeEvent`: extended type of param #0 mismatch")
})
t.Run("named types redeclare", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid5"), "configured declared named type intersects with the contract's one: `invalid5.NamedStruct`")
})
}
func TestGenerateRPCBindings_Errors(t *testing.T) {
app := cli.NewApp()
app.Commands = NewCommands()
app.ExitErrHandler = func(*cli.Context, error) {}
t.Run("duplicating resulting fields", func(t *testing.T) {
check := func(t *testing.T, packageName string, autogen bool, expectedError string) {
tmpDir := t.TempDir()
source := filepath.Join("testdata", "rpcbindings", packageName)
configFile := filepath.Join(source, "invalid.yml")
out := filepath.Join(tmpDir, "rpcbindings.out")
manifestF := filepath.Join(tmpDir, "manifest.json")
bindingF := filepath.Join(tmpDir, "binding.yml")
nefF := filepath.Join(tmpDir, "out.nef")
cmd := []string{"", "contract", "compile",
"--in", source,
"--config", configFile,
"--manifest", manifestF,
"--bindings", bindingF,
"--out", nefF,
}
if autogen {
cmd = append(cmd, "--guess-eventtypes")
}
require.NoError(t, app.Run(cmd))
cmds := []string{"", "contract", "generate-rpcwrapper",
"--config", bindingF,
"--manifest", manifestF,
"--out", out,
}
err := app.Run(cmds)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), expectedError), err.Error())
}
t.Run("event", func(t *testing.T) {
check(t, "invalid6", false, "error during generation: named type `SomeStruct` has two fields with identical resulting binding name `Field`")
})
t.Run("autogen event", func(t *testing.T) {
check(t, "invalid7", true, "error during generation: named type `invalid7.SomeStruct` has two fields with identical resulting binding name `Field`")
})
t.Run("struct", func(t *testing.T) {
check(t, "invalid8", false, "error during generation: named type `invalid8.SomeStruct` has two fields with identical resulting binding name `Field`")
})
check(t, filepath.Join("testdata", "invalid9"), "configured declared named type intersects with the contract's one: `invalid9.NamedStruct`")
})
}

View file

@ -8,7 +8,6 @@ import (
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
@ -38,7 +37,7 @@ func manifestAddGroup(ctx *cli.Context) error {
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
gAcc, w, err := options.GetAccFromContext(ctx)
gAcc, w, err := getAccFromContext(ctx)
if err != nil {
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
}
@ -110,7 +109,7 @@ func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byt
if err != nil {
return nil, nil, err
}
if err := m.IsValid(hash, true); err != nil {
if err := m.IsValid(hash); err != nil {
return nil, nil, fmt.Errorf("manifest is invalid: %w", err)
}
return m, manifestBytes, nil

View file

@ -1,6 +1,7 @@
package smartcontract
import (
"encoding/hex"
"errors"
"fmt"
@ -27,9 +28,10 @@ func (p permission) MarshalYAML() (any, error) {
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
case manifest.PermissionGroup:
bs := p.Contract.Value.(*keys.PublicKey).Bytes()
m.Content = append(m.Content,
&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(*keys.PublicKey).StringCompressed()})
&yaml.Node{Kind: yaml.ScalarNode, Value: hex.EncodeToString(bs)})
default:
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
}

View file

@ -11,11 +11,14 @@ import (
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
"github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"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/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
@ -36,14 +39,25 @@ import (
const addressFlagName = "address, a"
var (
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
errNoMethod = errors.New("no method specified for function invocation command")
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
errFileExist = errors.New("A file with given smart-contract name already exists")
addressFlag = flags.AddressFlag{
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
errNoMethod = errors.New("no method specified for function invocation command")
errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
errFileExist = errors.New("A file with given smart-contract name already exists")
walletFlag = cli.StringFlag{
Name: "wallet, w",
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
}
walletConfigFlag = cli.StringFlag{
Name: "wallet-config",
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag",
}
addressFlag = flags.AddressFlag{
Name: addressFlagName,
Usage: "address to use as transaction signee (and gas source)",
}
@ -86,14 +100,14 @@ func NewCommands() []cli.Command {
testInvokeFunctionFlags := []cli.Flag{options.Historic}
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
invokeFunctionFlags := []cli.Flag{
walletFlag,
walletConfigFlag,
addressFlag,
txctx.GasFlag,
txctx.SysGasFlag,
txctx.OutFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
}
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
deployFlags := append(invokeFunctionFlags, []cli.Flag{
cli.StringFlag{
@ -105,24 +119,6 @@ func NewCommands() []cli.Command {
Usage: "Manifest input file (*.manifest.json)",
},
}...)
manifestAddGroupFlags := append([]cli.Flag{
cli.StringFlag{
Name: "sender, s",
Usage: "deploy transaction sender",
},
flags.AddressFlag{
Name: addressFlagName, // use the same name for handler code unification.
Usage: "account to sign group with",
},
cli.StringFlag{
Name: "nef, n",
Usage: "path to the NEF file",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "path to the manifest",
},
}, options.Wallet...)
return []cli.Command{{
Name: "contract",
Usage: "compile - debug - deploy smart contracts",
@ -137,8 +133,7 @@ func NewCommands() []cli.Command {
then the output filenames for these flags will be guessed using the contract
name or path provided via --in option by trimming/adding corresponding suffixes
to the common part of the path. In the latter case the configuration filepath
will be guessed from the --in option using the same rule.
`,
will be guessed from the --in option using the same rule."`,
Action: contractCompile,
Flags: []cli.Flag{
cli.StringFlag{
@ -190,12 +185,10 @@ func NewCommands() []cli.Command {
{
Name: "deploy",
Usage: "deploy a smart contract (.nef with description)",
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [--await] [data]",
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [data]",
Description: `Deploys given contract into the chain. The gas parameter is for additional
gas to be added as a network fee to prioritize the transaction. The data
parameter is an optional parameter to be passed to '_deploy' method. When
--await flag is specified, it waits for the transaction to be included
in a block.
parameter is an optional parameter to be passed to '_deploy' method.
`,
Action: contractDeploy,
Flags: deployFlags,
@ -205,14 +198,13 @@ func NewCommands() []cli.Command {
{
Name: "invokefunction",
Usage: "invoke deployed contract on the blockchain",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] [--await] scripthash [method] [arguments...] [--] [signers...]",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method,
arguments and signers. Sender is included in the list of signers by default
with None witness scope. If you'd like to change default sender's scope,
specify it via signers parameter. See testinvokefunction documentation for
the details about parameters. It differs from testinvokefunction in that this
command sends an invocation transaction to the network. When --await flag is
specified, it waits for the transaction to be included in a block.
command sends an invocation transaction to the network.
`,
Action: invokeFunction,
Flags: invokeFunctionFlags,
@ -309,7 +301,26 @@ func NewCommands() []cli.Command {
Usage: "adds group to the manifest",
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
Action: manifestAddGroup,
Flags: manifestAddGroupFlags,
Flags: []cli.Flag{
walletFlag,
walletConfigFlag,
cli.StringFlag{
Name: "sender, s",
Usage: "deploy transaction sender",
},
flags.AddressFlag{
Name: addressFlagName, // use the same name for handler code unification.
Usage: "account to sign group with",
},
cli.StringFlag{
Name: "nef, n",
Usage: "path to the NEF file",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "path to the manifest",
},
},
},
},
},
@ -375,9 +386,6 @@ func initSmartContract(ctx *cli.Context) error {
}
gm := []byte("module " + contractName + `
go 1.20
require (
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
)`)
@ -573,7 +581,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
w *wallet.Wallet
)
if signAndPush {
acc, w, err = options.GetAccFromContext(ctx)
acc, w, err = getAccFromContext(ctx)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -600,14 +608,19 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
}
gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel()
c, err := options.GetRPCClient(gctx, ctx)
if err != nil {
return err
}
if signAndPush {
_, act, err = options.GetRPCWithActor(gctx, ctx, signersAccounts)
act, err = actor.New(c, signersAccounts)
if err != nil {
return err
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
}
inv = &act.Invoker
} else {
_, inv, err = options.GetRPCWithInvoker(gctx, ctx, cosigners)
inv, err = options.GetInvoker(c, ctx, cosigners)
if err != nil {
return err
}
@ -744,6 +757,68 @@ func inspect(ctx *cli.Context) error {
return nil
}
func getAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
var addr util.Uint160
wPath := ctx.String("wallet")
walletConfigPath := ctx.String("wallet-config")
if len(wPath) != 0 && len(walletConfigPath) != 0 {
return nil, nil, errConflictingWalletFlags
}
if len(wPath) == 0 && len(walletConfigPath) == 0 {
return nil, nil, errNoWallet
}
var pass *string
if len(walletConfigPath) != 0 {
cfg, err := cliwallet.ReadWalletConfig(walletConfigPath)
if err != nil {
return nil, nil, err
}
wPath = cfg.Path
pass = &cfg.Password
}
wall, err := wallet.NewWalletFromFile(wPath)
if err != nil {
return nil, nil, err
}
addrFlag := ctx.Generic("address").(*flags.Address)
if addrFlag.IsSet {
addr = addrFlag.Uint160()
} else {
addr = wall.GetChangeAddress()
}
acc, err := getUnlockedAccount(wall, addr, pass)
return acc, wall, err
}
func getUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
}
if acc.CanSign() {
return acc, nil
}
if pass == nil {
rawPass, err := input.ReadPassword(
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
if err != nil {
return nil, fmt.Errorf("Error reading password: %w", err)
}
trimmed := strings.TrimRight(string(rawPass), "\n")
pass = &trimmed
}
err := acc.Decrypt(*pass, wall.Scrypt)
if err != nil {
return nil, err
}
return acc, nil
}
// contractDeploy deploys contract.
func contractDeploy(ctx *cli.Context) error {
nefFile, f, err := readNEFFile(ctx.String("in"))
@ -769,7 +844,7 @@ func contractDeploy(ctx *cli.Context) error {
appCallParams = append(appCallParams, data[0])
}
acc, w, err := options.GetAccFromContext(ctx)
acc, w, err := getAccFromContext(ctx)
if err != nil {
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
}

View file

@ -1,6 +1,7 @@
package smartcontract
import (
"encoding/hex"
"flag"
"os"
"testing"
@ -108,7 +109,7 @@ func TestPermissionMarshal(t *testing.T) {
p.Methods.Add("abc")
p.Methods.Add("lamao")
testPermissionMarshal(t, p,
"group: "+priv.PublicKey().StringCompressed()+"\n"+
"group: "+hex.EncodeToString(priv.PublicKey().Bytes())+"\n"+
"methods:\n - abc\n - lamao\n")
})
}
@ -117,7 +118,7 @@ func TestPermissionUnmarshalInvalid(t *testing.T) {
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
pub := priv.PublicKey().StringCompressed()
pub := hex.EncodeToString(priv.PublicKey().Bytes())
u160 := random.Uint160().StringLE()
testCases := []string{
"hash: []\nmethods: '*'\n", // invalid hash type

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package gastoken contains RPC wrappers for GasToken contract.
package gastoken
@ -27,7 +25,7 @@ type Actor interface {
type ContractReader struct {
nep17.TokenReader
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// Contract implements all contract methods.
@ -35,7 +33,7 @@ type Contract struct {
ContractReader
nep17.TokenWriter
actor Actor
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.

View file

@ -1,4 +1,4 @@
package invalid1
package invalid5
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"

View file

@ -1,4 +1,4 @@
package invalid2
package invalid6
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"

View file

@ -1,4 +1,4 @@
package invalid3
package invalid7
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"

View file

@ -1,4 +1,4 @@
package invalid4
package invalid8
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"

View file

@ -1,4 +1,4 @@
package invalid5
package invalid9
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"

View file

@ -6,11 +6,11 @@ events:
type: Array
extendedtype:
base: Array
name: invalid5.NamedStruct
name: invalid9.NamedStruct
namedtypes:
invalid5.NamedStruct:
invalid9.NamedStruct:
base: Array
name: invalid5.NamedStruct
name: invalid9.NamedStruct
fields:
- field: SomeInt
base: Integer

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nameservice contains RPC wrappers for NameService contract.
package nameservice
@ -23,14 +21,14 @@ var Hash = util.Uint160{0xde, 0x46, 0x5f, 0x5d, 0x50, 0x57, 0xcf, 0x33, 0x28, 0x
// SetAdminEvent represents "SetAdmin" event emitted by the contract.
type SetAdminEvent struct {
Name string
Name string
OldAdmin util.Uint160
NewAdmin util.Uint160
}
// RenewEvent represents "Renew" event emitted by the contract.
type RenewEvent struct {
Name string
Name string
OldExpiration *big.Int
NewExpiration *big.Int
}
@ -58,7 +56,7 @@ type Actor interface {
type ContractReader struct {
nep11.NonDivisibleReader
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// Contract implements all contract methods.
@ -66,7 +64,7 @@ type Contract struct {
ContractReader
nep11.BaseWriter
actor Actor
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
@ -256,25 +254,25 @@ func (c *Contract) RenewUnsigned(name string) (*transaction.Transaction, error)
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name)
}
// Renew2 creates a transaction invoking `renew` method of the contract.
// Renew_2 creates a transaction invoking `renew` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Renew2(name string, years *big.Int) (util.Uint256, uint32, error) {
func (c *Contract) Renew_2(name string, years *big.Int) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "renew", name, years)
}
// Renew2Transaction creates a transaction invoking `renew` method of the contract.
// Renew_2Transaction creates a transaction invoking `renew` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) Renew2Transaction(name string, years *big.Int) (*transaction.Transaction, error) {
func (c *Contract) Renew_2Transaction(name string, years *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "renew", name, years)
}
// Renew2Unsigned creates a transaction invoking `renew` method of the contract.
// Renew_2Unsigned creates a transaction invoking `renew` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) Renew2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) {
func (c *Contract) Renew_2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name, years)
}
@ -385,10 +383,10 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.Name, err = func(item stackitem.Item) (string, error) {
e.Name, err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -397,13 +395,13 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field Name: %w", err)
}
index++
e.OldAdmin, err = func(item stackitem.Item) (util.Uint160, error) {
e.OldAdmin, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -413,13 +411,13 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field OldAdmin: %w", err)
}
index++
e.NewAdmin, err = func(item stackitem.Item) (util.Uint160, error) {
e.NewAdmin, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -429,7 +427,7 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field NewAdmin: %w", err)
}
@ -478,10 +476,10 @@ func (e *RenewEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.Name, err = func(item stackitem.Item) (string, error) {
e.Name, err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -490,7 +488,7 @@ func (e *RenewEvent) FromStackItem(item *stackitem.Array) error {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field Name: %w", err)
}

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nextoken contains RPC wrappers for NEX Token contract.
package nextoken
@ -21,8 +19,8 @@ var Hash = util.Uint160{0xa8, 0x1a, 0xa1, 0xf0, 0x4b, 0xf, 0xdc, 0x4a, 0xa2, 0xc
// OnMintEvent represents "OnMint" event emitted by the contract.
type OnMintEvent struct {
From util.Uint160
To util.Uint160
From util.Uint160
To util.Uint160
Amount *big.Int
SwapId *big.Int
}
@ -50,7 +48,7 @@ type Actor interface {
type ContractReader struct {
nep17.TokenReader
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// Contract implements all contract methods.
@ -58,7 +56,7 @@ type Contract struct {
ContractReader
nep17.TokenWriter
actor Actor
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
@ -289,10 +287,10 @@ func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.From, err = func(item stackitem.Item) (util.Uint160, error) {
e.From, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -302,13 +300,13 @@ func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field From: %w", err)
}
index++
e.To, err = func(item stackitem.Item) (util.Uint160, error) {
e.To, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -318,7 +316,7 @@ func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field To: %w", err)
}

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nonnepxxcontractwithiterators contains RPC wrappers for Non-NEPXX contract with iterators contract.
package nonnepxxcontractwithiterators
@ -25,7 +23,7 @@ type Invoker interface {
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.

View file

@ -17,7 +17,3 @@ events:
parameters:
- name: a
type: Array
- name: "SomeUnexportedField"
parameters:
- name: s
type: Struct

View file

@ -36,13 +36,6 @@ events:
base: Array
value:
base: Integer
- name: "SomeUnexportedField"
parameters:
- name: s
type: Struct
extendedtype:
base: Struct
name: simpleStruct
namedtypes:
crazyStruct:
base: Struct
@ -52,9 +45,3 @@ namedtypes:
base: Integer
- field: B
base: Boolean
simpleStruct:
base: Struct
name: simpleStruct
fields:
- field: i
base: Integer

View file

@ -17,7 +17,3 @@ events:
parameters:
- name: a
type: Array
- name: "SomeUnexportedField"
parameters:
- name: s
type: Struct

View file

@ -23,11 +23,3 @@ func Struct() {
func Array() {
runtime.Notify("SomeArray", [][]int{})
}
// UnexportedField emits notification with unexported field that must be converted
// to exported in the resulting RPC binding.
func UnexportedField() {
runtime.Notify("SomeUnexportedField", struct {
i int
}{i: 123})
}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"crypto/elliptic"
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -23,9 +23,64 @@ type CrazyStruct struct {
B bool
}
// SimpleStruct is a contract-specific simpleStruct type used by its methods.
type SimpleStruct struct {
I *big.Int
// LedgerBlock is a contract-specific ledger.Block type used by its methods.
type LedgerBlock struct {
Hash util.Uint256
Version *big.Int
PrevHash util.Uint256
MerkleRoot util.Uint256
Timestamp *big.Int
Nonce *big.Int
Index *big.Int
NextConsensus util.Uint160
TransactionsLength *big.Int
}
// LedgerBlockSR is a contract-specific ledger.BlockSR type used by its methods.
type LedgerBlockSR struct {
Hash util.Uint256
Version *big.Int
PrevHash util.Uint256
MerkleRoot util.Uint256
Timestamp *big.Int
Nonce *big.Int
Index *big.Int
NextConsensus util.Uint160
TransactionsLength *big.Int
PrevStateRoot util.Uint256
}
// LedgerTransaction is a contract-specific ledger.Transaction type used by its methods.
type LedgerTransaction struct {
Hash util.Uint256
Version *big.Int
Nonce *big.Int
Sender util.Uint160
SysFee *big.Int
NetFee *big.Int
ValidUntilBlock *big.Int
Script []byte
}
// LedgerTransactionSigner is a contract-specific ledger.TransactionSigner type used by its methods.
type LedgerTransactionSigner struct {
Account util.Uint160
Scopes *big.Int
AllowedContracts []util.Uint160
AllowedGroups keys.PublicKeys
Rules []*LedgerWitnessRule
}
// LedgerWitnessCondition is a contract-specific ledger.WitnessCondition type used by its methods.
type LedgerWitnessCondition struct {
Type *big.Int
Value any
}
// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods.
type LedgerWitnessRule struct {
Action *big.Int
Condition *LedgerWitnessCondition
}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
@ -48,11 +103,6 @@ type SomeArrayEvent struct {
A [][]*big.Int
}
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
type SomeUnexportedFieldEvent struct {
S *SimpleStruct
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
@ -66,7 +116,7 @@ type Actor interface {
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
@ -163,28 +213,6 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
}
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "unexportedField")
}
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "unexportedField")
}
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
}
// itemToCrazyStruct converts stack item into *CrazyStruct.
func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
if err != nil {
@ -208,7 +236,7 @@ func (res *CrazyStruct) FromStackItem(item stackitem.Item) error {
var (
index = -1
err error
err error
)
index++
res.I, err = arr[index].TryInteger()
@ -225,35 +253,564 @@ func (res *CrazyStruct) FromStackItem(item stackitem.Item) error {
return nil
}
// itemToSimpleStruct converts stack item into *SimpleStruct.
func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
// itemToLedgerBlock converts stack item into *LedgerBlock.
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
if err != nil {
return nil, err
}
var res = new(SimpleStruct)
var res = new(LedgerBlock)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of SimpleStruct from the given
// FromStackItem retrieves fields of LedgerBlock from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *SimpleStruct) FromStackItem(item stackitem.Item) error {
func (res *LedgerBlock) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
if len(arr) != 9 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
err error
)
index++
res.I, err = arr[index].TryInteger()
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field I: %w", err)
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevHash: %w", err)
}
index++
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field MerkleRoot: %w", err)
}
index++
res.Timestamp, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Timestamp: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Index, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Index: %w", err)
}
index++
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field NextConsensus: %w", err)
}
index++
res.TransactionsLength, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field TransactionsLength: %w", err)
}
return nil
}
// itemToLedgerBlockSR converts stack item into *LedgerBlockSR.
func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) {
if err != nil {
return nil, err
}
var res = new(LedgerBlockSR)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerBlockSR from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerBlockSR) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 10 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevHash: %w", err)
}
index++
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field MerkleRoot: %w", err)
}
index++
res.Timestamp, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Timestamp: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Index, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Index: %w", err)
}
index++
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field NextConsensus: %w", err)
}
index++
res.TransactionsLength, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field TransactionsLength: %w", err)
}
index++
res.PrevStateRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevStateRoot: %w", err)
}
return nil
}
// itemToLedgerTransaction converts stack item into *LedgerTransaction.
func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) {
if err != nil {
return nil, err
}
var res = new(LedgerTransaction)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerTransaction from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerTransaction) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 8 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Sender, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Sender: %w", err)
}
index++
res.SysFee, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field SysFee: %w", err)
}
index++
res.NetFee, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field NetFee: %w", err)
}
index++
res.ValidUntilBlock, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field ValidUntilBlock: %w", err)
}
index++
res.Script, err = arr[index].TryBytes()
if err != nil {
return fmt.Errorf("field Script: %w", err)
}
return nil
}
// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner.
func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) {
if err != nil {
return nil, err
}
var res = new(LedgerTransactionSigner)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerTransactionSigner from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerTransactionSigner) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 5 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Account, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Account: %w", err)
}
index++
res.Scopes, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Scopes: %w", err)
}
index++
res.AllowedContracts, err = func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field AllowedContracts: %w", err)
}
index++
res.AllowedGroups, err = func (item stackitem.Item) (keys.PublicKeys, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make(keys.PublicKeys, len(arr))
for i := range res {
res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) {
b, err := item.TryBytes()
if err != nil {
return nil, err
}
k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256())
if err != nil {
return nil, err
}
return k, nil
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field AllowedGroups: %w", err)
}
index++
res.Rules, err = func (item stackitem.Item) ([]*LedgerWitnessRule, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]*LedgerWitnessRule, len(arr))
for i := range res {
res[i], err = itemToLedgerWitnessRule(arr[i], nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Rules: %w", err)
}
return nil
}
// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition.
func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) {
if err != nil {
return nil, err
}
var res = new(LedgerWitnessCondition)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerWitnessCondition from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerWitnessCondition) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Type, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Type: %w", err)
}
index++
res.Value, err = arr[index].Value(), error(nil)
if err != nil {
return fmt.Errorf("field Value: %w", err)
}
return nil
}
// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule.
func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) {
if err != nil {
return nil, err
}
var res = new(LedgerWitnessRule)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerWitnessRule from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerWitnessRule) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Action, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Action: %w", err)
}
index++
res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil)
if err != nil {
return fmt.Errorf("field Condition: %w", err)
}
return nil
@ -300,10 +857,10 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
e.ComplicatedParam, err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -312,7 +869,7 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
@ -361,10 +918,10 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.M, err = func(item stackitem.Item) (map[*big.Int]map[string][]util.Uint160, error) {
e.M, err = func (item stackitem.Item) (map[*big.Int]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -375,14 +932,14 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) (map[string][]util.Uint160, error) {
v, err := func (item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
k, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -391,18 +948,18 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
} (m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -412,27 +969,27 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
return util.Uint160{}, err
}
return u, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field M: %w", err)
}
@ -481,7 +1038,7 @@ func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.S, err = itemToCrazyStruct(arr[index], nil)
@ -533,17 +1090,17 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.A, err = func(item stackitem.Item) ([][]*big.Int, error) {
e.A, err = func (item stackitem.Item) ([][]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]*big.Int, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]*big.Int, error) {
res[i], err = func (item stackitem.Item) ([]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
@ -556,68 +1113,16 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
}
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field A: %w", err)
}
return nil
}
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeUnexportedFieldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeUnexportedField" {
continue
}
event := new(SomeUnexportedFieldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
// returns an error if it's not possible to do to so.
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = itemToSimpleStruct(arr[index], nil)
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}

View file

@ -1,12 +1,12 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"crypto/elliptic"
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -17,17 +17,72 @@ import (
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// LedgerBlock is a contract-specific ledger.Block type used by its methods.
type LedgerBlock struct {
Hash util.Uint256
Version *big.Int
PrevHash util.Uint256
MerkleRoot util.Uint256
Timestamp *big.Int
Nonce *big.Int
Index *big.Int
NextConsensus util.Uint160
TransactionsLength *big.Int
}
// LedgerBlockSR is a contract-specific ledger.BlockSR type used by its methods.
type LedgerBlockSR struct {
Hash util.Uint256
Version *big.Int
PrevHash util.Uint256
MerkleRoot util.Uint256
Timestamp *big.Int
Nonce *big.Int
Index *big.Int
NextConsensus util.Uint160
TransactionsLength *big.Int
PrevStateRoot util.Uint256
}
// LedgerTransaction is a contract-specific ledger.Transaction type used by its methods.
type LedgerTransaction struct {
Hash util.Uint256
Version *big.Int
Nonce *big.Int
Sender util.Uint160
SysFee *big.Int
NetFee *big.Int
ValidUntilBlock *big.Int
Script []byte
}
// LedgerTransactionSigner is a contract-specific ledger.TransactionSigner type used by its methods.
type LedgerTransactionSigner struct {
Account util.Uint160
Scopes *big.Int
AllowedContracts []util.Uint160
AllowedGroups keys.PublicKeys
Rules []*LedgerWitnessRule
}
// LedgerWitnessCondition is a contract-specific ledger.WitnessCondition type used by its methods.
type LedgerWitnessCondition struct {
Type *big.Int
Value any
}
// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods.
type LedgerWitnessRule struct {
Action *big.Int
Condition *LedgerWitnessCondition
}
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
B bool
}
// UnnamedX is a contract-specific unnamedX type used by its methods.
type UnnamedX struct {
I *big.Int
}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
type ComplicatedNameEvent struct {
ComplicatedParam string
@ -48,11 +103,6 @@ type SomeArrayEvent struct {
A [][]*big.Int
}
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
type SomeUnexportedFieldEvent struct {
S *UnnamedX
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
@ -66,7 +116,7 @@ type Actor interface {
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
@ -163,26 +213,567 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
}
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "unexportedField")
// itemToLedgerBlock converts stack item into *LedgerBlock.
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
if err != nil {
return nil, err
}
var res = new(LedgerBlock)
err = res.FromStackItem(item)
return res, err
}
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "unexportedField")
// FromStackItem retrieves fields of LedgerBlock from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerBlock) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 9 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevHash: %w", err)
}
index++
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field MerkleRoot: %w", err)
}
index++
res.Timestamp, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Timestamp: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Index, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Index: %w", err)
}
index++
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field NextConsensus: %w", err)
}
index++
res.TransactionsLength, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field TransactionsLength: %w", err)
}
return nil
}
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
// itemToLedgerBlockSR converts stack item into *LedgerBlockSR.
func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) {
if err != nil {
return nil, err
}
var res = new(LedgerBlockSR)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerBlockSR from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerBlockSR) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 10 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevHash: %w", err)
}
index++
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field MerkleRoot: %w", err)
}
index++
res.Timestamp, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Timestamp: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Index, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Index: %w", err)
}
index++
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field NextConsensus: %w", err)
}
index++
res.TransactionsLength, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field TransactionsLength: %w", err)
}
index++
res.PrevStateRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevStateRoot: %w", err)
}
return nil
}
// itemToLedgerTransaction converts stack item into *LedgerTransaction.
func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) {
if err != nil {
return nil, err
}
var res = new(LedgerTransaction)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerTransaction from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerTransaction) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 8 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Sender, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Sender: %w", err)
}
index++
res.SysFee, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field SysFee: %w", err)
}
index++
res.NetFee, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field NetFee: %w", err)
}
index++
res.ValidUntilBlock, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field ValidUntilBlock: %w", err)
}
index++
res.Script, err = arr[index].TryBytes()
if err != nil {
return fmt.Errorf("field Script: %w", err)
}
return nil
}
// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner.
func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) {
if err != nil {
return nil, err
}
var res = new(LedgerTransactionSigner)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerTransactionSigner from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerTransactionSigner) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 5 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Account, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Account: %w", err)
}
index++
res.Scopes, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Scopes: %w", err)
}
index++
res.AllowedContracts, err = func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field AllowedContracts: %w", err)
}
index++
res.AllowedGroups, err = func (item stackitem.Item) (keys.PublicKeys, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make(keys.PublicKeys, len(arr))
for i := range res {
res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) {
b, err := item.TryBytes()
if err != nil {
return nil, err
}
k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256())
if err != nil {
return nil, err
}
return k, nil
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field AllowedGroups: %w", err)
}
index++
res.Rules, err = func (item stackitem.Item) ([]*LedgerWitnessRule, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]*LedgerWitnessRule, len(arr))
for i := range res {
res[i], err = itemToLedgerWitnessRule(arr[i], nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Rules: %w", err)
}
return nil
}
// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition.
func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) {
if err != nil {
return nil, err
}
var res = new(LedgerWitnessCondition)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerWitnessCondition from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerWitnessCondition) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Type, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Type: %w", err)
}
index++
res.Value, err = arr[index].Value(), error(nil)
if err != nil {
return fmt.Errorf("field Value: %w", err)
}
return nil
}
// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule.
func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) {
if err != nil {
return nil, err
}
var res = new(LedgerWitnessRule)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerWitnessRule from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *LedgerWitnessRule) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Action, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Action: %w", err)
}
index++
res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil)
if err != nil {
return fmt.Errorf("field Condition: %w", err)
}
return nil
}
// itemToUnnamed converts stack item into *Unnamed.
@ -208,7 +799,7 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
var (
index = -1
err error
err error
)
index++
res.I, err = arr[index].TryInteger()
@ -225,40 +816,6 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
return nil
}
// itemToUnnamedX converts stack item into *UnnamedX.
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
if err != nil {
return nil, err
}
var res = new(UnnamedX)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of UnnamedX from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
@ -300,10 +857,10 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
e.ComplicatedParam, err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -312,7 +869,7 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
@ -361,10 +918,10 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.M, err = func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
e.M, err = func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -375,21 +932,21 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]map[string][]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
k, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -398,18 +955,18 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
} (m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -419,33 +976,33 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
return util.Uint160{}, err
}
return u, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field M: %w", err)
}
@ -494,7 +1051,7 @@ func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.S, err = itemToUnnamed(arr[index], nil)
@ -546,17 +1103,17 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.A, err = func(item stackitem.Item) ([][]*big.Int, error) {
e.A, err = func (item stackitem.Item) ([][]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]*big.Int, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]*big.Int, error) {
res[i], err = func (item stackitem.Item) ([]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
@ -569,68 +1126,16 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
}
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field A: %w", err)
}
return nil
}
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeUnexportedFieldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeUnexportedField" {
continue
}
event := new(SomeUnexportedFieldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
// returns an error if it's not possible to do to so.
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = itemToUnnamedX(arr[index], nil)
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}

View file

@ -1,14 +0,0 @@
package invalid6
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
type SomeStruct struct {
Field int
// RPC binding generator will convert this field into exported, which matches
// exactly the existing Field.
field int
}
func Main() {
runtime.Notify("SomeEvent", SomeStruct{Field: 123, field: 123})
}

View file

@ -1,18 +0,0 @@
name: Test duplicating event fields
events:
- name: SomeEvent
parameters:
- name: p1
type: Struct
extendedtype:
base: Struct
name: SomeStruct
namedtypes:
SomeStruct:
base: Struct
name: SomeStruct
fields:
- field: Field
base: Integer
- field: field
base: Integer

View file

@ -1,14 +0,0 @@
package invalid7
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
type SomeStruct struct {
Field int
// RPC binding generator will convert this field into exported, which matches
// exactly the existing Field.
field int
}
func Main() {
runtime.Notify("SomeEvent", SomeStruct{Field: 123, field: 123})
}

View file

@ -1,6 +0,0 @@
name: Test duplicating autogenerated event fields
events:
- name: SomeEvent
parameters:
- name: p1
type: Struct

View file

@ -1,16 +0,0 @@
package invalid8
type SomeStruct struct {
Field int
// RPC binding generator will convert this field into exported, which matches
// exactly the existing Field.
field int
}
func Main() SomeStruct {
s := SomeStruct{
Field: 1,
field: 2,
}
return s
}

View file

@ -1 +0,0 @@
name: Test duplicating struct fields

View file

@ -1,500 +0,0 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"unicode/utf8"
)
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
type ComplicatedNameEvent struct {
ComplicatedParam string
}
// SomeMapEvent represents "SomeMap" event emitted by the contract.
type SomeMapEvent struct {
M map[any]any
}
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
type SomeStructEvent struct {
S []any
}
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
type SomeArrayEvent struct {
A []any
}
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
type SomeUnexportedFieldEvent struct {
S []any
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract {
var hash = Hash
return &Contract{actor, hash}
}
// Array creates a transaction invoking `array` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Array() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "array")
}
// ArrayTransaction creates a transaction invoking `array` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) ArrayTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "array")
}
// ArrayUnsigned creates a transaction invoking `array` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) ArrayUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "array", nil)
}
// CrazyMap creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) CrazyMap() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "crazyMap")
}
// CrazyMapTransaction creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) CrazyMapTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "crazyMap")
}
// CrazyMapUnsigned creates a transaction invoking `crazyMap` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) CrazyMapUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "crazyMap", nil)
}
// Main creates a transaction invoking `main` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Main() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "main")
}
// MainTransaction creates a transaction invoking `main` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) MainTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "main")
}
// MainUnsigned creates a transaction invoking `main` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) MainUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "main", nil)
}
// Struct creates a transaction invoking `struct` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Struct() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "struct")
}
// StructTransaction creates a transaction invoking `struct` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) StructTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "struct")
}
// StructUnsigned creates a transaction invoking `struct` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
}
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "unexportedField")
}
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "unexportedField")
}
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
}
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*ComplicatedNameEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "! complicated name %$#" {
continue
}
event := new(ComplicatedNameEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize ComplicatedNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to ComplicatedNameEvent or
// returns an error if it's not possible to do to so.
func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
return nil
}
// SomeMapEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeMap" name from the provided [result.ApplicationLog].
func SomeMapEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeMapEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeMapEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeMap" {
continue
}
event := new(SomeMapEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeMapEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeMapEvent or
// returns an error if it's not possible to do to so.
func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.M, err = func(item stackitem.Item) (map[any]any, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[any]any)
for i := range m {
k, err := m[i].Key.Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := m[i].Value.Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field M: %w", err)
}
return nil
}
// SomeStructEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeStruct" name from the provided [result.ApplicationLog].
func SomeStructEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeStructEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeStructEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeStruct" {
continue
}
event := new(SomeStructEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeStructEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeStructEvent or
// returns an error if it's not possible to do to so.
func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}
// SomeArrayEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeArray" name from the provided [result.ApplicationLog].
func SomeArrayEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeArrayEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeArrayEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeArray" {
continue
}
event := new(SomeArrayEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeArrayEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeArrayEvent or
// returns an error if it's not possible to do to so.
func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.A, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field A: %w", err)
}
return nil
}
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeUnexportedFieldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeUnexportedField" {
continue
}
event := new(SomeUnexportedFieldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
// returns an error if it's not possible to do to so.
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}

View file

@ -1,40 +0,0 @@
package structs
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
)
type Internal struct {
Bool bool
Int int
Bytes []byte
String string
H160 interop.Hash160
H256 interop.Hash256
PK interop.PublicKey
PubKey interop.PublicKey
Sign interop.Signature
ArrOfBytes [][]byte
ArrOfH160 []interop.Hash160
Map map[int][]interop.PublicKey
Struct *Internal
unexportedField int // this one should be exported in the resulting RPC binding.
}
func Contract(mc management.Contract) management.Contract {
return mc
}
func Block(b *ledger.Block) *ledger.Block {
return b
}
func Transaction(t *ledger.Transaction) *ledger.Transaction {
return t
}
func Struct(s *Internal) *Internal {
return s
}

View file

@ -0,0 +1,39 @@
package structs
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
)
type Internal struct {
Bool bool
Int int
Bytes []byte
String string
H160 interop.Hash160
H256 interop.Hash256
PK interop.PublicKey
PubKey interop.PublicKey
Sign interop.Signature
ArrOfBytes [][]byte
ArrOfH160 []interop.Hash160
Map map[int][]interop.PublicKey
Struct *Internal
}
func Contract(mc management.Contract) management.Contract {
return mc
}
func Block(b *ledger.Block) *ledger.Block {
return b
}
func Transaction(t *ledger.Transaction) *ledger.Transaction {
return t
}
func Struct(s *Internal) *Internal {
return s
}

View file

@ -1,3 +1,3 @@
name: "Types"
sourceurl: https://github.com/nspcc-dev/neo-go/
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps", "unnamedStructs", "unnamedStructsX"]
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps"]

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package types contains RPC wrappers for Types contract.
package types
@ -18,17 +16,6 @@ import (
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
}
// UnnamedX is a contract-specific unnamedX type used by its methods.
type UnnamedX struct {
I *big.Int
B bool
}
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
@ -37,7 +24,7 @@ type Invoker interface {
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
@ -48,32 +35,32 @@ func NewReader(invoker Invoker) *ContractReader {
// AAAStrings invokes `aAAStrings` method of contract.
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return func(item stackitem.Item, err error) ([][][]string, error) {
return func (item stackitem.Item, err error) ([][][]string, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) ([][][]string, error) {
return func (item stackitem.Item) ([][][]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][][]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([][]string, error) {
res[i], err = func (item stackitem.Item) ([][]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]string, error) {
res[i], err = func (item stackitem.Item) ([]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (string, error) {
res[i], err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -82,45 +69,45 @@ func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
}
// Any invokes `any` method of contract.
func (c *ContractReader) Any(a any) (any, error) {
return func(item stackitem.Item, err error) (any, error) {
return func (item stackitem.Item, err error) (any, error) {
if err != nil {
return nil, err
}
return item.Value(), error(nil)
}(unwrap.Item(c.invoker.Call(c.hash, "any", a)))
} (unwrap.Item(c.invoker.Call(c.hash, "any", a)))
}
// AnyMaps invokes `anyMaps` method of contract.
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
return func(item stackitem.Item, err error) (map[*big.Int]any, error) {
return func (item stackitem.Item, err error) (map[*big.Int]any, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int]any, error) {
return func (item stackitem.Item) (map[*big.Int]any, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -138,8 +125,8 @@ func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
}
// Bool invokes `bool` method of contract.
@ -164,11 +151,11 @@ func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
// CrazyMaps invokes `crazyMaps` method of contract.
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
return func(item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
return func (item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
return func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -179,21 +166,21 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]map[string][]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
k, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -202,18 +189,18 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
} (m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -223,34 +210,34 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
return util.Uint160{}, err
}
return u, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
}
// Hash160 invokes `hash160` method of contract.
@ -285,18 +272,18 @@ func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
// Maps invokes `maps` method of contract.
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return func(item stackitem.Item, err error) (map[string]string, error) {
return func (item stackitem.Item, err error) (map[string]string, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[string]string, error) {
return func (item stackitem.Item) (map[string]string, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string]string)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
k, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -305,11 +292,11 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
} (m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) (string, error) {
v, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -318,15 +305,15 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
}
// PublicKey invokes `publicKey` method of contract.
@ -358,87 +345,3 @@ func (c *ContractReader) String(s string) (string, error) {
func (c *ContractReader) Strings(s []string) ([]string, error) {
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
}
// UnnamedStructs invokes `unnamedStructs` method of contract.
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
}
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
}
// itemToUnnamed converts stack item into *Unnamed.
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
if err != nil {
return nil, err
}
var res = new(Unnamed)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of Unnamed from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// itemToUnnamedX converts stack item into *UnnamedX.
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
if err != nil {
return nil, err
}
var res = new(UnnamedX)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of UnnamedX from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}
return nil
}

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package types contains RPC wrappers for Types contract.
package types
@ -15,17 +13,6 @@ import (
"unicode/utf8"
)
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
}
// UnnamedX is a contract-specific unnamedX type used by its methods.
type UnnamedX struct {
I *big.Int
B bool
}
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
@ -34,7 +21,7 @@ type Invoker interface {
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
@ -44,32 +31,32 @@ func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
// AAAStrings invokes `aAAStrings` method of contract.
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return func(item stackitem.Item, err error) ([][][]string, error) {
return func (item stackitem.Item, err error) ([][][]string, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) ([][][]string, error) {
return func (item stackitem.Item) ([][][]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][][]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([][]string, error) {
res[i], err = func (item stackitem.Item) ([][]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]string, error) {
res[i], err = func (item stackitem.Item) ([]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (string, error) {
res[i], err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -78,45 +65,45 @@ func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
}
// Any invokes `any` method of contract.
func (c *ContractReader) Any(a any) (any, error) {
return func(item stackitem.Item, err error) (any, error) {
return func (item stackitem.Item, err error) (any, error) {
if err != nil {
return nil, err
}
return item.Value(), error(nil)
}(unwrap.Item(c.invoker.Call(c.hash, "any", a)))
} (unwrap.Item(c.invoker.Call(c.hash, "any", a)))
}
// AnyMaps invokes `anyMaps` method of contract.
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
return func(item stackitem.Item, err error) (map[*big.Int]any, error) {
return func (item stackitem.Item, err error) (map[*big.Int]any, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int]any, error) {
return func (item stackitem.Item) (map[*big.Int]any, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -134,8 +121,8 @@ func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
}
// Bool invokes `bool` method of contract.
@ -160,11 +147,11 @@ func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
// CrazyMaps invokes `crazyMaps` method of contract.
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
return func(item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
return func (item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
return func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -175,21 +162,21 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]map[string][]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
k, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -198,18 +185,18 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
} (m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
@ -219,34 +206,34 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
return util.Uint160{}, err
}
return u, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[i])
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
}
// Hash160 invokes `hash160` method of contract.
@ -281,18 +268,18 @@ func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
// Maps invokes `maps` method of contract.
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return func(item stackitem.Item, err error) (map[string]string, error) {
return func (item stackitem.Item, err error) (map[string]string, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[string]string, error) {
return func (item stackitem.Item) (map[string]string, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string]string)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
k, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -301,11 +288,11 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
} (m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) (string, error) {
v, err := func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
@ -314,15 +301,15 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Value)
} (m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
} (item)
} (unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
}
// PublicKey invokes `publicKey` method of contract.
@ -354,87 +341,3 @@ func (c *ContractReader) String(s string) (string, error) {
func (c *ContractReader) Strings(s []string) ([]string, error) {
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
}
// UnnamedStructs invokes `unnamedStructs` method of contract.
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
}
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
}
// itemToUnnamed converts stack item into *Unnamed.
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
if err != nil {
return nil, err
}
var res = new(Unnamed)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of Unnamed from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// itemToUnnamedX converts stack item into *UnnamedX.
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
if err != nil {
return nil, err
}
var res = new(UnnamedX)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of UnnamedX from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}
return nil
}

View file

@ -87,17 +87,3 @@ func CrazyMaps(m map[int][]map[string][]interop.Hash160) map[int][]map[string][]
func AnyMaps(m map[int]any) map[int]any {
return m
}
func UnnamedStructs() struct{ I int } {
return struct{ I int }{I: 123}
}
func UnnamedStructsX() struct {
I int
B bool
} {
return struct {
I int
B bool
}{I: 123, B: true}
}

View file

@ -1,297 +0,0 @@
package: testdata
hash: "0x0000000000000000000000000000000000000000"
overrides:
burnGas.gas: int
call: any
call.args: '[]any'
call.f: any
call.method: string
call.scriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
callWithToken: any
callWithToken.args: '[]any'
callWithToken.flags: int
callWithToken.method: string
callWithToken.scriptHash: string
callWithTokenNoRet.args: '[]any'
callWithTokenNoRet.flags: int
callWithTokenNoRet.method: string
callWithTokenNoRet.scriptHash: string
checkWitness: bool
checkWitness.hashOrKey: '[]byte'
createMultisigAccount: '[]byte'
createMultisigAccount.m: int
createMultisigAccount.pubs: '[]github.com/nspcc-dev/neo-go/pkg/interop.PublicKey'
createStandardAccount: '[]byte'
createStandardAccount.pub: github.com/nspcc-dev/neo-go/pkg/interop.PublicKey
currentHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
currentIndex: int
currentSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
equals: bool
equals.b: any
gasLeft: int
getAddressVersion: int
getBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Block'
getBlock.indexOrHash: any
getCallFlags: any
getCallingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getEntryScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getExecutingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getInvocationCounter: int
getNetwork: int
getNotifications: '[][]any'
getNotifications.h: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getRandom: int
getScriptContainer: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
getTime: int
getTransaction: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
getTransaction.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTransactionFromBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
getTransactionFromBlock.indexOrHash: any
getTransactionFromBlock.txIndex: int
getTransactionHeight: int
getTransactionHeight.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTransactionSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
getTransactionSigners.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTransactionVMState: int
getTransactionVMState.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTrigger: int
loadScript: any
loadScript.args: '[]any'
loadScript.f: any
loadScript.script: '[]byte'
log.message: string
notify.args: '[]any'
notify.name: string
onNEP11Payment.amount: int
onNEP11Payment.data: any
onNEP11Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
onNEP11Payment.token: '[]byte'
onNEP17Payment.amount: int
onNEP17Payment.data: any
onNEP17Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
opcode0NoReturn.op: string
opcode1: any
opcode1NoReturn.arg: any
opcode1NoReturn.op: string
opcode1.arg: any
opcode1.op: string
opcode2: any
opcode2NoReturn.arg1: any
opcode2NoReturn.arg2: any
opcode2NoReturn.op: string
opcode2.arg1: any
opcode2.arg2: any
opcode2.op: string
opcode3: any
opcode3.arg1: any
opcode3.arg2: any
opcode3.arg3: any
opcode3.op: string
platform: '[]byte'
syscall0: any
syscall0NoReturn.name: string
syscall0.name: string
syscall1: any
syscall1NoReturn.arg: any
syscall1NoReturn.name: string
syscall1.arg: any
syscall1.name: string
syscall2: any
syscall2NoReturn.arg1: any
syscall2NoReturn.arg2: any
syscall2NoReturn.name: string
syscall2.arg1: any
syscall2.arg2: any
syscall2.name: string
syscall3: any
syscall3NoReturn.arg1: any
syscall3NoReturn.arg2: any
syscall3NoReturn.arg3: any
syscall3NoReturn.name: string
syscall3.arg1: any
syscall3.arg2: any
syscall3.arg3: any
syscall3.name: string
syscall4: any
syscall4NoReturn.arg1: any
syscall4NoReturn.arg2: any
syscall4NoReturn.arg3: any
syscall4NoReturn.arg4: any
syscall4NoReturn.name: string
syscall4.arg1: any
syscall4.arg2: any
syscall4.arg3: any
syscall4.arg4: any
syscall4.name: string
toBlockSR: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.BlockSR'
verify: bool
namedtypes:
ledger.Block:
base: Array
name: ledger.Block
fields:
- field: Hash
base: Hash256
- field: Version
base: Integer
- field: PrevHash
base: Hash256
- field: MerkleRoot
base: Hash256
- field: Timestamp
base: Integer
- field: Nonce
base: Integer
- field: Index
base: Integer
- field: NextConsensus
base: Hash160
- field: TransactionsLength
base: Integer
ledger.BlockSR:
base: Array
name: ledger.BlockSR
fields:
- field: Hash
base: Hash256
- field: Version
base: Integer
- field: PrevHash
base: Hash256
- field: MerkleRoot
base: Hash256
- field: Timestamp
base: Integer
- field: Nonce
base: Integer
- field: Index
base: Integer
- field: NextConsensus
base: Hash160
- field: TransactionsLength
base: Integer
- field: PrevStateRoot
base: Hash256
ledger.Transaction:
base: Array
name: ledger.Transaction
fields:
- field: Hash
base: Hash256
- field: Version
base: Integer
- field: Nonce
base: Integer
- field: Sender
base: Hash160
- field: SysFee
base: Integer
- field: NetFee
base: Integer
- field: ValidUntilBlock
base: Integer
- field: Script
base: ByteArray
ledger.TransactionSigner:
base: Array
name: ledger.TransactionSigner
fields:
- field: Account
base: Hash160
- field: Scopes
base: Integer
- field: AllowedContracts
base: Array
value:
base: Hash160
- field: AllowedGroups
base: Array
value:
base: PublicKey
- field: Rules
base: Array
value:
base: Array
name: ledger.WitnessRule
ledger.WitnessCondition:
base: Array
name: ledger.WitnessCondition
fields:
- field: Type
base: Integer
- field: Value
base: Any
ledger.WitnessRule:
base: Array
name: ledger.WitnessRule
fields:
- field: Action
base: Integer
- field: Condition
base: Array
name: ledger.WitnessCondition
types:
call.args:
base: Array
value:
base: Any
call.f:
base: InteropInterface
interface: iterator
callWithToken.args:
base: Array
value:
base: Any
callWithTokenNoRet.args:
base: Array
value:
base: Any
createMultisigAccount.pubs:
base: Array
value:
base: PublicKey
currentSigners:
base: Array
value:
base: Array
name: ledger.TransactionSigner
getBlock:
base: Array
name: ledger.Block
getCallFlags:
base: InteropInterface
interface: iterator
getNotifications:
base: Array
value:
base: Array
value:
base: Any
getScriptContainer:
base: Array
name: ledger.Transaction
getTransaction:
base: Array
name: ledger.Transaction
getTransactionFromBlock:
base: Array
name: ledger.Transaction
getTransactionSigners:
base: Array
value:
base: Array
name: ledger.TransactionSigner
loadScript.args:
base: Array
value:
base: Any
loadScript.f:
base: InteropInterface
interface: iterator
notify.args:
base: Array
value:
base: Any
toBlockSR:
base: Array
name: ledger.BlockSR

View file

@ -1,5 +1,3 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package verify contains RPC wrappers for verify contract.
package verify
@ -34,7 +32,7 @@ type Actor interface {
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
@ -122,10 +120,10 @@ func (e *HelloWorldEvent) FromStackItem(item *stackitem.Array) error {
var (
index = -1
err error
err error
)
index++
e.Args, err = func(item stackitem.Item) ([]any, error) {
e.Args, err = func (item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
@ -138,7 +136,7 @@ func (e *HelloWorldEvent) FromStackItem(item *stackitem.Array) error {
}
}
return res, nil
}(arr[index])
} (arr[index])
if err != nil {
return fmt.Errorf("field Args: %w", err)
}

View file

@ -1,64 +0,0 @@
{
"version": "1.0",
"accounts": [
{
"address": "NgHcPxgEKZQV4QBedzyASJrgiANhJqBVLw",
"key": "6PYTbVq2P3AJQwWU5SFMKLjHYco7QABtNRo4ZvLvXhyaYjwMcuZm6xKokT",
"label": "one",
"contract": {
"script": "DCECnmSGVirDOqMr57EHaYz0YMTjaHQtO9FQYu8DMTCDw6VBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
},
{
"address": "NLvHRfKAifjio2z9HiwLo9ZnpRPHUbAHgH",
"key": "6PYUjQ8TgR3cduEpG5niUNuPEWi3tYiQsnC4Jha9nGAJ6tAQGUmcrZXsLF",
"label": "two",
"contract": {
"script": "DCECgk91c1ABAX3A1uJNnxhGlp7NwUJScwJzJhrsYrXIbgNBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
},
{
"address": "NcDfG8foJx79XSihcDDrx1df7cHAoJBfXj",
"key": "6PYRkUQKWFrTovHyeQZ7X4nWoDXKohtFRKW51LiCz317pwCjmB1cVwpcxz",
"label": "three",
"contract": {
"script": "DCEC9v0ZqBg8f4jJX9WR891M0bazf0FYTNu7MEgpSHrb9CVBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
}
],
"scrypt": {
"n": 2,
"r": 1,
"p": 1
},
"extra": {
"Tokens": null
}
}

View file

@ -5,16 +5,13 @@ package txctx
import (
"fmt"
"io"
"time"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli"
)
@ -40,11 +37,6 @@ var (
Name: "force",
Usage: "Do not ask for a confirmation (and ignore errors)",
}
// AwaitFlag is a flag used to wait for the transaction to be included in a block.
AwaitFlag = cli.BoolFlag{
Name: "await",
Usage: "wait for the transaction to be included in a block",
}
)
// SignAndSend adds network and system fees to the provided transaction and
@ -56,7 +48,6 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
gas = flags.Fixed8FromContext(ctx, "gas")
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
ver = act.GetVersion()
aer *state.AppExecResult
)
tx.SystemFee += int64(sysgas)
@ -75,39 +66,14 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
}
waitTime := time.Since(promptTime)
// Compensate for confirmation waiting.
tx.ValidUntilBlock += uint32(waitTime.Milliseconds()/int64(ver.Protocol.MillisecondsPerBlock)) + 2
}
var (
resTx util.Uint256
vub uint32
)
resTx, vub, err = act.SignAndSend(tx)
if err != nil {
return cli.NewExitError(err, 1)
}
if ctx.Bool("await") {
aer, err = act.Wait(resTx, vub, err)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1)
}
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
}
_, _, err = act.SignAndSend(tx)
}
if err != nil {
return cli.NewExitError(err, 1)
}
DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
return nil
}
// DumpTransactionInfo prints transaction info to the given writer.
func DumpTransactionInfo(w io.Writer, h util.Uint256, res *state.AppExecResult) {
fmt.Fprintln(w, h.StringLE())
if res != nil {
fmt.Fprintf(w, "OnChain:\t%t\n", res != nil)
fmt.Fprintf(w, "VMState:\t%s\n", res.VMState.String())
if res.FaultException != "" {
fmt.Fprintf(w, "FaultException:\t%s\n", res.FaultException)
}
}
}

View file

@ -1,103 +0,0 @@
package util
import (
"errors"
"fmt"
"strings"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/urfave/cli"
)
func cancelTx(ctx *cli.Context) error {
args := ctx.Args()
if len(args) == 0 {
return cli.NewExitError("transaction hash is missing", 1)
} else if len(args) > 1 {
return cli.NewExitError("only one transaction hash is accepted", 1)
}
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
if err != nil {
return cli.NewExitError(fmt.Sprintf("invalid tx hash: %s", args[0]), 1)
}
gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel()
acc, w, err := options.GetAccFromContext(ctx)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1)
}
defer w.Close()
signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
c, a, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
if exitErr != nil {
return exitErr
}
mainTx, _ := c.GetRawTransactionVerbose(txHash)
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
}
if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) {
return cli.NewExitError(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1)
}
resHash, resVub, err := a.SendTunedRun([]byte{byte(opcode.RET)}, []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: txHash}}}, func(r *result.Invoke, t *transaction.Transaction) error {
err := actor.DefaultCheckerModifier(r, t)
if err != nil {
return err
}
if mainTx != nil && t.NetworkFee < mainTx.NetworkFee+1 {
t.NetworkFee = mainTx.NetworkFee + 1
}
t.NetworkFee += int64(flags.Fixed8FromContext(ctx, "gas"))
if mainTx != nil {
t.ValidUntilBlock = mainTx.ValidUntilBlock
}
return nil
})
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to send conflicting transaction: %w", err), 1)
}
var res *state.AppExecResult
if ctx.Bool("await") {
res, err = a.WaitAny(gctx, resVub, txHash, resHash)
if err != nil {
if errors.Is(err, waiter.ErrTxNotAccepted) {
if mainTx == nil {
return cli.NewExitError(fmt.Errorf("neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of conlicting transaction). Main transaction is unknown to the provided RPC node, thus still has chances to be accepted, you may try cancellation again", resVub), 1)
}
fmt.Fprintf(ctx.App.Writer, "Neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of both target and conflicting transactions). Main transaction is not valid anymore, cancellation is successful\n", resVub)
return nil
}
return cli.NewExitError(fmt.Errorf("failed to await target/ conflicting transaction %s/ %s: %w", txHash.StringLE(), resHash.StringLE(), err), 1)
}
if txHash.Equals(res.Container) {
tx, err := c.GetRawTransactionVerbose(txHash)
if err != nil {
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted", txHash), 1)
}
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, tx.Blockhash.StringLE()), 1)
}
fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted")
}
txctx.DumpTransactionInfo(ctx.App.Writer, resHash, res)
return nil
}

View file

@ -6,9 +6,7 @@ import (
"fmt"
"os"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/urfave/cli"
@ -17,16 +15,6 @@ import (
// NewCommands returns util commands for neo-go CLI.
func NewCommands() []cli.Command {
txDumpFlags := append([]cli.Flag{}, options.RPC...)
txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
txCancelFlags := append([]cli.Flag{
flags.AddressFlag{
Name: "address, a",
Usage: "address to use as conflicting transaction signee (and gas source)",
},
txctx.GasFlag,
txctx.AwaitFlag,
}, options.RPC...)
txCancelFlags = append(txCancelFlags, options.Wallet...)
return []cli.Command{
{
Name: "util",
@ -44,35 +32,14 @@ func NewCommands() []cli.Command {
{
Name: "sendtx",
Usage: "Send complete transaction stored in a context file",
UsageText: "sendtx [-r <endpoint>] <file.in> [--await]",
UsageText: "sendtx [-r <endpoint>] <file.in>",
Description: `Sends the transaction from the given context file to the given RPC node if it's
completely signed and ready. This command expects a ContractParametersContext
JSON file for input, it can't handle binary (or hex- or base64-encoded)
transactions. If the --await flag is included, the command waits for the
transaction to be included in a block before exiting.
transactions.
`,
Action: sendTx,
Flags: txSendFlags,
},
{
Name: "canceltx",
Usage: "Cancel transaction by sending conflicting transaction",
UsageText: "canceltx <txid> -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>] [--await]",
Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more
prioritized conflicting transaction to the specified RPC node. The input for this command should
be the transaction hash. If another account is not specified, the conflicting transaction is
automatically generated and signed by the default account in the wallet. If the target transaction
is in the memory pool of the provided RPC node, the NetworkFee value of the conflicting transaction
is set to the target transaction's NetworkFee value plus one (if it's sufficient for the
conflicting transaction itself), the ValidUntilBlock value of the conflicting transaction is set to the
target transaction's ValidUntilBlock value. If the target transaction is not in the memory pool, standard
NetworkFee calculations are performed based on the calculatenetworkfee RPC request. If the --gas
flag is included, the specified value is added to the resulting conflicting transaction network fee
in both scenarios. When the --await flag is included, the command waits for one of the conflicting
or target transactions to be included in a block.
`,
Action: cancelTx,
Flags: txCancelFlags,
Flags: txDumpFlags,
},
{
Name: "txdump",
@ -80,12 +47,6 @@ func NewCommands() []cli.Command {
UsageText: "txdump [-r <endpoint>] <file.in>",
Action: txDump,
Flags: txDumpFlags,
Description: `Dumps the transaction from the given parameter context file to
the output. This command expects a ContractParametersContext JSON file for input, it can't handle
binary (or hex- or base64-encoded) transactions. If --rpc-endpoint flag is specified the result
of the given script after running it true the VM will be printed. Otherwise only transaction will
be printed.
`,
},
{
Name: "ops",

View file

@ -29,10 +29,7 @@ func txDump(ctx *cli.Context) error {
return cli.NewExitError("verifiable item is not a transaction", 1)
}
err = query.DumpApplicationLog(ctx, nil, tx, nil, true)
if err != nil {
return cli.NewExitError(err, 1)
}
query.DumpApplicationLog(ctx, nil, tx, nil, true)
if ctx.String(options.RPCEndpointFlag) != "" {
gctx, cancel := options.GetTimeoutContext(ctx)

View file

@ -5,9 +5,6 @@ import (
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
"github.com/urfave/cli"
)
@ -40,14 +37,6 @@ func sendTx(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
}
var aer *state.AppExecResult
if ctx.Bool("await") {
version, err := c.GetVersion()
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
}
}
txctx.DumpTransactionInfo(ctx.App.Writer, res, aer)
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
}

View file

@ -1,18 +1,12 @@
package util_test
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/stretchr/testify/require"
)
@ -69,124 +63,3 @@ func TestUtilOps(t *testing.T) {
e.Run(t, "neo-go", "util", "ops", "--hex", "--in", tmp) // hex from file
check(t)
}
func TestUtilCancelTx(t *testing.T) {
e := testcli.NewExecutorSuspended(t)
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
require.NoError(t, err)
transferArgs := []string{
"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--to", w.Accounts[0].Address,
"--token", "NEO",
"--from", testcli.ValidatorAddr,
"--force",
}
args := []string{"neo-go", "util", "canceltx",
"-r", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", testcli.ValidatorAddr}
e.In.WriteString("one\r")
e.Run(t, append(transferArgs, "--amount", "1")...)
line := e.GetNextLine(t)
txHash, err := util.Uint256DecodeStringLE(line)
require.NoError(t, err)
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
require.True(t, ok)
t.Run("invalid", func(t *testing.T) {
t.Run("missing tx argument", func(t *testing.T) {
e.RunWithError(t, args...)
})
t.Run("excessive arguments", func(t *testing.T) {
e.RunWithError(t, append(args, txHash.StringLE(), txHash.StringLE())...)
})
t.Run("invalid hash", func(t *testing.T) {
e.RunWithError(t, append(args, "notahash")...)
})
t.Run("not signed by main signer", func(t *testing.T) {
e.In.WriteString("one\r")
e.RunWithError(t, "neo-go", "util", "canceltx",
"-r", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", testcli.MultisigAddr, txHash.StringLE())
})
t.Run("wrong rpc endpoint", func(t *testing.T) {
e.In.WriteString("one\r")
e.RunWithError(t, "neo-go", "util", "canceltx",
"-r", "http://localhost:20331",
"--wallet", testcli.ValidatorWallet, txHash.StringLE())
})
})
e.In.WriteString("one\r")
e.Run(t, append(args, txHash.StringLE())...)
resHash, err := util.Uint256DecodeStringLE(e.GetNextLine(t))
require.NoError(t, err)
_, _, err = e.Chain.GetTransaction(resHash)
require.NoError(t, err)
e.CheckEOF(t)
go e.Chain.Run()
require.Eventually(t, func() bool {
_, aerErr := e.Chain.GetAppExecResults(resHash, trigger.Application)
return aerErr == nil
}, time.Second*2, time.Millisecond*50)
}
func TestAwaitUtilCancelTx(t *testing.T) {
e := testcli.NewExecutor(t, true)
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
require.NoError(t, err)
transferArgs := []string{
"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--to", w.Accounts[0].Address,
"--token", "NEO",
"--from", testcli.ValidatorAddr,
"--force",
}
args := []string{"neo-go", "util", "canceltx",
"-r", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", testcli.ValidatorAddr,
"--await"}
e.In.WriteString("one\r")
e.Run(t, append(transferArgs, "--amount", "1")...)
line := e.GetNextLine(t)
txHash, err := util.Uint256DecodeStringLE(line)
require.NoError(t, err)
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
require.True(t, ok)
// Allow both cases: either target or conflicting tx acceptance.
e.In.WriteString("one\r")
err = e.RunUnchecked(t, append(args, txHash.StringLE())...)
switch {
case err == nil:
response := e.GetNextLine(t)
require.Equal(t, "Conflicting transaction accepted", response)
resHash, _ := e.CheckAwaitableTxPersisted(t)
require.NotEqual(t, resHash, txHash)
case strings.Contains(err.Error(), fmt.Sprintf("target transaction %s is accepted", txHash)) ||
strings.Contains(err.Error(), fmt.Sprintf("failed to send conflicting transaction: Invalid transaction attribute (-507) - invalid attribute: conflicting transaction %s is already on chain", txHash)):
tx, _ := e.GetTransaction(t, txHash)
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, 1, len(aer))
require.Equal(t, vmstate.Halt, aer[0].VMState)
default:
t.Fatal(fmt.Errorf("unexpected error: %w", err))
}
}

View file

@ -616,7 +616,7 @@ func getInstructionParameter(c *cli.Context) (int, error) {
}
n, err := strconv.Atoi(args[0])
if err != nil {
return 0, fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return 0, fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
return n, nil
}
@ -736,7 +736,7 @@ func handleLoadNEF(c *cli.Context) error {
if signersStartOffset != 0 && len(args) > signersStartOffset {
signers, err = cmdargs.ParseSigners(c.Args()[signersStartOffset:])
if err != nil {
return fmt.Errorf("%w: failed to parse signers: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: failed to parse signers: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
}
err = prepareVM(c, createFakeTransaction(nef.Script, signers))
@ -767,7 +767,7 @@ func handleLoadBase64(c *cli.Context) error {
}
b, err := base64.StdEncoding.DecodeString(args[0])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
var signers []transaction.Signer
if len(args) > 1 {
@ -779,7 +779,7 @@ func handleLoadBase64(c *cli.Context) error {
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
}
err = prepareVM(c, createFakeTransaction(b, signers))
@ -807,7 +807,7 @@ func handleLoadHex(c *cli.Context) error {
}
b, err := hex.DecodeString(args[0])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
var signers []transaction.Signer
if len(args) > 1 {
@ -819,7 +819,7 @@ func handleLoadHex(c *cli.Context) error {
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
}
err = prepareVM(c, createFakeTransaction(b, signers))
@ -859,7 +859,7 @@ func handleLoadGo(c *cli.Context) error {
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
}
@ -962,7 +962,7 @@ func handleLoadDeployed(c *cli.Context) error {
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
}
err = prepareVM(c, createFakeTransaction(cs.NEF.Script, signers)) // prepare VM one more time for proper IC initialization.
@ -1074,7 +1074,7 @@ func handleRun(c *cli.Context) error {
_, scParams, err := cmdargs.ParseParams(args[1:], true)
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
params = make([]stackitem.Item, len(scParams))
for i := range scParams {
@ -1105,7 +1105,7 @@ func handleRun(c *cli.Context) error {
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
ic.ReuseVM(v)
v.GasLimit = gasLimit
v.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
v.LoadNEFMethod(&cs.NEF, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
for _, bp := range breaks {
v.AddBreakPoint(bp)
}
@ -1185,7 +1185,7 @@ func handleStep(c *cli.Context) error {
if len(args) > 0 {
n, err = strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
}
}
v.AddBreakPointRel(n)
@ -1436,57 +1436,58 @@ func Parse(args []string) (string, error) {
return "", ErrMissingParameter
}
arg := args[0]
var buf []byte
buf := bytes.NewBuffer(nil)
if val, err := strconv.ParseInt(arg, 10, 64); err == nil {
bs := bigint.ToBytes(big.NewInt(val))
buf = fmt.Appendf(buf, "Integer to Hex\t%s\n", hex.EncodeToString(bs))
buf = fmt.Appendf(buf, "Integer to Base64\t%s\n", base64.StdEncoding.EncodeToString(bs))
buf.WriteString(fmt.Sprintf("Integer to Hex\t%s\n", hex.EncodeToString(bs)))
buf.WriteString(fmt.Sprintf("Integer to Base64\t%s\n", base64.StdEncoding.EncodeToString(bs)))
}
noX := strings.TrimPrefix(arg, "0x")
if rawStr, err := hex.DecodeString(noX); err == nil {
if val, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
buf = fmt.Appendf(buf, "BE ScriptHash to Address\t%s\n", address.Uint160ToString(val))
buf = fmt.Appendf(buf, "LE ScriptHash to Address\t%s\n", address.Uint160ToString(val.Reverse()))
buf.WriteString(fmt.Sprintf("BE ScriptHash to Address\t%s\n", address.Uint160ToString(val)))
buf.WriteString(fmt.Sprintf("LE ScriptHash to Address\t%s\n", address.Uint160ToString(val.Reverse())))
}
if pub, err := keys.NewPublicKeyFromBytes(rawStr, elliptic.P256()); err == nil {
sh := pub.GetScriptHash()
buf = fmt.Appendf(buf, "Public key to BE ScriptHash\t%s\n", sh)
buf = fmt.Appendf(buf, "Public key to LE ScriptHash\t%s\n", sh.Reverse())
buf = fmt.Appendf(buf, "Public key to Address\t%s\n", address.Uint160ToString(sh))
buf.WriteString(fmt.Sprintf("Public key to BE ScriptHash\t%s\n", sh))
buf.WriteString(fmt.Sprintf("Public key to LE ScriptHash\t%s\n", sh.Reverse()))
buf.WriteString(fmt.Sprintf("Public key to Address\t%s\n", address.Uint160ToString(sh)))
}
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)))
buf.WriteString(fmt.Sprintf("Hex to String\t%s\n", fmt.Sprintf("%q", string(rawStr))))
buf.WriteString(fmt.Sprintf("Hex to Integer\t%s\n", bigint.FromBytes(rawStr)))
buf.WriteString(fmt.Sprintf("Swap Endianness\t%s\n", hex.EncodeToString(slice.CopyReverse(rawStr))))
}
if addr, err := address.StringToUint160(arg); err == nil {
buf = fmt.Appendf(buf, "Address to BE ScriptHash\t%s\n", addr)
buf = fmt.Appendf(buf, "Address to LE ScriptHash\t%s\n", addr.Reverse())
buf = fmt.Appendf(buf, "Address to Base64 (BE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesBE()))
buf = fmt.Appendf(buf, "Address to Base64 (LE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesLE()))
buf.WriteString(fmt.Sprintf("Address to BE ScriptHash\t%s\n", addr))
buf.WriteString(fmt.Sprintf("Address to LE ScriptHash\t%s\n", addr.Reverse()))
buf.WriteString(fmt.Sprintf("Address to Base64 (BE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesBE())))
buf.WriteString(fmt.Sprintf("Address to Base64 (LE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesLE())))
}
if rawStr, err := base64.StdEncoding.DecodeString(arg); err == nil {
buf = fmt.Appendf(buf, "Base64 to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))
buf = fmt.Appendf(buf, "Base64 to BigInteger\t%s\n", bigint.FromBytes(rawStr))
buf.WriteString(fmt.Sprintf("Base64 to String\t%s\n", fmt.Sprintf("%q", string(rawStr))))
buf.WriteString(fmt.Sprintf("Base64 to BigInteger\t%s\n", bigint.FromBytes(rawStr)))
if u, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
buf = fmt.Appendf(buf, "Base64 to BE ScriptHash\t%s\n", u.StringBE())
buf = fmt.Appendf(buf, "Base64 to LE ScriptHash\t%s\n", u.StringLE())
buf = fmt.Appendf(buf, "Base64 to Address (BE)\t%s\n", address.Uint160ToString(u))
buf = fmt.Appendf(buf, "Base64 to Address (LE)\t%s\n", address.Uint160ToString(u.Reverse()))
buf.WriteString(fmt.Sprintf("Base64 to BE ScriptHash\t%s\n", u.StringBE()))
buf.WriteString(fmt.Sprintf("Base64 to LE ScriptHash\t%s\n", u.StringLE()))
buf.WriteString(fmt.Sprintf("Base64 to Address (BE)\t%s\n", address.Uint160ToString(u)))
buf.WriteString(fmt.Sprintf("Base64 to Address (LE)\t%s\n", address.Uint160ToString(u.Reverse())))
}
}
buf = fmt.Appendf(buf, "String to Hex\t%s\n", hex.EncodeToString([]byte(arg)))
buf = fmt.Appendf(buf, "String to Base64\t%s\n", base64.StdEncoding.EncodeToString([]byte(arg)))
buf.WriteString(fmt.Sprintf("String to Hex\t%s\n", hex.EncodeToString([]byte(arg))))
buf.WriteString(fmt.Sprintf("String to Base64\t%s\n", base64.StdEncoding.EncodeToString([]byte(arg))))
res := bytes.NewBuffer(nil)
w := tabwriter.NewWriter(res, 0, 4, 4, '\t', 0)
if _, err := w.Write(buf); err != nil {
out := buf.Bytes()
buf = bytes.NewBuffer(nil)
w := tabwriter.NewWriter(buf, 0, 4, 4, '\t', 0)
if _, err := w.Write(out); err != nil {
return "", err
}
if err := w.Flush(); err != nil {
return "", err
}
return res.String(), nil
return buf.String(), nil
}
const logo = `

View file

@ -14,7 +14,6 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
@ -23,7 +22,6 @@ import (
"github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/internal/basicchain"
"github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
@ -43,11 +41,9 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
)
// Keep contract NEFs consistent between runs.
const _ = versionutil.TestVersion
type readCloser struct {
sync.Mutex
bytes.Buffer
@ -93,11 +89,10 @@ func newTestVMCLIWithLogoAndCustomConfig(t *testing.T, printLogo bool, cfg *conf
}
var c config.Config
if cfg == nil {
configPath := filepath.Join("..", "..", "config", "protocol.unit_testnet.single.yml")
configPath := "../../config/protocol.unit_testnet.single.yml"
var err error
c, err = config.LoadFile(configPath, filepath.Join("..", "..", "config"))
c, err = config.LoadFile(configPath)
require.NoError(t, err, "could not load chain config")
require.Equal(t, filepath.Join("..", "..", "testdata", "wallet1_solo.json"), c.ApplicationConfiguration.Consensus.UnlockWallet.Path)
c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
} else {
c = *cfg
@ -134,10 +129,6 @@ func newTestVMClIWithState(t *testing.T) *executor {
}
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
require.NoError(t, err)
// Save config for future usage.
protoCfg := bc.GetConfig()
go bc.Run()
e := neotest.NewExecutor(t, bc, validators, committee)
basicchain.InitSimple(t, "../../", e)
@ -149,9 +140,7 @@ func newTestVMClIWithState(t *testing.T) *executor {
require.NoError(t, err)
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
cfg.ProtocolConfiguration.StateRootInHeader = protoCfg.StateRootInHeader
cfg.ProtocolConfiguration.P2PStateExchangeExtensions = protoCfg.P2PStateExchangeExtensions
cfg.ProtocolConfiguration.Hardforks = protoCfg.Hardforks
cfg.ProtocolConfiguration.StateRootInHeader = true
return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg)
}
@ -353,7 +342,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.18`)
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
return filename
}
@ -362,6 +351,8 @@ go 1.20`)
// via `loadnef` command. It returns the name of manifest and NEF files ready to be used in CLI
// commands.
func prepareLoadnefSrc(t *testing.T, tmpDir, src string) (string, string) {
config.Version = "0.92.0-test"
nefFile, di, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
require.NoError(t, err)
filename := filepath.Join(tmpDir, "vmtestcontract.nef")
@ -687,7 +678,6 @@ func TestLoad_RunWithCALLT(t *testing.T) {
e.runProg(t,
"loaddeployed "+cH.StringLE()+" -- NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB:Global", // the contract's owner got from the contract's code.
"run destroy",
"exit",
)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t) // Nothing on stack, successful execution.
@ -1104,7 +1094,7 @@ func TestRunWithHistoricState(t *testing.T) {
e.checkNextLine(t, "READY: loaded 36 instructions")
e.checkStack(t, []byte{1})
e.checkNextLine(t, "READY: loaded 36 instructions")
e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): System.Contract.Call failed: called contract 0f825b050eb8ce9eaa82993e90615025ab798016 not found: key not found\n")
e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): System.Contract.Call failed: called contract 73a23e915b66ae406866787f4a6c1c517dc981e2 not found: key not found\n")
}
func TestEvents(t *testing.T) {

View file

@ -13,7 +13,7 @@ import (
// NewCommands returns 'vm' command.
func NewCommands() []cli.Command {
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags := []cli.Flag{options.Config, options.ConfigFile}
cfgFlags = append(cfgFlags, options.Network...)
return []cli.Command{{
Name: "vm",

View file

@ -1,6 +1,7 @@
package wallet_test
import (
"encoding/hex"
"math/big"
"strconv"
"testing"
@ -17,7 +18,7 @@ func TestRegisterCandidate(t *testing.T) {
validatorAddress := testcli.ValidatorPriv.Address()
validatorPublic := testcli.ValidatorPriv.PublicKey()
validatorHex := validatorPublic.StringCompressed()
validatorHex := hex.EncodeToString(validatorPublic.Bytes())
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
@ -158,61 +159,4 @@ func TestRegisterCandidate(t *testing.T) {
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
t.Run("VoteUnvote await", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "register",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--force", "--await")
e.CheckAwaitableTxPersisted(t)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "vote",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--candidate", validatorHex,
"--force",
"--await")
e.CheckAwaitableTxPersisted(t)
b, _ := e.Chain.GetGoverningTokenBalance(testcli.ValidatorPriv.GetScriptHash())
// unvote
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "vote",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--force", "--await")
_, index := e.CheckAwaitableTxPersisted(t)
vs, err = e.Chain.GetEnrollments()
require.Equal(t, 1, len(vs))
require.Equal(t, validatorPublic, vs[0].Key)
require.Equal(t, big.NewInt(0), vs[0].Votes)
// check state
e.Run(t, "neo-go", "query", "voter",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
validatorAddress)
e.CheckNextLine(t, "^\\s*Voted:\\s+"+"null") // no vote.
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
e.CheckNextLine(t, "^\\s*Block\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
e.CheckEOF(t)
})
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--force",
"--await")
e.CheckAwaitableTxPersisted(t)
vs, err = e.Chain.GetEnrollments()
require.Equal(t, 0, len(vs))
}

View file

@ -8,7 +8,6 @@ import (
"errors"
"os"
"github.com/nspcc-dev/neo-go/cli/options"
"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"
@ -47,7 +46,7 @@ func newWalletV2FromFile(path string, configPath string) (*walletV2, *string, er
}
var pass *string
if len(configPath) != 0 {
cfg, err := options.ReadWalletConfig(configPath)
cfg, err := ReadWalletConfig(configPath)
if err != nil {
return nil, nil, err
}

View file

@ -1,12 +1,12 @@
package wallet
import (
"bytes"
"crypto/elliptic"
"encoding/hex"
"testing"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util/slice"
"github.com/stretchr/testify/require"
)
@ -36,27 +36,27 @@ func TestParseMultisigContract(t *testing.T) {
testParseMultisigContract(t, s, 1, pub)
})
t.Run("bad, no check multisig", func(t *testing.T) {
sBad := bytes.Clone(s)
sBad := slice.Copy(s)
sBad[len(sBad)-1] ^= 0xFF
testParseMultisigContract(t, sBad, 0)
})
t.Run("bad, invalid number of keys", func(t *testing.T) {
sBad := bytes.Clone(s)
sBad := slice.Copy(s)
sBad[len(sBad)-2] = opPush1 + 1
testParseMultisigContract(t, sBad, 0)
})
t.Run("bad, invalid first instruction", func(t *testing.T) {
sBad := bytes.Clone(s)
sBad := slice.Copy(s)
sBad[0] = 0xFF
testParseMultisigContract(t, sBad, 0)
})
t.Run("bad, invalid public key", func(t *testing.T) {
sBad := bytes.Clone(s)
sBad := slice.Copy(s)
sBad[2] = 0xFF
testParseMultisigContract(t, sBad, 0)
})
t.Run("bad, many sigs", func(t *testing.T) {
sBad := bytes.Clone(s)
sBad := slice.Copy(s)
sBad[0] = opPush1 + 1
testParseMultisigContract(t, sBad, 0)
})

View file

@ -8,10 +8,7 @@ import (
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
"github.com/urfave/cli"
)
@ -20,11 +17,15 @@ func signStoredTransaction(ctx *cli.Context) error {
out = ctx.String("out")
rpcNode = ctx.String(options.RPCEndpointFlag)
addrFlag = ctx.Generic("address").(*flags.Address)
aer *state.AppExecResult
)
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := readWallet(ctx)
if err != nil {
return cli.NewExitError(err, 1)
}
defer wall.Close()
pc, err := paramcontext.Read(ctx.String("in"))
if err != nil {
@ -34,7 +35,9 @@ func signStoredTransaction(ctx *cli.Context) error {
if !addrFlag.IsSet {
return cli.NewExitError("address was not provided", 1)
}
acc, _, err := options.GetAccFromContext(ctx)
var ch = addrFlag.Uint160()
acc, err := getDecryptedAccount(wall, ch, pass)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -44,13 +47,20 @@ func signStoredTransaction(ctx *cli.Context) error {
return cli.NewExitError("verifiable item is not a transaction", 1)
}
if !tx.HasSigner(acc.ScriptHash()) {
signerFound := false
for i := range tx.Signers {
if tx.Signers[i].Account == ch {
signerFound = true
break
}
}
if !signerFound {
return cli.NewExitError("tx signers don't contain provided account", 1)
}
if acc.CanSign() {
sign := acc.SignHashable(pc.Network, pc.Verifiable)
if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
if err := pc.AddSignature(ch, acc.Contract, acc.PublicKey(), sign); err != nil {
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
}
} else if rpcNode == "" {
@ -88,15 +98,10 @@ func signStoredTransaction(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
}
if ctx.Bool("await") {
version, err := c.GetVersion()
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
}
}
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
}
txctx.DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
return nil
}

View file

@ -1,6 +1,7 @@
package wallet_test
import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
@ -44,9 +45,9 @@ func TestSignMultisigTx(t *testing.T) {
"--wallet", w,
"--wif", wif,
"--min", "2",
pubs[0].StringCompressed(),
pubs[1].StringCompressed(),
pubs[2].StringCompressed())
hex.EncodeToString(pubs[0].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()))
}
addAccount(wallet1Path, privs[0].WIF())
addAccount(wallet2Path, privs[1].WIF())

View file

@ -101,7 +101,7 @@ func newNEP11Commands() []cli.Command {
{
Name: "transfer",
Usage: "transfer NEP-11 tokens",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP11,
Flags: transferFlags,
Description: `Transfers specified NEP-11 token with optional cosigners list attached to
@ -110,8 +110,7 @@ func newNEP11Commands() []cli.Command {
'contract testinvokefunction' documentation for the details
about cosigners syntax. If no cosigners are given then the
sender with CalledByEntry scope will be used as the only
signer. If --await flag is set then the command will wait
for the transaction to be included in a block.
signer.
`,
},
{

View file

@ -30,14 +30,6 @@ import (
"github.com/urfave/cli"
)
// transferTarget represents target address, token amount and data for transfer.
type transferTarget struct {
Token util.Uint160
Address util.Uint160
Amount int64
Data any
}
var (
tokenFlag = cli.StringFlag{
Name: "token",
@ -70,7 +62,6 @@ var (
txctx.GasFlag,
txctx.SysGasFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
cli.StringFlag{
Name: "amount",
Usage: "Amount of asset to send",
@ -84,7 +75,6 @@ var (
txctx.GasFlag,
txctx.SysGasFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
}, options.RPC...)
)
@ -149,22 +139,20 @@ func newNEP17Commands() []cli.Command {
{
Name: "transfer",
Usage: "transfer NEP-17 tokens",
UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP17,
Flags: transferFlags,
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
list attached to the transfer. See 'contract testinvokefunction' documentation
for the details about 'data' parameter and cosigners syntax. If no 'data' is
given then default nil value will be used. If no cosigners are given then the
sender with CalledByEntry scope will be used as the only signer. When --await
flag is used, the command waits for the transaction to be included in a block
before exiting.
sender with CalledByEntry scope will be used as the only signer.
`,
},
{
Name: "multitransfer",
Usage: "transfer NEP-17 tokens to multiple recipients",
UsageText: `multitransfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr>` +
UsageText: `multitransfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr>` +
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
Action: multiTransferNEP17,
Flags: multiTransferFlags,
@ -526,7 +514,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(err, 1)
}
acc, err := options.GetUnlockedAccount(wall, from, pass)
acc, err := getDecryptedAccount(wall, from, pass)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -534,36 +522,25 @@ func multiTransferNEP17(ctx *cli.Context) error {
gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel()
c, err := options.GetRPCClient(gctx, ctx)
if err != nil {
return cli.NewExitError(err, 1)
}
if ctx.NArg() == 0 {
return cli.NewExitError("empty recipients list", 1)
}
var (
recipients []transferTarget
cosignersSepPos = ctx.NArg() // `--` position.
recipients []rpcclient.TransferTarget
cosignersOffset = ctx.NArg()
)
cache := make(map[string]*wallet.Token)
for i := 0; i < ctx.NArg(); i++ {
arg := ctx.Args().Get(i)
if arg == cmdargs.CosignersSeparator {
cosignersSepPos = i
cosignersOffset = i + 1
break
}
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersSepPos+1)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
if exitErr != nil {
return exitErr
}
cache := make(map[string]*wallet.Token)
for i := 0; i < cosignersSepPos; i++ {
arg := ctx.Args().Get(i)
ss := strings.SplitN(arg, ":", 3)
if len(ss) != 3 {
return cli.NewExitError("send format must be '<token>:<addr>:<amount>", 1)
@ -587,7 +564,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
}
recipients = append(recipients, transferTarget{
recipients = append(recipients, rpcclient.TransferTarget{
Token: token.Hash,
Address: addr,
Amount: amount.Int64(),
@ -595,6 +572,19 @@ func multiTransferNEP17(ctx *cli.Context) error {
})
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
act, err := actor.New(c, signersAccounts)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
}
tx, err := makeMultiTransferNEP17(act, recipients)
if err != nil {
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
@ -620,7 +610,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
if err != nil {
return cli.NewExitError(err, 1)
}
acc, err := options.GetUnlockedAccount(wall, from, pass)
acc, err := getDecryptedAccount(wall, from, pass)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -628,22 +618,9 @@ func transferNEP(ctx *cli.Context, standard string) error {
gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel()
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
if extErr != nil {
return extErr
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
c, err := options.GetRPCClient(gctx, ctx)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
if exitErr != nil {
return exitErr
return cli.NewExitError(err, 1)
}
toFlag := ctx.Generic("to").(*flags.Address)
@ -659,6 +636,24 @@ func transferNEP(ctx *cli.Context, standard string) error {
}
}
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
if extErr != nil {
return extErr
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
act, err := actor.New(c, signersAccounts)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
}
amountArg := ctx.String("amount")
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
// It's OK for NEP-11 transfer to not have amount set.
@ -695,7 +690,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
return txctx.SignAndSend(ctx, act, acc, tx)
}
func makeMultiTransferNEP17(act *actor.Actor, recipients []transferTarget) (*transaction.Transaction, error) {
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) {
scr := smartcontract.NewBuilder()
for i := range recipients {
scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(),

View file

@ -5,10 +5,13 @@ import (
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"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/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
@ -20,7 +23,7 @@ func newValidatorCommands() []cli.Command {
{
Name: "register",
Usage: "register as a new candidate",
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
Action: handleRegister,
Flags: append([]cli.Flag{
walletPathFlag,
@ -29,7 +32,6 @@ func newValidatorCommands() []cli.Command {
txctx.SysGasFlag,
txctx.OutFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{
Name: "address, a",
Usage: "Address to register",
@ -39,7 +41,7 @@ func newValidatorCommands() []cli.Command {
{
Name: "unregister",
Usage: "unregister self as a candidate",
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
Action: handleUnregister,
Flags: append([]cli.Flag{
walletPathFlag,
@ -48,7 +50,6 @@ func newValidatorCommands() []cli.Command {
txctx.SysGasFlag,
txctx.OutFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{
Name: "address, a",
Usage: "Address to unregister",
@ -58,10 +59,9 @@ func newValidatorCommands() []cli.Command {
{
Name: "vote",
Usage: "vote for a validator",
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force] [--await]",
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force]",
Description: `Votes for a validator by calling "vote" method of a NEO native
contract. Do not provide candidate argument to perform unvoting. If --await flag is
included, the command waits for the transaction to be included in a block before exiting.
contract. Do not provide candidate argument to perform unvoting.
`,
Action: handleVote,
Flags: append([]cli.Flag{
@ -71,7 +71,6 @@ func newValidatorCommands() []cli.Command {
txctx.SysGasFlag,
txctx.OutFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{
Name: "address, a",
Usage: "Address to vote from",
@ -112,7 +111,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
return cli.NewExitError("address was not provided", 1)
}
addr := addrFlag.Uint160()
acc, err := options.GetUnlockedAccount(wall, addr, pass)
acc, err := getDecryptedAccount(wall, addr, pass)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -120,13 +119,13 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel()
signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, transaction.CalledByEntry)
c, err := options.GetRPCClient(gctx, ctx)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
return cli.NewExitError(err, 1)
}
_, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
if exitErr != nil {
return exitErr
act, err := actor.NewSimple(c, acc)
if err != nil {
return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1)
}
contract := neo.New(act)
@ -154,3 +153,32 @@ func handleVote(ctx *cli.Context) error {
return contract.VoteUnsigned(addr, pub)
})
}
// getDecryptedAccount tries to get and unlock the specified account if it has a
// key inside (otherwise it's returned as is, without an ability to sign). If
// password is nil, it will be requested via terminal.
func getDecryptedAccount(wall *wallet.Wallet, addr util.Uint160, password *string) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr))
}
// No private key available, nothing to decrypt, but it's still a useful account for many purposes.
if acc.EncryptedWIF == "" {
return acc, nil
}
if password == nil {
pass, err := input.ReadPassword(EnterPasswordPrompt)
if err != nil {
fmt.Println("Error reading password", err)
return nil, err
}
password = &pass
}
err := acc.Decrypt(*password, wall.Scrypt)
if err != nil {
return nil, err
}
return acc, nil
}

View file

@ -15,6 +15,7 @@ import (
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -25,6 +26,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli"
"gopkg.in/yaml.v3"
)
const (
@ -86,7 +88,6 @@ func NewCommands() []cli.Command {
txctx.SysGasFlag,
txctx.OutFlag,
txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{
Name: "address, a",
Usage: "Address to claim GAS for",
@ -97,7 +98,6 @@ func NewCommands() []cli.Command {
walletPathFlag,
walletConfigFlag,
txctx.OutFlag,
txctx.AwaitFlag,
inFlag,
flags.AddressFlag{
Name: "address, a",
@ -112,7 +112,7 @@ func NewCommands() []cli.Command {
{
Name: "claim",
Usage: "claim GAS",
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force] [--await]",
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force]",
Action: claimGas,
Flags: claimFlags,
},
@ -236,15 +236,8 @@ func NewCommands() []cli.Command {
{
Name: "import-multisig",
Usage: "import multisig contract",
UsageText: "import-multisig -w wallet [--wallet-config path] [--wif <wif>] [--name <account_name>] --min <m>" +
UsageText: "import-multisig -w wallet [--wallet-config path] --wif <wif> [--name <account_name>] --min <n>" +
" [<pubkey1> [<pubkey2> [...]]]",
Description: `Imports a standard multisignature contract with "m out of n" signatures required where "m" is
specified by --min flag and "n" is the length of provided set of public keys. If
--wif flag is provided, it's used to create an account with the given name (or
without a name if --name flag is not provided). Otherwise, the command tries to
find an account with one of the given public keys and convert it to multisig. If
no suitable account is found and no --wif flag is specified, an error is returned.
`,
Action: importMultisig,
Flags: []cli.Flag{
walletPathFlag,
@ -297,15 +290,13 @@ func NewCommands() []cli.Command {
{
Name: "sign",
Usage: "cosign transaction with multisig/contract/additional account",
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>] [--await]",
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>]",
Description: `Signs the given (in file.in) context (which must be a transaction
signing context) for the given address using the given wallet. This command can
output the resulting JSON (with additional signature added) right to the console
(if no file.out and no RPC endpoint specified) or into a file (which can be the
same as input one). If an RPC endpoint is given it'll also try to construct a
complete transaction and send it via RPC (printing its hash if everything is OK).
If the --await (with a given RPC endpoint) flag is included, the command waits
for the transaction to be included in a block before exiting.
`,
Action: signStoredTransaction,
Flags: signFlags,
@ -528,12 +519,6 @@ loop:
}
func importMultisig(ctx *cli.Context) error {
var (
label *string
acc *wallet.Account
accPub *keys.PublicKey
)
wall, pass, err := openWallet(ctx, true)
if err != nil {
return cli.NewExitError(err, 1)
@ -555,45 +540,12 @@ func importMultisig(ctx *cli.Context) error {
}
}
var label *string
if ctx.IsSet("name") {
l := ctx.String("name")
label = &l
}
loop:
for _, pub := range pubs {
for _, wallAcc := range wall.Accounts {
if wallAcc.ScriptHash().Equals(pub.GetScriptHash()) {
if acc != nil {
// Multiple matching accounts found, fallback to WIF-based conversion.
acc = nil
break loop
}
acc = new(wallet.Account)
*acc = *wallAcc
accPub = pub
}
}
}
if acc != nil {
err = acc.ConvertMultisigEncrypted(accPub, m, pubs)
if err != nil {
return cli.NewExitError(err, 1)
}
if label != nil {
acc.Label = *label
}
if err := addAccountAndSave(wall, acc); err != nil {
return cli.NewExitError(err, 1)
}
return nil
}
if !ctx.IsSet("wif") {
return cli.NewExitError(errors.New("none of the provided public keys correspond to an existing key in the wallet or multiple matching accounts found in the wallet, and no WIF is provided"), 1)
}
acc, err = newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -651,8 +603,7 @@ func importDeployed(ctx *cli.Context) error {
return cli.NewExitError("contract has no `verify` method with boolean return", 1)
}
acc.Address = address.Uint160ToString(cs.Hash)
// Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed.
acc.Contract.Script = nil
acc.Contract.Script = cs.NEF.Script
acc.Contract.Parameters = acc.Contract.Parameters[:0]
for _, p := range md.Parameters {
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{
@ -871,7 +822,7 @@ func createWallet(ctx *cli.Context) error {
}
var pass *string
if len(configPath) != 0 {
cfg, err := options.ReadWalletConfig(configPath)
cfg, err := ReadWalletConfig(configPath)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -949,14 +900,14 @@ func createAccount(wall *wallet.Wallet, pass *string) error {
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
if err != nil {
return nil, nil, cli.NewExitError(fmt.Errorf("failed to get wallet path or password: %w", err), 1)
return nil, nil, err
}
if path == "-" {
return nil, nil, errNoStdin
}
w, err := wallet.NewWalletFromFile(path)
if err != nil {
return nil, nil, cli.NewExitError(fmt.Errorf("failed to read wallet: %w", err), 1)
return nil, nil, err
}
return w, pass, nil
}
@ -995,7 +946,7 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
}
var pass *string
if len(configPath) != 0 {
cfg, err := options.ReadWalletConfig(configPath)
cfg, err := ReadWalletConfig(configPath)
if err != nil {
return "", nil, err
}
@ -1005,6 +956,27 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
return path, pass, nil
}
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
file, err := os.Open(configPath)
if err != nil {
return nil, err
}
defer file.Close()
configData, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("unable to read wallet config: %w", err)
}
cfg := &config.Wallet{}
err = yaml.Unmarshal(configData, &cfg)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
}
return cfg, nil
}
func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams, label *string, pass *string) (*wallet.Account, error) {
var (
phrase, name string

View file

@ -1,6 +1,7 @@
package wallet_test
import (
"encoding/hex"
"encoding/json"
"math/big"
"os"
@ -436,16 +437,16 @@ func TestWalletInit(t *testing.T) {
"--wallet", walletPath,
"--min", "2"}
t.Run("invalid pub encoding", func(t *testing.T) {
e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
pubs[1].StringCompressed(),
pubs[2].StringCompressed(),
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
"not-a-pub")...)
})
t.Run("missing WIF", func(t *testing.T) {
e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
pubs[1].StringCompressed(),
pubs[2].StringCompressed(),
pubs[3].StringCompressed())...)
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
hex.EncodeToString(pubs[3].Bytes()))...)
})
cmd = append(cmd, "--wif", privs[0].WIF())
t.Run("InvalidPublicKeys", func(t *testing.T) {
@ -454,18 +455,18 @@ func TestWalletInit(t *testing.T) {
e.In.WriteString("multipass\r")
defer e.In.Reset()
e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
pubs[1].StringCompressed(),
pubs[2].StringCompressed(),
pubs[3].StringCompressed())...)
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
hex.EncodeToString(pubs[3].Bytes()))...)
})
e.In.WriteString("multiacc\r")
e.In.WriteString("multipass\r")
e.In.WriteString("multipass\r")
e.Run(t, append(cmd, pubs[0].StringCompressed(),
pubs[1].StringCompressed(),
pubs[2].StringCompressed(),
pubs[3].StringCompressed())...)
e.Run(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
hex.EncodeToString(pubs[3].Bytes()))...)
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
require.NoError(t, err)
@ -481,62 +482,10 @@ func TestWalletInit(t *testing.T) {
e.In.WriteString("multiacc\r")
e.In.WriteString("multipass\r")
e.In.WriteString("multipass\r")
e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
pubs[1].StringCompressed(),
pubs[2].StringCompressed(),
pubs[3].StringCompressed())...)
})
privs, pubs = testcli.GenerateKeys(t, 3)
script, err = smartcontract.CreateMultiSigRedeemScript(2, pubs)
require.NoError(t, err)
// Create a wallet and import a standard account
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
e.In.WriteString("standardacc\rstdpass\rstdpass\r")
e.Run(t, "neo-go", "wallet", "import",
"--wallet", walletPath,
"--wif", privs[0].WIF())
w, err = wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
actual = w.GetAccount(privs[0].GetScriptHash())
require.NotNil(t, actual)
require.NotEqual(t, actual.Contract.Script, script)
// Test when a public key of an already imported account is present
t.Run("existing account public key, no WIF", func(t *testing.T) {
e.Run(t, "neo-go", "wallet", "import-multisig",
"--wallet", walletPath,
"--min", "2",
pubs[0].StringCompressed(), // Public key of the already imported account
pubs[1].StringCompressed(),
pubs[2].StringCompressed())
w, err := wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
actual := w.GetAccount(hash.Hash160(script))
require.NotNil(t, actual)
require.Equal(t, actual.Contract.Script, script)
require.NoError(t, actual.Decrypt("stdpass", w.Scrypt))
require.NotEqual(t, actual.Address, w.GetAccount(privs[0].GetScriptHash()).Address)
})
// Test when no public key of an already imported account is present, and no WIF is provided
t.Run("no existing account public key, no WIF", func(t *testing.T) {
_, pubsNew := testcli.GenerateKeys(t, 3)
scriptNew, err := smartcontract.CreateMultiSigRedeemScript(2, pubsNew)
require.NoError(t, err)
e.RunWithError(t, "neo-go", "wallet", "import-multisig",
"--wallet", walletPath,
"--min", "2",
pubsNew[0].StringCompressed(),
pubsNew[1].StringCompressed(),
pubsNew[2].StringCompressed())
w, err := wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
actual := w.GetAccount(hash.Hash160(scriptNew))
require.Nil(t, actual)
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
hex.EncodeToString(pubs[3].Bytes()))...)
})
})
})
@ -656,47 +605,6 @@ func TestWalletClaimGas(t *testing.T) {
} else {
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
}
t.Run("await", func(t *testing.T) {
args := []string{
"neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--from", testcli.ValidatorAddr, "--await",
"--force",
"NEO:" + testcli.TestWalletAccount + ":1000",
"GAS:" + testcli.TestWalletAccount + ":1000", // for tx send
}
e.In.WriteString("one\r")
e.Run(t, args...)
e.CheckAwaitableTxPersisted(t)
h, err := address.StringToUint160(testcli.TestWalletAccount)
require.NoError(t, err)
balanceBefore := e.Chain.GetUtilityTokenBalance(h)
claimHeight := e.Chain.BlockHeight() + 1
cl, err := e.Chain.CalculateClaimable(h, claimHeight)
require.NoError(t, err)
require.True(t, cl.Sign() > 0)
e.In.WriteString("testpass\r")
e.Run(t, "neo-go", "wallet", "claim",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.TestWalletPath,
"--address", testcli.TestWalletAccount,
"--force", "--await")
tx, height = e.CheckAwaitableTxPersisted(t)
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
balanceBefore.Add(balanceBefore, cl)
balanceAfter = e.Chain.GetUtilityTokenBalance(h)
// height can be bigger than claimHeight especially when tests are executed with -race.
if height == claimHeight {
require.Equal(t, 0, balanceAfter.Cmp(balanceBefore))
} else {
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
}
})
}
func TestWalletImportDeployed(t *testing.T) {
@ -914,31 +822,6 @@ func TestOfflineSigning(t *testing.T) {
"--in", txPath)
})
e.CheckTxPersisted(t)
t.Run("await 1/1 multisig", func(t *testing.T) {
args := []string{"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", walletPath,
"--from", testcli.ValidatorAddr,
"--to", w.Accounts[0].Address,
"--token", "NEO",
"--amount", "1",
"--force",
}
e.Run(t, append(args, "--out", txPath)...)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "sign",
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
"--in", txPath, "--out", txPath)
e.Run(t, "neo-go", "wallet", "sign",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", walletPath, "--address", testcli.ValidatorAddr,
"--in", txPath, "--await")
e.CheckAwaitableTxPersisted(t)
})
t.Run("simple signature", func(t *testing.T) {
simpleAddr := w.Accounts[0].Address
args := []string{"neo-go", "wallet", "nep17", "transfer",
@ -970,31 +853,6 @@ func TestOfflineSigning(t *testing.T) {
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
txPath)
})
t.Run("await simple signature", func(t *testing.T) {
simpleAddr := w.Accounts[0].Address
args := []string{"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", walletPath,
"--from", simpleAddr,
"--to", testcli.ValidatorAddr,
"--token", "NEO",
"--amount", "1",
"--force",
}
e.Run(t, append(args, "--out", txPath)...)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "sign",
"--wallet", testcli.ValidatorWallet, "--address", simpleAddr,
"--in", txPath, "--out", txPath)
e.Run(t, "neo-go", "util", "sendtx",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
txPath, "--await")
e.CheckAwaitableTxPersisted(t)
})
}
func TestWalletDump(t *testing.T) {

View file

@ -22,11 +22,19 @@ ProtocolConfiguration:
- morph6.fs.neo.org:40333
- morph7.fs.neo.org:40333
VerifyTransactions: true
P2PSigExtensions: true
P2PSigExtensions: false
Hardforks:
Aspidochelone: 3000000
Basilisk: 4500000
Cockatrice: 5800000
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false

View file

@ -37,8 +37,16 @@ ProtocolConfiguration:
P2PSigExtensions: false
Hardforks:
Aspidochelone: 1730000
Basilisk: 4120000
Cockatrice: 5450000
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false

View file

@ -16,6 +16,16 @@ ProtocolConfiguration:
- node_four:20336
VerifyTransactions: true
P2PSigExtensions: false
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false
@ -63,7 +73,6 @@ ApplicationConfiguration:
- ":30336"
MaxGasInvoke: 15
EnableCORSWorkaround: false
SessionEnabled: true
Prometheus:
Enabled: true
Addresses:

View file

@ -16,6 +16,16 @@ ProtocolConfiguration:
- node_four:20336
VerifyTransactions: true
P2PSigExtensions: false
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false
@ -63,15 +73,13 @@ ApplicationConfiguration:
- ":30333"
MaxGasInvoke: 15
EnableCORSWorkaround: false
SessionEnabled: true
Prometheus:
Enabled: true
Addresses:
- ":20001"
Pprof:
Enabled: false
Addresses:
- ":20011"
Port: 20011
Consensus:
Enabled: true
UnlockWallet:

View file

@ -10,6 +10,16 @@ ProtocolConfiguration:
- node_single:20333
VerifyTransactions: true
P2PSigExtensions: false
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false
@ -54,7 +64,6 @@ ApplicationConfiguration:
- ":30333"
EnableCORSWorkaround: false
MaxGasInvoke: 15
SessionEnabled: true
Prometheus:
Enabled: true
Addresses:

View file

@ -16,6 +16,16 @@ ProtocolConfiguration:
- node_four:20336
VerifyTransactions: true
P2PSigExtensions: false
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false
@ -63,7 +73,6 @@ ApplicationConfiguration:
- ":30335"
MaxGasInvoke: 15
EnableCORSWorkaround: false
SessionEnabled: true
Prometheus:
Enabled: true
Addresses:

View file

@ -16,6 +16,16 @@ ProtocolConfiguration:
- node_four:20336
VerifyTransactions: true
P2PSigExtensions: false
NativeActivations:
ContractManagement: [0]
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration:
SkipBlockVerification: false
@ -63,7 +73,6 @@ ApplicationConfiguration:
EnableCORSWorkaround: false
Addresses:
- ":30334"
SessionEnabled: true
Prometheus:
Enabled: true
Addresses:

Some files were not shown because too many files have changed in this diff Show more