Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
|
8790602f69 | ||
|
c9050cef4b | ||
|
c296f8804c | ||
|
4543de0923 | ||
|
d77b35c385 | ||
|
225152f2d7 | ||
|
baf24d1c66 | ||
|
017a6b9bc1 | ||
|
5cb2a1219c | ||
|
c11481b119 | ||
|
bd3722041a |
730 changed files with 15273 additions and 50817 deletions
138
.circleci/config.yml
Normal file
138
.circleci/config.yml
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
version: 2.1
|
||||||
|
|
||||||
|
executors:
|
||||||
|
go1_17:
|
||||||
|
docker:
|
||||||
|
- image: cimg/go:1.17
|
||||||
|
go1_18:
|
||||||
|
docker:
|
||||||
|
- image: cimg/go:1.18
|
||||||
|
go1_19:
|
||||||
|
docker:
|
||||||
|
- image: cimg/go:1.19
|
||||||
|
|
||||||
|
commands:
|
||||||
|
gomod:
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
keys: [deps-v2-]
|
||||||
|
- run:
|
||||||
|
name: Download go module dependencies
|
||||||
|
command: go mod download
|
||||||
|
- save_cache:
|
||||||
|
key: deps-v2-{{ checksum "go.sum" }}-{{ checksum "go.sum" }}
|
||||||
|
paths: [/home/circleci/go/pkg/mod]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
working_directory: /home/circleci/go/src/github.com/nspcc-dev/neo-go
|
||||||
|
# TODO: temp workaround, need to upgrade to go1_18 after https://github.com/golangci/golangci-lint/issues/2649 is resolved.
|
||||||
|
executor: go1_17
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- gomod
|
||||||
|
- run:
|
||||||
|
name: go-lint
|
||||||
|
command: |
|
||||||
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2
|
||||||
|
make lint
|
||||||
|
|
||||||
|
test_1_17:
|
||||||
|
working_directory: /home/circleci/go/src/github.com/nspcc-dev/neo-go
|
||||||
|
executor: go1_17
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: git submodule sync
|
||||||
|
- run: git submodule update --init
|
||||||
|
- gomod
|
||||||
|
- run:
|
||||||
|
command: go test -v -race ./...
|
||||||
|
no_output_timeout: 15m
|
||||||
|
|
||||||
|
test_1_18:
|
||||||
|
working_directory: /home/circleci/go/src/github.com/nspcc-dev/neo-go
|
||||||
|
executor: go1_18
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: git submodule sync
|
||||||
|
- run: git submodule update --init
|
||||||
|
- gomod
|
||||||
|
- run:
|
||||||
|
command: go test -v -race ./...
|
||||||
|
no_output_timeout: 15m
|
||||||
|
|
||||||
|
test_1_19:
|
||||||
|
working_directory: /home/circleci/go/src/github.com/nspcc-dev/neo-go
|
||||||
|
executor: go1_19
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: git submodule sync
|
||||||
|
- run: git submodule update --init
|
||||||
|
- gomod
|
||||||
|
- run:
|
||||||
|
command: go test -v -race ./...
|
||||||
|
no_output_timeout: 15m
|
||||||
|
|
||||||
|
build_cli:
|
||||||
|
working_directory: /home/circleci/go/src/github.com/nspcc-dev/neo-go
|
||||||
|
executor: go1_19
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- gomod
|
||||||
|
- run: make build
|
||||||
|
- store_artifacts:
|
||||||
|
path: bin
|
||||||
|
destination: /
|
||||||
|
|
||||||
|
build_image:
|
||||||
|
working_directory: /home/circleci/go/src/github.com/nspcc-dev/neo-go
|
||||||
|
executor: go1_19
|
||||||
|
docker:
|
||||||
|
- image: golang:1-alpine
|
||||||
|
steps:
|
||||||
|
- run: apk update && apk add git make curl tar
|
||||||
|
- checkout
|
||||||
|
- gomod
|
||||||
|
- setup_remote_docker:
|
||||||
|
version: 20.10.6
|
||||||
|
- run:
|
||||||
|
name: Install Docker client
|
||||||
|
command: |
|
||||||
|
set -x
|
||||||
|
VER="20.10.6"
|
||||||
|
curl -L -o /tmp/docker-$VER.tgz https://download.docker.com/linux/static/stable/x86_64/docker-$VER.tgz
|
||||||
|
tar -xz -C /tmp -f /tmp/docker-$VER.tgz
|
||||||
|
mv /tmp/docker/* /usr/bin
|
||||||
|
- run: make image
|
||||||
|
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
workflow:
|
||||||
|
jobs:
|
||||||
|
- lint:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: v/[0-9]+\.[0-9]+\.[0-9]+/
|
||||||
|
- test_1_17:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: v/[0-9]+\.[0-9]+\.[0-9]+/
|
||||||
|
- test_1_18:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: v/[0-9]+\.[0-9]+\.[0-9]+/
|
||||||
|
- test_1_19:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: v/[0-9]+\.[0-9]+\.[0-9]+/
|
||||||
|
- build_cli:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: v/[0-9]+\.[0-9]+\.[0-9]+/
|
||||||
|
- build_image:
|
||||||
|
requires:
|
||||||
|
- build_cli
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: v/[0-9]+\.[0-9]+\.[0-9]+/
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
@ -52,4 +52,4 @@
|
||||||
"extra": {
|
"extra": {
|
||||||
"Tokens": null
|
"Tokens": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP",
|
"address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP",
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
@ -69,4 +69,4 @@
|
||||||
"extra": {
|
"extra": {
|
||||||
"Tokens": null
|
"Tokens": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
@ -52,4 +52,4 @@
|
||||||
"extra": {
|
"extra": {
|
||||||
"Tokens": null
|
"Tokens": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
@ -52,4 +52,4 @@
|
||||||
"extra": {
|
"extra": {
|
||||||
"Tokens": null
|
"Tokens": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isDefault": false
|
"isdefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
@ -52,4 +52,4 @@
|
||||||
"extra": {
|
"extra": {
|
||||||
"Tokens": null
|
"Tokens": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -1 +0,0 @@
|
||||||
* @AnnaShaleva @roman-khimov
|
|
BIN
.github/logo_dark.png
vendored
BIN
.github/logo_dark.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
56
.github/workflows/build.yml
vendored
56
.github/workflows/build.yml
vendored
|
@ -34,83 +34,78 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
build_cli:
|
build_cli:
|
||||||
name: Build CLI
|
name: Build CLI
|
||||||
runs-on: ${{matrix.os.name}}
|
runs-on: ${{matrix.os}}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [{ name: ubuntu-22.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }]
|
os: [ubuntu-20.04, windows-2022, macos-12]
|
||||||
arch: [amd64, arm64]
|
arch: [amd64, arm64]
|
||||||
exclude:
|
exclude:
|
||||||
- os: { name: windows-2022, bin-name: windows }
|
- os: windows-2022
|
||||||
arch: 'arm64'
|
arch: 'arm64'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
# Allows to fetch all history for all branches and tags. Need this for proper versioning.
|
# Allows to fetch all history for all branches and tags. Need this for proper versioning.
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.22'
|
go-version: 1.19
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Update Go modules
|
||||||
|
run: go mod download -json
|
||||||
|
|
||||||
- name: Build CLI
|
- name: Build CLI
|
||||||
run: make build
|
run: make build
|
||||||
env:
|
env:
|
||||||
GOARCH: ${{ matrix.arch }}
|
GOARCH: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Rename CLI binary
|
|
||||||
run: mv ./bin/neo-go* ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
|
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}
|
name: neo-go-${{ matrix.os }}-${{ matrix.arch }}
|
||||||
path: ./bin/neo-go*
|
path: ./bin/neo-go*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Attach binary to the release as an asset
|
|
||||||
if: ${{ github.event_name == 'release' }}
|
|
||||||
run: gh release upload ${{ github.event.release.tag_name }} ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
build_image:
|
build_image:
|
||||||
needs: build_cli
|
needs: build_cli
|
||||||
name: Build and push docker image
|
name: Build and push docker image
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
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:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||||
|
|
||||||
- name: Set vars
|
- name: Set vars
|
||||||
id: setvars
|
id: setvars
|
||||||
run: make gh-docker-vars >> $GITHUB_OUTPUT
|
run: make gh-docker-vars
|
||||||
|
|
||||||
- name: Set latest tag
|
- name: Set latest tag
|
||||||
id: setlatest
|
id: setlatest
|
||||||
if: ${{ (github.event_name == 'release' && github.event.release.target_commitish == 'master') || (github.event_name == 'workflow_dispatch' && github.event.inputs.use_latest_tag == 'true') }}
|
if: ${{ (github.event_name == 'release' && github.event.release.target_commitish == 'master') || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true' && github.event.inputs.use_latest_tag == 'true') }}
|
||||||
run: echo "latest=,${{ steps.setvars.outputs.repo }}:latest" >> $GITHUB_OUTPUT
|
run: echo "::set-output name=latest::,${{ steps.setvars.outputs.repo }}:latest"
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
||||||
|
@ -126,20 +121,21 @@ jobs:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# For proper `deps` make target execution.
|
# For proper `deps` make target execution.
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.22'
|
go-version: 1.19
|
||||||
|
cache: true
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
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:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||||
|
|
11
.github/workflows/contribution_guidelines.yml
vendored
11
.github/workflows/contribution_guidelines.yml
vendored
|
@ -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
|
|
|
@ -8,7 +8,7 @@ on:
|
||||||
- master
|
- master
|
||||||
types: [opened, synchronize]
|
types: [opened, synchronize]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'scripts/*.sh'
|
- 'scripts/**'
|
||||||
- '**/*.md'
|
- '**/*.md'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
@ -18,61 +18,26 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/setup-go@v3
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version: 1.19
|
||||||
|
- uses: actions/checkout@v3
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
version: latest
|
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:
|
gomodcheck:
|
||||||
name: Check internal dependencies
|
name: Check internal dependencies
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Check dependencies
|
- name: Check dependencies
|
||||||
run: |
|
run: |
|
||||||
./scripts/check_deps.sh
|
./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:
|
codeql:
|
||||||
name: CodeQL
|
name: CodeQL
|
||||||
|
@ -88,11 +53,11 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# 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).
|
# 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)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v3
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
|
@ -117,37 +82,41 @@ jobs:
|
||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|
||||||
test_cover:
|
test_cover:
|
||||||
name: Coverage
|
name: Coverage
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
GOEXPERIMENT: nocoverageredesign
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: 'true'
|
|
||||||
|
- name: Sync VM submodule
|
||||||
|
run: |
|
||||||
|
git submodule sync
|
||||||
|
git submodule update --init
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.22'
|
go-version: 1.19
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
|
- name: Update Go modules
|
||||||
|
run: go mod download -json
|
||||||
|
|
||||||
- name: Write coverage profile
|
- 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
|
- name: Upload coverage results to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
|
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
|
||||||
files: ./coverage.txt
|
files: ./coverage.txt
|
||||||
slug: nspcc-dev/neo-go
|
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
|
@ -155,36 +124,40 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-22.04, windows-2022, macos-12, macos-14]
|
os: [ubuntu-20.04, windows-2022, macos-12]
|
||||||
go_versions: [ '1.20', '1.21', '1.22' ]
|
go_versions: [ '1.17', '1.18', '1.19' ]
|
||||||
exclude:
|
exclude:
|
||||||
# Only latest Go version for Windows and MacOS.
|
# Only latest Go version for Windows and MacOS.
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
go_versions: '1.20'
|
go_versions: '1.17'
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
go_versions: '1.21'
|
go_versions: '1.18'
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
go_versions: '1.20'
|
go_versions: '1.17'
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
go_versions: '1.21'
|
go_versions: '1.18'
|
||||||
- os: macos-14
|
|
||||||
go_versions: '1.20'
|
|
||||||
- os: macos-14
|
|
||||||
go_versions: '1.21'
|
|
||||||
# Exclude latest Go version for Ubuntu as Coverage uses it.
|
# Exclude latest Go version for Ubuntu as Coverage uses it.
|
||||||
- os: ubuntu-22.04
|
- os: ubuntu-20.04
|
||||||
go_versions: '1.22'
|
go_versions: '1.19'
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '${{ matrix.go_versions }}'
|
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
|
- name: Run tests
|
||||||
run: go test -timeout 15m -v -race ./...
|
run: go test -v -race ./...
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -7,6 +7,9 @@
|
||||||
# Test binary, build with `go test -c`
|
# Test binary, build with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
# Added by CoZ developers
|
# Added by CoZ developers
|
||||||
vendor/
|
vendor/
|
||||||
bin/
|
bin/
|
||||||
|
@ -51,7 +54,6 @@ testdata/
|
||||||
!pkg/services/notary/testdata
|
!pkg/services/notary/testdata
|
||||||
!pkg/services/oracle/testdata
|
!pkg/services/oracle/testdata
|
||||||
!pkg/smartcontract/testdata
|
!pkg/smartcontract/testdata
|
||||||
!cli/smartcontract/testdata
|
|
||||||
pkg/vm/testdata/fuzz
|
pkg/vm/testdata/fuzz
|
||||||
!pkg/vm/testdata
|
!pkg/vm/testdata
|
||||||
!pkg/wallet/testdata
|
!pkg/wallet/testdata
|
||||||
|
|
|
@ -32,32 +32,20 @@ linters:
|
||||||
- revive
|
- revive
|
||||||
|
|
||||||
# some default golangci-lint linters
|
# some default golangci-lint linters
|
||||||
|
- deadcode
|
||||||
- errcheck
|
- errcheck
|
||||||
- gosimple
|
- gosimple
|
||||||
- godot
|
- godot
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- staticcheck
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
- typecheck
|
- typecheck
|
||||||
- unused
|
- unused
|
||||||
|
- varcheck
|
||||||
|
|
||||||
# extra linters
|
# extra linters
|
||||||
# - exhaustive
|
# - exhaustive
|
||||||
# - goconst
|
|
||||||
# - goerr113
|
|
||||||
# - gomnd
|
|
||||||
# - nonamedreturns
|
|
||||||
# - unparam
|
|
||||||
- bidichk
|
|
||||||
- bodyclose
|
|
||||||
- contextcheck
|
|
||||||
- decorder
|
|
||||||
- durationcheck
|
|
||||||
- errorlint
|
|
||||||
- exportloopref
|
|
||||||
- gofmt
|
- gofmt
|
||||||
- misspell
|
|
||||||
- predeclared
|
|
||||||
- reassign
|
|
||||||
- whitespace
|
- whitespace
|
||||||
- goimports
|
- goimports
|
||||||
disable-all: true
|
disable-all: true
|
||||||
|
@ -69,7 +57,3 @@ issues:
|
||||||
- EXC0003 # test/Test ... consider calling this
|
- EXC0003 # test/Test ... consider calling this
|
||||||
- EXC0004 # govet
|
- EXC0004 # govet
|
||||||
- EXC0005 # C-style breaks
|
- EXC0005 # C-style breaks
|
||||||
exclude-rules:
|
|
||||||
- linters:
|
|
||||||
- revive
|
|
||||||
text: "unused-parameter"
|
|
||||||
|
|
938
CHANGELOG.md
938
CHANGELOG.md
|
@ -2,942 +2,6 @@
|
||||||
|
|
||||||
This document outlines major changes between releases.
|
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
|
|
||||||
instructions check of smart contract's script on contract deployment or update.
|
|
||||||
Presence of this check leads to the known T5 testnet state incompatibility
|
|
||||||
(since 1670095) which causes inability to process new blocks (since 2272533).
|
|
||||||
It should be noted that the corresponding check was accidentally removed from
|
|
||||||
the reference C# node implementation way back in neo-project/neo#2266 and added
|
|
||||||
again in neo-project/neo#2849 which is planned to be a part of the upcoming
|
|
||||||
3.6.0 C# node release. Thus, changes made in the presented 0.101.3 release will
|
|
||||||
be reverted afterwards and strict contract script check will be present in the
|
|
||||||
next 3.6.0-compatible version of NeoGo node.
|
|
||||||
|
|
||||||
T5 testnet chain requires a complete resynchronization for this version. Mainnet
|
|
||||||
chain resynchronization is recommended.
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
|
|
||||||
* extra strict contract script check on contract deployment or update is
|
|
||||||
removed (#3052)
|
|
||||||
|
|
||||||
## 0.101.2 "Excavation" (29 Jun 2023)
|
|
||||||
|
|
||||||
One more (and unexpected one!) 3.5.0-compatible version that fixes a VM bug
|
|
||||||
leading to mainnet state incompatibility (since 3672783) which in turn leads
|
|
||||||
to inability to process new blocks (since 3682290).
|
|
||||||
|
|
||||||
Mainnet chain needs to be resynchronized for this version.
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* documentation updates (#3029, #2990, #2981)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* incorrect handling of empty Any-type parameter for RPC invocations (#2959)
|
|
||||||
* incorrect state rollbacks in case of exception during cross-contract call
|
|
||||||
when the call is made from non-TRYing context (#3046)
|
|
||||||
|
|
||||||
## 0.101.1 "Shallowness" (17 Mar 2023)
|
|
||||||
|
|
||||||
Another 3.5.0-compatible version that delivers important bug fixes and
|
|
||||||
provides a new API to be used by NeoFS. An upgrade is recommended, the DB
|
|
||||||
doesn't need to be resynchronized.
|
|
||||||
|
|
||||||
New features:
|
|
||||||
* internal RPC client for deeply integrated applications like NeoFS (#2916)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* documentation updates (#2879, #2880, #2893, #2917, #2920, #2936)
|
|
||||||
* code style, spelling and updated linter fixes (#2884, #2922, #2933)
|
|
||||||
* NEP-2 import password can be provided via config file now (#2887)
|
|
||||||
* custom stack item deserialization limit is available via public APIs now (#2904)
|
|
||||||
* RPC client endpoint can be retrieved via public API (#2915)
|
|
||||||
* dependency updates (#2919, #2929)
|
|
||||||
* WSClient now copies filter parameters to Subscribe* and Receive* methods
|
|
||||||
improving code safety (#2937)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* name parameter ignored for wallet import command (#2887)
|
|
||||||
* incorrect RPC binding code generated for Any return type (#2918)
|
|
||||||
* memory leak on active peer disconnection (#2924)
|
|
||||||
* consensus process deadlock (#2930)
|
|
||||||
* dBFT deadlock in "committed at previous view" scenario (#2935)
|
|
||||||
* panic in RPC waiter code (#2938)
|
|
||||||
|
|
||||||
## 0.101.0 "Shortness" (13 Jan 2023)
|
|
||||||
|
|
||||||
This release delivers an important fix for block execution application logs
|
|
||||||
and requires a resynchronization, therefore it's 0.101.0 (even though it's
|
|
||||||
also 3.5.0-compatible). It fixes some other minor problems as well (the other
|
|
||||||
most notable change probably is in the compiler), so we recommend upgrading.
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* updated golang.org/x/* dependencies (#2854)
|
|
||||||
* CLI help and required flags handling fixes (#2852)
|
|
||||||
* transfer data storage optimization (#2865)
|
|
||||||
* network's magic number is stored (and checked against the config on
|
|
||||||
startup) in the DB now, reducing potential for node operator errors (#2867)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* in rare cases nodes could request an invalid number of blocks from peers
|
|
||||||
leading to disconnect (#2846)
|
|
||||||
* outdated documentation fixes (#2860, #2876)
|
|
||||||
* application logs for blocks that contained GAS spends for transaction fees
|
|
||||||
contained (and returned from getapplicationlog RPC) incorrect (off by one)
|
|
||||||
values for amount in Transfer events; transaction application logs were not
|
|
||||||
affected by this, but data returned to RPC event subscribers could
|
|
||||||
potentially be (#2865)
|
|
||||||
* findstates RPC returned an error instead of an empty data set for valid
|
|
||||||
contracts that have no data (unlike C# node, #2866)
|
|
||||||
* miscompiled shadowed range loop variable definition (#2871)
|
|
||||||
* missing (compared to C# node) explicit (even though null) 'exception' field
|
|
||||||
in the getapplicationlog RPC output from server (#2872)
|
|
||||||
|
|
||||||
## 0.100.1 "Chaptalization" (28 Dec 2022)
|
|
||||||
|
|
||||||
This is a tiny update that 99.99% of users can easily skip. The reason for
|
|
||||||
this release is the need to fix compatibility with the NeoFS mainnet
|
|
||||||
sidechain and have some stable version to be used there. In any other case it
|
|
||||||
can be ignored, but if you still decide to upgrade you don't need to
|
|
||||||
resynchronize.
|
|
||||||
|
|
||||||
Behaviour changes:
|
|
||||||
* Aspidochelone fork is made to include ContractManagement native contract
|
|
||||||
deploy/update methods call flags change, initially it was an unconditional
|
|
||||||
part of 0.99.0 NeoGo release (or 3.2.0 C# version), but this behavior is
|
|
||||||
incompatible with the NeoFS mainnet sidechain; the change to the fork logic
|
|
||||||
does not affect any other public networks (mainnet/testnet) and any new
|
|
||||||
networks that have Aspidochelone enabled since block 0 (#2848)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* more robust NEP-11 divisibility check in the RPC server code (#2841)
|
|
||||||
* microoptimization for some debug log messages (#2842)
|
|
||||||
* additional fuzz tests for integer serialization and script parsing code (#2851)
|
|
||||||
|
|
||||||
## 0.100.0 "Centuplication" (08 Dec 2022)
|
|
||||||
|
|
||||||
A 3.5.0-compatible version of NeoGo with all the appropriate protocol updates
|
|
||||||
and a number of other changes. The most notable ones are configuration
|
|
||||||
updates. New features and some long-standing inconsistencies required for some
|
|
||||||
changes and this release brings them with it. Old configurations are still
|
|
||||||
supported and will work the same way (except for one minor exception in
|
|
||||||
VerifyBlocks that is only supposed to be used for tests/development), but we'd
|
|
||||||
like to highlight that all of the old settings will be removed in ~6 months,
|
|
||||||
so please review these updates and update your configurations. For public
|
|
||||||
networks the best way to go is to take the new versions from the "config"
|
|
||||||
directory and then adjust for particular scenario if needed.
|
|
||||||
|
|
||||||
This release requires a complete resynchronization due to native contract
|
|
||||||
changes, so please schedule your updates appropriately.
|
|
||||||
|
|
||||||
New features:
|
|
||||||
* System.Runtime.LoadScript syscall (and appropriate smart contract interops)
|
|
||||||
allowing to load/run dynamic code (#2719)
|
|
||||||
* PUSHT/PUSHF VM instructions allowing for simpler/cheaper booleans (#2770)
|
|
||||||
* ContractManagement native contract was extended with ID->hash mappings and
|
|
||||||
`getContractById` and `getContractHashes` methods (#2702, #2837)
|
|
||||||
* LogLevel application configuration option that can be changed on SIGHUP
|
|
||||||
(#2831)
|
|
||||||
* additional type data generated by the compiler that then can be used by the
|
|
||||||
RPC bindings (SDK/contract wrapper) generator, this allows for complex
|
|
||||||
types (structures/arrays/maps) to be easily represented/handled in
|
|
||||||
contract-specific RPC code (#2828)
|
|
||||||
* multiaddress listeners for all services and P2P, this changes the old
|
|
||||||
Address/Port (and AnnouncedPort for P2P) configuration scheme to more
|
|
||||||
generic Addresses list, the old configuration is still supported, but is
|
|
||||||
deprecated and will be removed in future node versions (#2827, #2839)
|
|
||||||
|
|
||||||
Behaviour changes:
|
|
||||||
* Aspidochelone fork block for NeoFS sidechain mainnet configuration is
|
|
||||||
rescheduled again (#2823, #2830)
|
|
||||||
* Blockchain's GetHeaderHash() method now accepts uint32 for parameter
|
|
||||||
(#2814)
|
|
||||||
* pre-0.97.3 and pre-0.99.0 deprecated compatibility fields and logic were
|
|
||||||
dropped from the result.Version (`getversion` RPC result) structure (#2786)
|
|
||||||
* SecondsPerBlock protocol configuration variable was replaced with
|
|
||||||
TimePerBlock allowing for sub-second precision, SecondsPerBlock is still
|
|
||||||
supported, but will eventually be removed (#2829)
|
|
||||||
* AttemptConnPeers, BroadcastFactor, DialTimeout, ExtensiblePoolSize,
|
|
||||||
MaxPeers, MinPeers, PingInterval, PingTimeout, ProtoTickInterval settings
|
|
||||||
were moved into the new P2P section, timing parameters now use Duration
|
|
||||||
type allowing for more human-friendly values in many cases, old parameters
|
|
||||||
are still supported, but will eventually be removed (#2827)
|
|
||||||
* consensus (dBFT) is configured as a separate service now that can be
|
|
||||||
enabled/disabled (and can work in "watch only" mode without a wallet), the
|
|
||||||
old direct "UnlockWallet" specification in "ApplicationConfiguration" is
|
|
||||||
still supported, but is deprecated and will be removed in future versions
|
|
||||||
(#2832)
|
|
||||||
* GarbageCollectionPeriod, KeepOnlyLatestState, RemoveUntraceableBlocks,
|
|
||||||
SaveStorageBatch and VerifyBlocks settings were moved from
|
|
||||||
ProtocolConfiguration to ApplicationConfiguration; old configurations are
|
|
||||||
still supported, except for VerifyBlocks which is replaced by
|
|
||||||
SkipBlockVerification with inverted meaning (and hence an inverted default)
|
|
||||||
for security reasons; this also affects NewBlockchain and neotest APIs
|
|
||||||
(#2833)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* more user-friendly error and help messages in some cases (#2824, #2834)
|
|
||||||
* faster node startup time and smaller memory footprint for networks with
|
|
||||||
lots (1-2M+) of blocks (#2814)
|
|
||||||
* minor documentation fixes (#2834, #2838)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* transactions with system fee or more than MaxBlockSystemFee are no longer
|
|
||||||
accepted into the mempool, preventing a form a network-wide DoS (#2826)
|
|
||||||
* deprecated WSClient subscription methods not working correctly when filters
|
|
||||||
are being used (#2836)
|
|
||||||
|
|
||||||
## 0.99.7 "Hyalinization" (23 Nov 2022)
|
|
||||||
|
|
||||||
Bugs, terrestrial arthropods with at least six legs. Sometimes we don't notice
|
|
||||||
them, sometimes we ignore them, but they do exist and there are times when
|
|
||||||
they need to be dealt with in one way or another. Most of the bugs fixed in
|
|
||||||
this release have a little less legs than proper insects, they're far from
|
|
||||||
being as critical as the ones fixed in the previous release and yet we
|
|
||||||
consider them annoying enough to warrant this new version of NeoGo to be
|
|
||||||
published. We don't want to see our users fighting these pesky creatures in
|
|
||||||
the wild, better update and have a troublefree experience.
|
|
||||||
|
|
||||||
If you're not affected by #2815 (requests for verbose transaction data and
|
|
||||||
application logs failed for some specific mainnet transaction(s)) you may
|
|
||||||
leave the DB as is with this upgrade, if you want it to be solved then please
|
|
||||||
resynchronize.
|
|
||||||
|
|
||||||
Behaviour changes:
|
|
||||||
* "loadtx" VM CLI command now uses transaction system fee value as the
|
|
||||||
default GAS limit for the context, unless --gas is used (previously it
|
|
||||||
wasn't limited, #2816)
|
|
||||||
* SendRawTransaction RPC client method will now always return transaction
|
|
||||||
hash, even if error occured, this also affects Actor APIs and allows to
|
|
||||||
handle some specific errors (like transaction already present in the
|
|
||||||
mempool) in more appropriate way (#2817)
|
|
||||||
* Actor and NotaryActor Wait() wrapper methods now handle "already exists"
|
|
||||||
and "already on chain" errors as non-errors, waiting (if needed) and
|
|
||||||
returning proper results (#2817)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* reworked network discoverer/connection manager that has a better picture of
|
|
||||||
the network (especially if it's a small one), doesn't try to make additional
|
|
||||||
connections (even when having less than MinPeers of them) when there are no
|
|
||||||
more real addresses to connect to, establishes stable connections faster in
|
|
||||||
containerized environments and does more connection attempts when MinPeers
|
|
||||||
setting is not satisfied, but there are potential candidates (#2811)
|
|
||||||
* VM invocation stack handling microoptimization (#2812)
|
|
||||||
* load* VM CLI commands now accept --gas parameter to set the amount of GAS
|
|
||||||
to be used in this context (#2816)
|
|
||||||
* better logging during state reset process (#2813)
|
|
||||||
* subscription-based transaction waiter now handles already accepted
|
|
||||||
transactions faster (~immediately vs waiting for block timeout previously,
|
|
||||||
#2817)
|
|
||||||
* WSClient can return more specific error on websocket handshake failure if
|
|
||||||
it's provided by server (#2821)
|
|
||||||
* new MaxWebSocketClients configuration option for the RPC server to control
|
|
||||||
the number of allowed websocket clients, missing or 0 value make the server
|
|
||||||
use the default of 64 which is compatible with the previous behavior (you
|
|
||||||
can use old configurations if you don't care about this option, #2821)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* occasional "loadgo" VM CLI test failures because of timeout (#2810)
|
|
||||||
* websocket waiter test instability (#2809)
|
|
||||||
* websocket event unsubscriptions could lead to node deadlock in rare
|
|
||||||
circumstances (#2809)
|
|
||||||
* exception handler could use improper evaluation stack in some cases (#2812)
|
|
||||||
* pointer stack items were not handled correctly in "protected" serialization
|
|
||||||
mode leading to inability to deserialize these items back (#2816)
|
|
||||||
* state reset functionality not working for big chains like mainnet (#2813)
|
|
||||||
|
|
||||||
## 0.99.6 "Funambulation" (16 Nov 2022)
|
|
||||||
|
|
||||||
An emergency release fixing mainnet incompatibility at block 2504320 leading
|
|
||||||
to inability to process block 2504813. A couple of other less severe bugs got
|
|
||||||
fixed as well. Unfortunately, this release requires complete resynchronization
|
|
||||||
for mainnet, other networks can use old DBs.
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* only transactions requested by the consensus process are forwarded to it
|
|
||||||
now slightly improving performance in some networked scenarios (#2788)
|
|
||||||
* a complete set of simple array unwrappers in the unwrap library (#2792)
|
|
||||||
* RPC binding generator can handle simple arrays now with configuration file
|
|
||||||
provided (#2792)
|
|
||||||
* more user-friendly error messages in some cases (#2797, #2802, #2804)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* DB was not properly closed after state reset (#2791)
|
|
||||||
* VM stack handling problem leading to lost items after return from call to
|
|
||||||
another contract (#2800)
|
|
||||||
* "istack" command panic in the VM CLI (#2800)
|
|
||||||
* failure to decode incorrect contract from ContractManagement state leading
|
|
||||||
to failure to start the node, it'll be ignored now similar to how C# node
|
|
||||||
treats this (#2802)
|
|
||||||
* subscription to execution events failed if no "state" filter was used along
|
|
||||||
with "container" (#2804)
|
|
||||||
* Actor using WSClient could deadlock in the transaction waiter during
|
|
||||||
unsubscription (#2804)
|
|
||||||
|
|
||||||
## 0.99.5 "Underestimation" (11 Nov 2022)
|
|
||||||
|
|
||||||
It wasn't long since the previous release until a juicy set of features and
|
|
||||||
optimisations came on board. So we've decided to change our release plan and
|
|
||||||
supply one more 3.4.0 compatible version. It comes up with a massive suite
|
|
||||||
of network P2P and broadcast improvements. We've carefully investigated message
|
|
||||||
sending timeouts on benchmarks, reworked the broadcast logic and significantly
|
|
||||||
reduced delays in message sending and the amount of useless traffic between our
|
|
||||||
nodes. For smart-contract developers and RPC client users several new features
|
|
||||||
were added. These are automatic RPC bindings generator, poll-based and
|
|
||||||
websocket-based transactions awaiting and an extended websocket client
|
|
||||||
subscriptions interface. For better debugging experience we've improved state
|
|
||||||
related functionality of VM CLI and added an ability to reset chain state to a
|
|
||||||
particular height.
|
|
||||||
|
|
||||||
An important dBFT initialization bug that caused timestamp-related errors on
|
|
||||||
block addition was fixed. Also, those who use NeoGo node with
|
|
||||||
EnableCORSWorkaround setting may want to update the node to be able to handle
|
|
||||||
web-socket requests with Origin set in the header. The users of websocket RPC
|
|
||||||
client subscription mechanism are welcomed to move from deprecated subscriptions
|
|
||||||
API to the extended one. Finally, we are kindly asking our users to have a look
|
|
||||||
at our roadmap file where deprecated code removal schedule is attached.
|
|
||||||
|
|
||||||
This version is fully compatible with C# node 3.4.0 and does not require
|
|
||||||
resynchronization on upgrade. This time for sure, the next release is planned
|
|
||||||
to be compatible with 3.5.0.
|
|
||||||
|
|
||||||
New features:
|
|
||||||
* logarithmic gossip fan-out, new `BroadcastFactor` application setting and
|
|
||||||
adaptive peer requests are added to optimise broadcasting process (#608,
|
|
||||||
#2678, #2743)
|
|
||||||
* Prometheus histograms with handling time are added for P2P commands (#2750)
|
|
||||||
and RPC calls (#2784)
|
|
||||||
* transaction awaiting is added to RPC clients (#2740, #2749)
|
|
||||||
* RPC bindings generator (#2705) is added for both safe (#2766) and
|
|
||||||
state-changing (#2769, #2778) methods with initial iterator support (#2783)
|
|
||||||
* the ability to reset chain state to a particular height is added (#2576,
|
|
||||||
#2773)
|
|
||||||
|
|
||||||
Behaviour changes:
|
|
||||||
* Aspidochelone fork block for NeoFS sidechain mainnet configuration is
|
|
||||||
rescheduled (#2754, #2776)
|
|
||||||
* RPC server will now handle any Origin in websocket connection when
|
|
||||||
EnableCORSWorkaround setting is on (#2772, #2724)
|
|
||||||
* WS RPC client subscriptions API is extended to accept custom subscriber
|
|
||||||
channels, old subscriptions API is marked as deprecated (#2756, #2764)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* network code refactoring (#2742)
|
|
||||||
* network packets sending is now limited in time (#2738)
|
|
||||||
* broadcast messages will be sent concurrently to each peer (#2741)
|
|
||||||
* ping messages are broadcast using the common broadcast logic (#2742)
|
|
||||||
* transactions requested by dBFT will be accepted on demand only (#2746, #2748,
|
|
||||||
nspcc-dev/dbft#63)
|
|
||||||
* VM CLI's state-based functionality improvements (extended signers and
|
|
||||||
arguments parsing, enabled logging) and additional commands (`loadtx`,
|
|
||||||
`loaddeployed`, `jump`) (#2729, #2606, #2740)
|
|
||||||
* incoming P2P transactions are now processed concurrently and buffer for
|
|
||||||
inventory hashes is reusable (#2755)
|
|
||||||
* `GetData` and `GetBlocksByIndex` replies are now batched on a TCP-level
|
|
||||||
(#2757)
|
|
||||||
* optimisation of incoming P2P transactions and blocks filtering are introduced
|
|
||||||
(#2758, #2759)
|
|
||||||
* batch size of broadcast transactions hashes is adjusted (#2760)
|
|
||||||
* peer reconnections logic is improved, `GetAddr` messages are sent more
|
|
||||||
often (#2761, #2745)
|
|
||||||
* documentation for wallet configuration file is clarified (#2763)
|
|
||||||
* Koblitz curve implementation of btcd/btcec was replaced with decred/secp256k1
|
|
||||||
due to GitHub security warning (#2781)
|
|
||||||
* `NOT` opcode for Bool emission is now used to reduce resulting script
|
|
||||||
cost (#2762)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* failing tests cleanup on Windows (#2736)
|
|
||||||
* race in CLI test (#2765)
|
|
||||||
* invalid conversion of PublicKey smart contract parameter to emitable (#2739)
|
|
||||||
* initialize dBFT's context with previous block's timestamp on view 0 (#2753,
|
|
||||||
#2752, nspcc-dev/dbft#64)
|
|
||||||
|
|
||||||
## 0.99.4 "Transliteration" (07 Oct 2022)
|
|
||||||
|
|
||||||
A small update mostly interesting for people building/testing smart contracts
|
|
||||||
with NeoGo. It contains long-awaited VM CLI update that allows to use
|
|
||||||
blockchain state and complete set of interops, additional helper functions for
|
|
||||||
smart contracts and notification checking code (for upcoming 3.5.0 protocol
|
|
||||||
changes). Node operators using EnableCORSWorkaround (that is still not
|
|
||||||
recommended, but available) also may want to update to be able to handle
|
|
||||||
pre-flight CORS requests.
|
|
||||||
|
|
||||||
This version is compatible with C# node 3.4.0 and does not require
|
|
||||||
resynchronization on upgrade. The next release is planned to be compatible
|
|
||||||
with 3.5.0.
|
|
||||||
|
|
||||||
New features:
|
|
||||||
* address conversion helpers for smart contracts (#2698)
|
|
||||||
* interop helper to call specific version of a contract (#2695)
|
|
||||||
* notifications are now checked for manifest compliance, a warning is logged
|
|
||||||
in case on detected inconsistencies (#2710)
|
|
||||||
* VM CLI can now use blockchain state DB (including historic states) to run
|
|
||||||
code with a complete set of interops and contracts available; additional
|
|
||||||
commands were added to it to inspect storage and generated events (#2723)
|
|
||||||
|
|
||||||
Behavior changes:
|
|
||||||
* type assertion with two return values in Go contracts can't be compiled now
|
|
||||||
(it never worked properly, #2718)
|
|
||||||
* RPC server will now handle pre-flight CORS requests (via OPTIONS methods)
|
|
||||||
when EnableCORSWorkaround setting is on (#2724)
|
|
||||||
* all transaction-generating CLI commands were unified to accept
|
|
||||||
gas/sysgas/out/force parameters, ask for confirmation and be able to save
|
|
||||||
transaction into a file; this affects wallet claim and candidate-related
|
|
||||||
commands mostly (#2731)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* smartcontract.Builder API was extended with Len method (#2691)
|
|
||||||
* NNS example contract adjustments for better DNS compatibility (#2679)
|
|
||||||
* documentation updates (#2708, #2722, #2726, #2728)
|
|
||||||
* compiler now emits code to explicitly cast runtime.Notify() parameters to
|
|
||||||
appropriate types (#2720)
|
|
||||||
* CLI tests repackaging (#2725)
|
|
||||||
* NeoFS sidechain configurations for mainnet and testnet (#2730)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* panic on node shutdown (#2689)
|
|
||||||
* panic on inlined append() compilation (#2716)
|
|
||||||
|
|
||||||
## 0.99.3 "Simplification" (09 Sep 2022)
|
|
||||||
|
|
||||||
Version 0.99.3 brings with it most of the planned refactoring changes to the
|
|
||||||
RPC client. dApp backend code can be greatly simplified in many cases by
|
|
||||||
using new APIs (old ones are still available for transition period of about
|
|
||||||
one-two releases more). We also have some updates for CLI and compiler and a
|
|
||||||
number of bug fixes.
|
|
||||||
|
|
||||||
This version is compatible with C# node 3.4.0 and does not require
|
|
||||||
resynchronization on upgrade. The next release is planned to be compatible
|
|
||||||
with 3.5.0 (if it's to be released around currently planned dates).
|
|
||||||
|
|
||||||
New features:
|
|
||||||
* native contract RPC wrappers (#2643, #2646, #2650, #2666, #2665)
|
|
||||||
* NEP-11 RPC wrappers (#2651)
|
|
||||||
* invoker interface extension with session-based iterators support (#2650)
|
|
||||||
* notary Actor greatly simplifying creation of notary-assisted transactions
|
|
||||||
via RPC client (#2665)
|
|
||||||
* historic smart contract calls can now be made via CLI (#2683)
|
|
||||||
|
|
||||||
Behavior changes:
|
|
||||||
* calculatenetworkfee RPC can handle paid attributes (NeoGo extensions) and
|
|
||||||
invalid contract signatures now, it won't return an error for them (#2658)
|
|
||||||
* graceful node shutdown on SIGTERM (#2660)
|
|
||||||
* wallet balance commands now require at least 0.99.1 NeoGo version (or
|
|
||||||
compatible C# node) used by the RPC server (#2667)
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
* build system corrections (#2641, #2684)
|
|
||||||
* additional types in `unwrap` (#2650, #2651)
|
|
||||||
* session iterator consistency check in `unwrap` (#2650)
|
|
||||||
* multitransfers in NEP-17 RPC wrapper (#2653)
|
|
||||||
* extended transaction validity time in CLI wallet commands (#2653)
|
|
||||||
* reference counter optimization in VM (#2659)
|
|
||||||
* RPC Actor API can have default (used for all transactions) attributes and
|
|
||||||
callbacks now (#2665)
|
|
||||||
* neptoken RPC package can now provide wallet.Token data (#2667)
|
|
||||||
* NEP-11 balance commands can now work without direct token hash
|
|
||||||
specification or previous token import (#2667)
|
|
||||||
* support for offline signing in CLI (#2668)
|
|
||||||
* compiler can optimize out unused global variables now (#2624)
|
|
||||||
* private keys are now cleaned up from memory when they're no longer needed,
|
|
||||||
additional Account APIs added to reduce direct interactions with private
|
|
||||||
keys (#2672)
|
|
||||||
* updated linter settings, some code cleanup (#2674)
|
|
||||||
* more documentation and examples for new RPC APIs (#2681)
|
|
||||||
* refactored state-changing methods of NEP-11/NEP-17 RPC wrappers into a
|
|
||||||
separate structure to simplify reusing them in higher-level code (#2681)
|
|
||||||
* simplified rpcclient historic API (#2686)
|
|
||||||
|
|
||||||
Bugs fixed:
|
|
||||||
* compiler panic on empty package list (#2645)
|
|
||||||
* compiler not allowed to use unnamed parameters in exported methods (#2648)
|
|
||||||
* compiler allowed to export multireturn functions (#2648)
|
|
||||||
* compiler panic on nil method receiver in the compiled code (#2649)
|
|
||||||
* compiler panic on variable initialization from multireturn call (#2644)
|
|
||||||
* potential lockups or panics on node shutdown (#2652)
|
|
||||||
* contract manifest not checked for correctness in bindings generation CLI
|
|
||||||
command (#2656)
|
|
||||||
* SignTx wallet Account API could lead to inconsistent result in some cases
|
|
||||||
(#2665)
|
|
||||||
* wallet Account API allowed to sign with locked accounts (#2665)
|
|
||||||
* potential panic in keys.WIFDecode on some inputs (#2672)
|
|
||||||
|
|
||||||
## 0.99.2 "Recalibration" (12 Aug 2022)
|
## 0.99.2 "Recalibration" (12 Aug 2022)
|
||||||
|
|
||||||
This is a 3.4.0-compatible (tested for mainnet and testnet) update to NeoGo
|
This is a 3.4.0-compatible (tested for mainnet and testnet) update to NeoGo
|
||||||
|
@ -2609,7 +1673,7 @@ Behavior changes:
|
||||||
* contracts no longer have single entry point, rather they export a set of
|
* contracts no longer have single entry point, rather they export a set of
|
||||||
methods with specific offsets. Go smart contract compiler has been changed
|
methods with specific offsets. Go smart contract compiler has been changed
|
||||||
accordingly to add all exported (as in Go) methods to the manifest
|
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
|
#1228). Please also refer to examples changes to better see how it affects
|
||||||
contracts, manifests and configuration files (#1296)
|
contracts, manifests and configuration files (#1296)
|
||||||
* native contracts are now called via Neo.Native.Call syscall (#1191)
|
* native contracts are now called via Neo.Native.Call syscall (#1191)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Builder image
|
# Builder image
|
||||||
# Keep go version in sync with Build GA job.
|
# Keep go version in sync with Build GA job.
|
||||||
FROM golang:1.22-alpine as builder
|
FROM golang:1.18-alpine as builder
|
||||||
|
|
||||||
# Display go version for information purposes.
|
# Display go version for information purposes.
|
||||||
RUN go version
|
RUN go version
|
||||||
|
|
|
@ -1,6 +1,75 @@
|
||||||
# Builder image
|
# 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.
|
# Keep go version in sync with Build GA job.
|
||||||
FROM golang:1.22.0-windowsservercore-ltsc2022 as builder
|
ENV GOLANG_VERSION=1.19
|
||||||
|
|
||||||
|
RUN $url = 'https://go.dev/dl/go1.19.windows-amd64.zip'; \
|
||||||
|
Write-Host ('Downloading {0} ...' -f $url); \
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile 'go.zip'; \
|
||||||
|
\
|
||||||
|
$sha256 = 'bcaaf966f91980d35ae93c37a8fe890e4ddfca19448c0d9f66c027d287e2823a'; \
|
||||||
|
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
|
COPY . /neo-go
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
MIT License
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
12
Makefile
12
Makefile
|
@ -3,7 +3,7 @@ REPONAME = "neo-go"
|
||||||
NETMODE ?= "privnet"
|
NETMODE ?= "privnet"
|
||||||
BINARY=neo-go
|
BINARY=neo-go
|
||||||
BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE)
|
BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE)
|
||||||
GO_VERSION ?= 1.20
|
GO_VERSION ?= 1.18
|
||||||
DESTDIR = ""
|
DESTDIR = ""
|
||||||
SYSCONFIGDIR = "/etc"
|
SYSCONFIGDIR = "/etc"
|
||||||
BINDIR = "/usr/bin"
|
BINDIR = "/usr/bin"
|
||||||
|
@ -16,7 +16,7 @@ DC_FILE ?= ".docker/docker-compose.yml" # Single docker-compose for Ubuntu/WSC,
|
||||||
ENV_IMAGE_TAG="env_neo_go_image"
|
ENV_IMAGE_TAG="env_neo_go_image"
|
||||||
|
|
||||||
REPO ?= "$(shell go list -m)"
|
REPO ?= "$(shell go list -m)"
|
||||||
VERSION ?= "$(shell git describe --tags --match "v*" --abbrev=8 2>/dev/null | sed -r 's,^v([0-9]+\.[0-9]+)\.([0-9]+)(-.*)?$$,\1 \2 \3,' | while read mm patch suffix; do if [ -z "$$suffix" ]; then echo $$mm.$$patch; else patch=`expr $$patch + 1`; echo $$mm.$${patch}-pre$$suffix; fi; done)"
|
VERSION ?= "$(shell git describe --tags --match "v*" 2>/dev/null | sed 's/^v//')"
|
||||||
MODVERSION ?= "$(shell cat go.mod | cat go.mod | sed -r -n -e 's|.*pkg/interop (.*)|\1|p')"
|
MODVERSION ?= "$(shell cat go.mod | cat go.mod | sed -r -n -e 's|.*pkg/interop (.*)|\1|p')"
|
||||||
BUILD_FLAGS = "-X '$(REPO)/pkg/config.Version=$(VERSION)' -X '$(REPO)/cli/smartcontract.ModVersion=$(MODVERSION)'"
|
BUILD_FLAGS = "-X '$(REPO)/pkg/config.Version=$(VERSION)' -X '$(REPO)/cli/smartcontract.ModVersion=$(MODVERSION)'"
|
||||||
|
|
||||||
|
@ -96,10 +96,10 @@ version:
|
||||||
@echo $(VERSION)
|
@echo $(VERSION)
|
||||||
|
|
||||||
gh-docker-vars:
|
gh-docker-vars:
|
||||||
@echo "file=$(D_FILE)"
|
@echo "::set-output name=file::$(D_FILE)"
|
||||||
@echo "version=$(VERSION)"
|
@echo "::set-output name=version::$(VERSION)"
|
||||||
@echo "repo=$(IMAGE_REPO)"
|
@echo "::set-output name=repo::$(IMAGE_REPO)"
|
||||||
@echo "suffix=$(IMAGE_SUFFIX)"
|
@echo "::set-output name=suffix::$(IMAGE_SUFFIX)"
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@go test ./... -cover
|
@go test ./... -cover
|
||||||
|
|
75
README.md
75
README.md
|
@ -1,9 +1,5 @@
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<picture>
|
<img src="./.github/neo_color_dark_gopher.png" width="300px" alt="logo">
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="./.github/logo_dark.png">
|
|
||||||
<source media="(prefers-color-scheme: light)" srcset="./.github/logo_light.png">
|
|
||||||
<img src="./.github/logo_light.png" width="300px" alt="NeoGo logo">
|
|
||||||
</picture>
|
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<b>Go</b> Node and SDK for the <a href="https://neo.org">Neo</a> blockchain.
|
<b>Go</b> Node and SDK for the <a href="https://neo.org">Neo</a> blockchain.
|
||||||
|
@ -12,7 +8,8 @@
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
[![codecov](https://codecov.io/gh/nspcc-dev/neo-go/branch/master/graph/badge.svg)](https://codecov.io/gh/nspcc-dev/neo-go)
|
[![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)
|
[![CircleCI](https://circleci.com/gh/nspcc-dev/neo-go/tree/master.svg?style=shield)](https://circleci.com/gh/nspcc-dev/neo-go/tree/master)
|
||||||
|
[![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)
|
[![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)
|
[![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)
|
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/nspcc-dev/neo-go?sort=semver)
|
||||||
|
@ -20,21 +17,20 @@
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
NeoGo is a complete platform for distributed application development built on
|
This project aims to be a full port of the original C# [Neo project](https://github.com/neo-project).
|
||||||
top of and compatible with the [Neo project](https://github.com/neo-project).
|
A complete toolkit for the NEO blockchain, including:
|
||||||
This includes, but not limited to (see documentation for more details):
|
|
||||||
|
|
||||||
- [Consensus node](docs/consensus.md)
|
- [Consensus node](docs/consensus.md)
|
||||||
- [RPC node & client](docs/rpc.md)
|
- [RPC node & client](docs/rpc.md)
|
||||||
- [CLI tool](docs/cli.md)
|
- [CLI tool](docs/cli.md)
|
||||||
- [Smart contract compiler](docs/compiler.md)
|
- [Smart contract compiler](docs/compiler.md)
|
||||||
- [Neo virtual machine](docs/vm.md)
|
- [NEO virtual machine](docs/vm.md)
|
||||||
- [Smart contract examples](examples/README.md)
|
- [Smart contract examples](examples/README.md)
|
||||||
- [Oracle service](docs/oracle.md)
|
- [Oracle service](docs/oracle.md)
|
||||||
- [State validation service](docs/stateroots.md)
|
- [State validation service](docs/stateroots.md)
|
||||||
|
|
||||||
The protocol implemented here is Neo N3-compatible, however you can also find
|
This branch (**master**) is Neo N3-compatible. For the current
|
||||||
an implementation of the Neo Legacy protocol in the [**master-2.x**
|
Legacy-compatible version please refer to the [**master-2.x**
|
||||||
branch](https://github.com/nspcc-dev/neo-go/tree/master-2.x) and releases
|
branch](https://github.com/nspcc-dev/neo-go/tree/master-2.x) and releases
|
||||||
before 0.80.0 (**0.7X.Y** track).
|
before 0.80.0 (**0.7X.Y** track).
|
||||||
|
|
||||||
|
@ -51,16 +47,13 @@ NeoGo, `:latest` points to the latest release) or build yourself.
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
Building NeoGo requires Go 1.20+ and `make`:
|
To build NeoGo you need Go 1.16+ and `make`:
|
||||||
|
|
||||||
```
|
```
|
||||||
make
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
The resulting binary is `bin/neo-go`. Notice that using some random revision
|
The resulting binary is `bin/neo-go`.
|
||||||
from the `master` branch is not recommended (it can have any number of
|
|
||||||
incompatibilities and bugs depending on the development stage), please use
|
|
||||||
tagged released versions.
|
|
||||||
|
|
||||||
#### Building on Windows
|
#### Building on Windows
|
||||||
|
|
||||||
|
@ -68,11 +61,13 @@ To build NeoGo on Windows platform we recommend you to install `make` from [MinG
|
||||||
package](https://osdn.net/projects/mingw/). Then, you can build NeoGo with:
|
package](https://osdn.net/projects/mingw/). Then, you can build NeoGo with:
|
||||||
|
|
||||||
```
|
```
|
||||||
make
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
The resulting binary is `bin/neo-go.exe`.
|
The resulting binary is `bin/neo-go.exe`.
|
||||||
|
|
||||||
|
We also recommend you to switch the Windows Firewall off for further NeoGo node run.
|
||||||
|
|
||||||
## Running a node
|
## Running a node
|
||||||
|
|
||||||
A node needs to connect to some network, either local one (usually referred to
|
A node needs to connect to some network, either local one (usually referred to
|
||||||
|
@ -101,9 +96,6 @@ Available network flags:
|
||||||
To run a consensus/committee node, refer to [consensus
|
To run a consensus/committee node, refer to [consensus
|
||||||
documentation](docs/consensus.md).
|
documentation](docs/consensus.md).
|
||||||
|
|
||||||
If you're running a node on Windows, please turn off or configure Windows
|
|
||||||
Firewall appropriately (allowing inbound connections to the P2P port).
|
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
By default, the `CMD` is set to run a node on `privnet`. So, to do this, simply run:
|
By default, the `CMD` is set to run a node on `privnet`. So, to do this, simply run:
|
||||||
|
@ -134,39 +126,37 @@ Refer to [consensus node documentation](docs/consensus.md).
|
||||||
|
|
||||||
## Smart contract development
|
## Smart contract development
|
||||||
|
|
||||||
Please refer to [NeoGo smart contract development
|
Please refer to [neo-go smart contract development
|
||||||
workshop](https://github.com/nspcc-dev/neo-go-sc-wrkshp) that shows some
|
workshop](https://github.com/nspcc-dev/neo-go-sc-wrkshp) that shows some
|
||||||
simple contracts that can be compiled/deployed/run using NeoGo compiler, SDK
|
simple contracts that can be compiled/deployed/run using neo-go compiler, SDK
|
||||||
and a private network. For details on how Go code is translated to Neo VM
|
and a private network. For details on how Go code is translated to Neo VM
|
||||||
bytecode and what you can and can not do in a smart contract, please refer to the
|
bytecode and what you can and can not do in a smart contract, please refer to the
|
||||||
[compiler documentation](docs/compiler.md).
|
[compiler documentation](docs/compiler.md).
|
||||||
|
|
||||||
Refer to [examples](examples/README.md) for more Neo smart contract examples
|
Refer to [examples](examples/README.md) for more NEO smart contract examples
|
||||||
written in Go.
|
written in Go.
|
||||||
|
|
||||||
## Wallets
|
## Wallets
|
||||||
|
|
||||||
NeoGo wallet is just a
|
NeoGo differs substantially from C# implementation in its approach to
|
||||||
|
wallets. NeoGo wallet is just a
|
||||||
[NEP-6](https://github.com/neo-project/proposals/blob/68398d28b6932b8dd2b377d5d51bca7b0442f532/nep-6.mediawiki)
|
[NEP-6](https://github.com/neo-project/proposals/blob/68398d28b6932b8dd2b377d5d51bca7b0442f532/nep-6.mediawiki)
|
||||||
file that is used by CLI commands to sign various things. CLI commands are not
|
file that is used by CLI commands to sign various things. There is no database
|
||||||
a direct part of the node, but rather a part of the NeoGo binary, their
|
behind it, the blockchain is the database and CLI commands use RPC to query
|
||||||
implementations use RPC to query data from the blockchain and perform any
|
data from it. At the same time, it's not required to open a wallet on an RPC
|
||||||
required actions. It's not required to open a wallet on an RPC node (unless
|
node to perform various actions (unless your node provides some service
|
||||||
your node provides some service for the network like consensus or oracle nodes
|
for the network like consensus or oracle nodes do).
|
||||||
do).
|
|
||||||
|
|
||||||
## Monitoring
|
# Developer notes
|
||||||
NeoGo provides [Prometheus](https://prometheus.io/docs/guides/go-application) and
|
Nodes have such features as [Prometheus](https://prometheus.io/docs/guides/go-application) and
|
||||||
[Pprof](https://golang.org/pkg/net/http/pprof/) services that can be enabled
|
[Pprof](https://golang.org/pkg/net/http/pprof/) in order to have additional information about them for debugging.
|
||||||
in the node in order to provide additional monitoring and debugging data.
|
|
||||||
|
|
||||||
Configuring any of the two services is easy, add the following section (`Pprof`
|
How to configure Prometheus or Pprof:
|
||||||
instead of `Prometheus` if you need that) to the respective `config/protocol.*.yml`:
|
In `config/protocol.*.yml` there is
|
||||||
```
|
```
|
||||||
Prometheus:
|
Prometheus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Addresses:
|
Port: 2112
|
||||||
- ":2112"
|
|
||||||
```
|
```
|
||||||
where you can switch on/off and define port. Prometheus is enabled and Pprof is disabled by default.
|
where you can switch on/off and define port. Prometheus is enabled and Pprof is disabled by default.
|
||||||
|
|
||||||
|
@ -180,9 +170,10 @@ describing the feature/topic you are going to implement.
|
||||||
|
|
||||||
# Contact
|
# Contact
|
||||||
|
|
||||||
- [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub
|
|
||||||
- [@roman-khimov](https://github.com/roman-khimov) on GitHub
|
- [@roman-khimov](https://github.com/roman-khimov) on GitHub
|
||||||
- Reach out to us on the [Neo Discord](https://discordapp.com/invite/R8v48YA) channel
|
- [@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
|
# License
|
||||||
|
|
||||||
|
|
67
ROADMAP.md
67
ROADMAP.md
|
@ -7,65 +7,10 @@ functionality.
|
||||||
## Versions 0.7X.Y (as needed)
|
## Versions 0.7X.Y (as needed)
|
||||||
* Neo 2.0 support (bug fixes, minor functionality additions)
|
* Neo 2.0 support (bug fixes, minor functionality additions)
|
||||||
|
|
||||||
## Version 0.107.0 (~Jun-Jul 2024)
|
## Version 0.99.3 (September 2022)
|
||||||
* protocol updates
|
* completely reworked RPC packages with all of the old functionality (but
|
||||||
* bug fixes
|
keeping old APIs for this release as well)
|
||||||
* node resynchronisation from local DB
|
* VM CLI improvements
|
||||||
* CLI library upgrade
|
|
||||||
|
|
||||||
## Version 1.0 (2024, TBD)
|
## Version 1.0 (2022, TBD)
|
||||||
* stable version
|
* stable version with full Neo N3 support and useful extensions
|
||||||
|
|
||||||
# Deprecated functionality
|
|
||||||
|
|
||||||
As the node and the protocol evolve some external APIs can change. Usually we
|
|
||||||
try keeping backwards compatibility for some time (like half a year) unless
|
|
||||||
it's impossible to do for some reason. But eventually old
|
|
||||||
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.
|
|
||||||
|
|
||||||
## 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).
|
|
||||||
|
|
||||||
## `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.
|
|
||||||
|
|
||||||
## `serv_node_version` Prometheus gauge metric
|
|
||||||
|
|
||||||
This metric is replaced by the new `neogo_version` and `server_id` Prometheus gauge
|
|
||||||
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).
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/query"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/server"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/vm"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/wallet"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func versionPrinter(c *cli.Context) {
|
|
||||||
_, _ = fmt.Fprintf(c.App.Writer, "NeoGo\nVersion: %s\nGoVersion: %s\n",
|
|
||||||
config.Version,
|
|
||||||
runtime.Version(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a NeoGo instance of [cli.App] with all commands included.
|
|
||||||
func New() *cli.App {
|
|
||||||
cli.VersionPrinter = versionPrinter
|
|
||||||
ctl := cli.NewApp()
|
|
||||||
ctl.Name = "neo-go"
|
|
||||||
ctl.Version = config.Version
|
|
||||||
ctl.Usage = "Official Go client for Neo"
|
|
||||||
ctl.ErrWriter = os.Stdout
|
|
||||||
|
|
||||||
ctl.Commands = append(ctl.Commands, server.NewCommands()...)
|
|
||||||
ctl.Commands = append(ctl.Commands, smartcontract.NewCommands()...)
|
|
||||||
ctl.Commands = append(ctl.Commands, wallet.NewCommands()...)
|
|
||||||
ctl.Commands = append(ctl.Commands, vm.NewCommands()...)
|
|
||||||
ctl.Commands = append(ctl.Commands, util.NewCommands()...)
|
|
||||||
ctl.Commands = append(ctl.Commands, query.NewCommands()...)
|
|
||||||
return ctl
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package app_test
|
|
||||||
|
|
||||||
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.
|
|
||||||
e := testcli.NewExecutor(t, false)
|
|
||||||
e.Run(t, "neo-go", "--version")
|
|
||||||
e.CheckNextLine(t, "^NeoGo")
|
|
||||||
e.CheckNextLine(t, "^Version:")
|
|
||||||
e.CheckNextLine(t, "^GoVersion:")
|
|
||||||
e.CheckEOF(t)
|
|
||||||
}
|
|
155
cli/candidate_test.go
Normal file
155
cli/candidate_test.go
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register standby validator and vote for it.
|
||||||
|
// We don't create a new account here, because chain will
|
||||||
|
// stop working after validator will change.
|
||||||
|
func TestRegisterCandidate(t *testing.T) {
|
||||||
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
validatorHex := hex.EncodeToString(validatorPriv.PublicKey().Bytes())
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--from", validatorAddr,
|
||||||
|
"--force",
|
||||||
|
"NEO:"+validatorPriv.Address()+":10",
|
||||||
|
"GAS:"+validatorPriv.Address()+":10000")
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "query", "committee",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||||
|
e.checkNextLine(t, "^\\s*"+validatorHex)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "query", "candidates",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||||
|
e.checkNextLine(t, "^\\s*Key.+$") // Header.
|
||||||
|
e.checkEOF(t)
|
||||||
|
|
||||||
|
// missing address
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "candidate", "register",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet)
|
||||||
|
|
||||||
|
// additional parameter
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "candidate", "register",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address(),
|
||||||
|
"error")
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "register",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address())
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
vs, err := e.Chain.GetEnrollments()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(vs))
|
||||||
|
require.Equal(t, validatorPriv.PublicKey(), vs[0].Key)
|
||||||
|
require.Equal(t, big.NewInt(0), vs[0].Votes)
|
||||||
|
|
||||||
|
t.Run("VoteUnvote", func(t *testing.T) {
|
||||||
|
// positional instead of a flag.
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "candidate", "vote",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address(),
|
||||||
|
validatorHex) // not "--candidate hex", but "hex".
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address(),
|
||||||
|
"--candidate", validatorHex)
|
||||||
|
_, index := e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
require.Equal(t, 1, len(vs))
|
||||||
|
require.Equal(t, validatorPriv.PublicKey(), vs[0].Key)
|
||||||
|
b, _ := e.Chain.GetGoverningTokenBalance(validatorPriv.GetScriptHash())
|
||||||
|
require.Equal(t, b, vs[0].Votes)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "query", "committee",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||||
|
e.checkNextLine(t, "^\\s*"+validatorHex)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "query", "candidates",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||||
|
e.checkNextLine(t, "^\\s*Key.+$") // Header.
|
||||||
|
e.checkNextLine(t, "^\\s*"+validatorHex+"\\s*"+b.String()+"\\s*true\\s*true$")
|
||||||
|
e.checkEOF(t)
|
||||||
|
|
||||||
|
// check state
|
||||||
|
e.Run(t, "neo-go", "query", "voter",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
validatorPriv.Address())
|
||||||
|
e.checkNextLine(t, "^\\s*Voted:\\s+"+validatorHex+"\\s+\\("+validatorPriv.Address()+"\\)$")
|
||||||
|
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
||||||
|
e.checkNextLine(t, "^\\s*Block\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||||
|
e.checkEOF(t)
|
||||||
|
|
||||||
|
// unvote
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address())
|
||||||
|
_, index = e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
require.Equal(t, 1, len(vs))
|
||||||
|
require.Equal(t, validatorPriv.PublicKey(), 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.Addr,
|
||||||
|
validatorPriv.Address())
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
|
||||||
|
// missing address
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet)
|
||||||
|
// additional argument
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address(),
|
||||||
|
"argument")
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--address", validatorPriv.Address())
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
require.Equal(t, 0, len(vs))
|
||||||
|
|
||||||
|
// query voter: missing address
|
||||||
|
e.RunWithError(t, "neo-go", "query", "voter")
|
||||||
|
// Excessive parameters.
|
||||||
|
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addr, validatorPriv.Address(), validatorPriv.Address())
|
||||||
|
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addr, "something")
|
||||||
|
e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addr, "something")
|
||||||
|
}
|
|
@ -24,144 +24,19 @@ const (
|
||||||
ArrayEndSeparator = "]"
|
ArrayEndSeparator = "]"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// ParamsParsingDoc is a documentation for parameters parsing.
|
|
||||||
ParamsParsingDoc = ` Arguments always do have regular Neo smart contract parameter types, either
|
|
||||||
specified explicitly or being inferred from the value. To specify the type
|
|
||||||
manually use "type:value" syntax where the type is one of the following:
|
|
||||||
'signature', 'bool', 'int', 'hash160', 'hash256', 'bytes', 'key' or 'string'.
|
|
||||||
Array types are also supported: use special space-separated '[' and ']'
|
|
||||||
symbols around array values to denote array bounds. Nested arrays are also
|
|
||||||
supported. Null parameter is supported via 'nil' keyword without additional
|
|
||||||
type specification.
|
|
||||||
|
|
||||||
There is ability to provide an argument of 'bytearray' type via file. Use a
|
|
||||||
special 'filebytes' argument type for this with a filepath specified after
|
|
||||||
the colon, e.g. 'filebytes:my_file.txt'.
|
|
||||||
|
|
||||||
Given values are type-checked against given types with the following
|
|
||||||
restrictions applied:
|
|
||||||
* 'signature' type values should be hex-encoded and have a (decoded)
|
|
||||||
length of 64 bytes.
|
|
||||||
* 'bool' type values are 'true' and 'false'.
|
|
||||||
* 'int' values are decimal integers that can be successfully converted
|
|
||||||
from the string.
|
|
||||||
* 'hash160' values are Neo addresses and hex-encoded 20-bytes long (after
|
|
||||||
decoding) strings.
|
|
||||||
* 'hash256' type values should be hex-encoded and have a (decoded)
|
|
||||||
length of 32 bytes.
|
|
||||||
* 'bytes' type values are any hex-encoded things.
|
|
||||||
* 'filebytes' type values are filenames with the argument value inside.
|
|
||||||
* 'key' type values are hex-encoded marshalled public keys.
|
|
||||||
* 'string' type values are any valid UTF-8 strings. In the value's part of
|
|
||||||
the string the colon looses it's special meaning as a separator between
|
|
||||||
type and value and is taken literally.
|
|
||||||
|
|
||||||
If no type is explicitly specified, it is inferred from the value using the
|
|
||||||
following logic:
|
|
||||||
- anything that can be interpreted as a decimal integer gets
|
|
||||||
an 'int' type
|
|
||||||
- 'nil' string gets 'Any' NEP-14 parameter type and nil value which corresponds
|
|
||||||
to Null stackitem
|
|
||||||
- 'true' and 'false' strings get 'bool' type
|
|
||||||
- valid Neo addresses and 20 bytes long hex-encoded strings get 'hash160'
|
|
||||||
type
|
|
||||||
- valid hex-encoded public keys get 'key' type
|
|
||||||
- 32 bytes long hex-encoded values get 'hash256' type
|
|
||||||
- 64 bytes long hex-encoded values get 'signature' type
|
|
||||||
- any other valid hex-encoded values get 'bytes' type
|
|
||||||
- anything else is a 'string'
|
|
||||||
|
|
||||||
Backslash character is used as an escape character and allows to use colon in
|
|
||||||
an implicitly typed string. For any other characters it has no special
|
|
||||||
meaning, to get a literal backslash in the string use the '\\' sequence.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
* 'int:42' is an integer with a value of 42
|
|
||||||
* '42' is an integer with a value of 42
|
|
||||||
* 'nil' is a parameter with Any NEP-14 type and nil value (corresponds to Null stackitem)
|
|
||||||
* 'bad' is a string with a value of 'bad'
|
|
||||||
* 'dead' is a byte array with a value of 'dead'
|
|
||||||
* 'string:dead' is a string with a value of 'dead'
|
|
||||||
* 'filebytes:my_data.txt' is bytes decoded from a content of my_data.txt
|
|
||||||
* 'NSiVJYZej4XsxG5CUpdwn7VRQk8iiiDMPM' is a hash160 with a value
|
|
||||||
of '682cca3ebdc66210e5847d7f8115846586079d4a'
|
|
||||||
* '\4\2' is an integer with a value of 42
|
|
||||||
* '\\4\2' is a string with a value of '\42'
|
|
||||||
* 'string:string' is a string with a value of 'string'
|
|
||||||
* 'string\:string' is a string with a value of 'string:string'
|
|
||||||
* '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c' is a
|
|
||||||
key with a value of '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c'
|
|
||||||
* '[ a b c ]' is an array with strings values 'a', 'b' and 'c'
|
|
||||||
* '[ a b [ c d ] e ]' is an array with 4 values: string 'a', string 'b',
|
|
||||||
array of two strings 'c' and 'd', string 'e'
|
|
||||||
* '[ ]' is an empty array`
|
|
||||||
|
|
||||||
// SignersParsingDoc is a documentation for signers parsing.
|
|
||||||
SignersParsingDoc = ` Signers represent a set of Uint160 hashes with witness scopes and are used
|
|
||||||
to verify hashes in System.Runtime.CheckWitness syscall. First signer is treated
|
|
||||||
as a sender. To specify signers use signer[:scope] syntax where
|
|
||||||
* 'signer' is a signer's address (as Neo address or hex-encoded 160 bit (20 byte)
|
|
||||||
LE value with or without '0x' prefix).
|
|
||||||
* 'scope' is a comma-separated set of cosigner's scopes, which could be:
|
|
||||||
- 'None' - default witness scope which may be used for the sender
|
|
||||||
to only pay fee for the transaction.
|
|
||||||
- 'Global' - allows this witness in all contexts. This cannot be combined
|
|
||||||
with other flags.
|
|
||||||
- 'CalledByEntry' - means that this condition must hold: EntryScriptHash
|
|
||||||
== CallingScriptHash. The witness/permission/signature
|
|
||||||
given on first invocation will automatically expire if
|
|
||||||
entering deeper internal invokes. This can be default
|
|
||||||
safe choice for native NEO/GAS.
|
|
||||||
- 'CustomContracts' - define valid custom contract hashes for witness check.
|
|
||||||
Hashes are be provided as hex-encoded LE value string.
|
|
||||||
At lest one hash must be provided. Multiple hashes
|
|
||||||
are separated by ':'.
|
|
||||||
- 'CustomGroups' - define custom public keys for group members. Public keys are
|
|
||||||
provided as short-form (1-byte prefix + 32 bytes) hex-encoded
|
|
||||||
values. At least one key must be provided. Multiple keys
|
|
||||||
are separated by ':'.
|
|
||||||
|
|
||||||
If no scopes were specified, 'CalledByEntry' used as default. If no signers were
|
|
||||||
specified, no array is passed. Note that scopes are properly handled by
|
|
||||||
neo-go RPC server only. C# implementation does not support scopes capability.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
* 'NNQk4QXsxvsrr3GSozoWBUxEmfag7B6hz5'
|
|
||||||
* 'NVquyZHoPirw6zAEPvY1ZezxM493zMWQqs:Global'
|
|
||||||
* '0x0000000009070e030d0f0e020d0c06050e030c02'
|
|
||||||
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
|
||||||
`CustomGroups:0206d7495ceb34c197093b5fc1cccf1996ada05e69ef67e765462a7f5d88ee14d0'
|
|
||||||
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
|
||||||
`CustomContracts:1011120009070e030d0f0e020d0c06050e030c02:0x1211100009070e030d0f0e020d0c06050e030c02'`
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetSignersFromContext returns signers parsed from context args starting
|
// GetSignersFromContext returns signers parsed from context args starting
|
||||||
// from the specified offset.
|
// from the specified offset.
|
||||||
func GetSignersFromContext(ctx *cli.Context, offset int) ([]transaction.Signer, *cli.ExitError) {
|
func GetSignersFromContext(ctx *cli.Context, offset int) ([]transaction.Signer, *cli.ExitError) {
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
var (
|
|
||||||
signers []transaction.Signer
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if args.Present() && len(args) > offset {
|
|
||||||
signers, err = ParseSigners(args[offset:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return signers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseSigners returns array of signers parsed from their string representation.
|
|
||||||
func ParseSigners(args []string) ([]transaction.Signer, error) {
|
|
||||||
var signers []transaction.Signer
|
var signers []transaction.Signer
|
||||||
for i, c := range args {
|
if args.Present() && len(args) > offset {
|
||||||
cosigner, err := parseCosigner(c)
|
for i, c := range args[offset:] {
|
||||||
if err != nil {
|
cosigner, err := parseCosigner(c)
|
||||||
return nil, fmt.Errorf("failed to parse signer #%d: %w", i, err)
|
if err != nil {
|
||||||
|
return nil, cli.NewExitError(fmt.Errorf("failed to parse signer #%d: %w", i, err), 1)
|
||||||
|
}
|
||||||
|
signers = append(signers, cosigner)
|
||||||
}
|
}
|
||||||
signers = append(signers, cosigner)
|
|
||||||
}
|
}
|
||||||
return signers, nil
|
return signers, nil
|
||||||
}
|
}
|
||||||
|
@ -230,9 +105,9 @@ func parseCosigner(c string) (transaction.Signer, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDataFromContext returns data parameter from context args.
|
// GetDataFromContext returns data parameter from context args.
|
||||||
func GetDataFromContext(ctx *cli.Context) (int, any, *cli.ExitError) {
|
func GetDataFromContext(ctx *cli.Context) (int, interface{}, *cli.ExitError) {
|
||||||
var (
|
var (
|
||||||
data any
|
data interface{}
|
||||||
offset int
|
offset int
|
||||||
params []smartcontract.Parameter
|
params []smartcontract.Parameter
|
||||||
err error
|
err error
|
||||||
|
@ -324,7 +199,10 @@ func ParseParams(args []string, calledFromMain bool) (int, []smartcontract.Param
|
||||||
// accounts from the provided wallet.
|
// accounts from the provided wallet.
|
||||||
func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers []transaction.Signer, accScope transaction.WitnessScope) ([]actor.SignerAccount, error) {
|
func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers []transaction.Signer, accScope transaction.WitnessScope) ([]actor.SignerAccount, error) {
|
||||||
signersAccounts := make([]actor.SignerAccount, 0, len(signers)+1)
|
signersAccounts := make([]actor.SignerAccount, 0, len(signers)+1)
|
||||||
sender := senderAcc.ScriptHash()
|
sender, err := address.StringToUint160(senderAcc.Address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
signersAccounts = append(signersAccounts, actor.SignerAccount{
|
signersAccounts = append(signersAccounts, actor.SignerAccount{
|
||||||
Signer: transaction.Signer{
|
Signer: transaction.Signer{
|
||||||
Account: sender,
|
Account: sender,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cmdargs
|
package cmdargs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ func TestParseCosigner(t *testing.T) {
|
||||||
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
|
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
|
||||||
AllowedContracts: []util.Uint160{c1, c2},
|
AllowedContracts: []util.Uint160{c1, c2},
|
||||||
},
|
},
|
||||||
acc.StringLE() + ":CustomGroups:" + priv.PublicKey().StringCompressed(): {
|
acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): {
|
||||||
Account: acc,
|
Account: acc,
|
||||||
Scopes: transaction.CustomGroups,
|
Scopes: transaction.CustomGroups,
|
||||||
AllowedGroups: keys.PublicKeys{priv.PublicKey()},
|
AllowedGroups: keys.PublicKeys{priv.PublicKey()},
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package smartcontract_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -13,8 +12,6 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"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/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
@ -25,7 +22,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"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/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||||
|
@ -34,12 +30,9 @@ import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keep contract NEFs consistent between runs.
|
|
||||||
const _ = versionutil.TestVersion
|
|
||||||
|
|
||||||
func TestCalcHash(t *testing.T) {
|
func TestCalcHash(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
e := testcli.NewExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
nefPath := "./testdata/verify.nef"
|
nefPath := "./testdata/verify.nef"
|
||||||
src, err := os.ReadFile(nefPath)
|
src, err := os.ReadFile(nefPath)
|
||||||
|
@ -90,24 +83,27 @@ func TestCalcHash(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("valid, uint160", func(t *testing.T) {
|
t.Run("valid, uint160", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--sender", sender.StringLE())...)
|
e.Run(t, append(cmd, "--sender", sender.StringLE())...)
|
||||||
e.CheckNextLine(t, expected.StringLE())
|
e.checkNextLine(t, expected.StringLE())
|
||||||
})
|
})
|
||||||
t.Run("valid, uint160 with 0x", func(t *testing.T) {
|
t.Run("valid, uint160 with 0x", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--sender", "0x"+sender.StringLE())...)
|
e.Run(t, append(cmd, "--sender", "0x"+sender.StringLE())...)
|
||||||
e.CheckNextLine(t, expected.StringLE())
|
e.checkNextLine(t, expected.StringLE())
|
||||||
})
|
})
|
||||||
t.Run("valid, address", func(t *testing.T) {
|
t.Run("valid, address", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--sender", address.Uint160ToString(sender))...)
|
e.Run(t, append(cmd, "--sender", address.Uint160ToString(sender))...)
|
||||||
e.CheckNextLine(t, expected.StringLE())
|
e.checkNextLine(t, expected.StringLE())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractBindings(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.
|
// For proper contract init. The actual version as it will be replaced.
|
||||||
smartcontract.ModVersion = "v0.0.0"
|
smartcontract.ModVersion = "v0.0.0"
|
||||||
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
e := testcli.NewExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
ctrPath := filepath.Join(tmpDir, "testcontract")
|
ctrPath := filepath.Join(tmpDir, "testcontract")
|
||||||
e.Run(t, "neo-go", "contract", "init", "--name", ctrPath)
|
e.Run(t, "neo-go", "contract", "init", "--name", ctrPath)
|
||||||
|
@ -146,7 +142,18 @@ func Blocks() []*alias.Block {
|
||||||
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
|
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
|
||||||
|
|
||||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
// 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,
|
cmd = append(cmd, "--config", cfgPath,
|
||||||
"--out", filepath.Join(tmpDir, "out.nef"),
|
"--out", filepath.Join(tmpDir, "out.nef"),
|
||||||
|
@ -156,7 +163,7 @@ func Blocks() []*alias.Block {
|
||||||
e.RunWithError(t, append(cmd, "something")...)
|
e.RunWithError(t, append(cmd, "something")...)
|
||||||
})
|
})
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
require.FileExists(t, bindingsPath)
|
require.FileExists(t, bindingsPath)
|
||||||
|
|
||||||
outPath := filepath.Join(t.TempDir(), "binding.go")
|
outPath := filepath.Join(t.TempDir(), "binding.go")
|
||||||
|
@ -166,9 +173,7 @@ func Blocks() []*alias.Block {
|
||||||
|
|
||||||
bs, err := os.ReadFile(outPath)
|
bs, err := os.ReadFile(outPath)
|
||||||
require.NoError(t, err)
|
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.
|
require.Equal(t, `// Package testcontract contains wrappers for testcontract contract.
|
||||||
|
|
||||||
// Package testcontract contains wrappers for testcontract contract.
|
|
||||||
package testcontract
|
package testcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -203,90 +208,15 @@ func ToMap(a []testcontract.MyPair) map[int]string {
|
||||||
`, string(bs))
|
`, 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) {
|
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.
|
// For proper contract init. The actual version as it will be replaced.
|
||||||
smartcontract.ModVersion = "v0.0.0"
|
smartcontract.ModVersion = "v0.0.0"
|
||||||
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
e := testcli.NewExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
t.Run("no path is provided", func(t *testing.T) {
|
t.Run("no path is provided", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "init")
|
e.RunWithError(t, "neo-go", "contract", "init")
|
||||||
|
@ -306,8 +236,7 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "init", "--name", ctrPath)
|
e.RunWithError(t, "neo-go", "contract", "init", "--name", ctrPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
ctrRootPath := filepath.Join(ctrPath, "main")
|
srcPath := filepath.Join(ctrPath, "main.go")
|
||||||
srcPath := ctrRootPath + ".go"
|
|
||||||
cfgPath := filepath.Join(ctrPath, "neo-go.yml")
|
cfgPath := filepath.Join(ctrPath, "neo-go.yml")
|
||||||
nefPath := filepath.Join(tmpDir, "testcontract.nef")
|
nefPath := filepath.Join(tmpDir, "testcontract.nef")
|
||||||
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
|
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
|
||||||
|
@ -333,7 +262,15 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
// 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)
|
cmd = append(cmd, "--config", cfgPath)
|
||||||
|
|
||||||
|
@ -342,35 +279,25 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
require.FileExists(t, nefPath)
|
require.FileExists(t, nefPath)
|
||||||
require.FileExists(t, manifestPath)
|
require.FileExists(t, manifestPath)
|
||||||
|
|
||||||
t.Run("output hex script with --verbose", func(t *testing.T) {
|
t.Run("output hex script with --verbose", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--verbose")...)
|
e.Run(t, append(cmd, "--verbose")...)
|
||||||
e.CheckNextLine(t, "^[0-9a-hA-H]+$")
|
e.checkNextLine(t, "^[0-9a-hA-H]+$")
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("autocomplete outputs", func(t *testing.T) {
|
|
||||||
cfg, err := os.ReadFile(cfgPath)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, os.WriteFile(filepath.Join(ctrPath, "main.yml"), cfg, os.ModePerm))
|
|
||||||
e.Run(t, "neo-go", "contract", "compile", "--in", srcPath)
|
|
||||||
defaultNefPath := ctrRootPath + ".nef"
|
|
||||||
defaultManifestPath := ctrRootPath + ".manifest.json"
|
|
||||||
defaultBindingsPath := ctrRootPath + ".bindings.yml"
|
|
||||||
require.FileExists(t, defaultNefPath)
|
|
||||||
require.FileExists(t, defaultManifestPath)
|
|
||||||
require.FileExists(t, defaultBindingsPath)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks that error is returned if GAS available for test-invoke exceeds
|
// Checks that error is returned if GAS available for test-invoke exceeds
|
||||||
// GAS needed to be consumed.
|
// GAS needed to be consumed.
|
||||||
func TestDeployBigContract(t *testing.T) {
|
func TestDeployBigContract(t *testing.T) {
|
||||||
e := testcli.NewExecutorWithConfig(t, true, true, func(c *config.Config) {
|
e := newExecutorWithConfig(t, true, true, func(c *config.Config) {
|
||||||
c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1)
|
c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -380,15 +307,18 @@ func TestDeployBigContract(t *testing.T) {
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString("one\r")
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName)
|
"--in", nefName, "--manifest", manifestName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractDeployWithData(t *testing.T) {
|
func TestContractDeployWithData(t *testing.T) {
|
||||||
eCompile := testcli.NewExecutor(t, false)
|
eCompile := newExecutor(t, false)
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -398,36 +328,28 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--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)
|
e := newExecutor(t, true)
|
||||||
cmd := []string{
|
cmd := []string{
|
||||||
"neo-go", "contract", "deploy",
|
"neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"--force",
|
"--force",
|
||||||
}
|
}
|
||||||
|
|
||||||
if await {
|
|
||||||
cmd = append(cmd, "--await")
|
|
||||||
}
|
|
||||||
if haveData {
|
if haveData {
|
||||||
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
|
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
|
||||||
}
|
}
|
||||||
if scope != "" {
|
if scope != "" {
|
||||||
cmd = append(cmd, "--", testcli.ValidatorAddr+":"+scope)
|
cmd = append(cmd, "--", validatorAddr+":"+scope)
|
||||||
} else {
|
} else {
|
||||||
scope = "CalledByEntry"
|
scope = "CalledByEntry"
|
||||||
}
|
}
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, cmd...)
|
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())
|
require.Equal(t, scope, tx.Signers[0].Scopes.String())
|
||||||
if !haveData {
|
if !haveData {
|
||||||
return
|
return
|
||||||
|
@ -440,7 +362,7 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
h.StringLE(),
|
h.StringLE(),
|
||||||
"getValueWithKey", "key1",
|
"getValueWithKey", "key1",
|
||||||
)
|
)
|
||||||
|
@ -452,7 +374,7 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
require.Equal(t, []byte{12}, res.Stack[0].Value())
|
require.Equal(t, []byte{12}, res.Stack[0].Value())
|
||||||
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
h.StringLE(),
|
h.StringLE(),
|
||||||
"getValueWithKey", "key2",
|
"getValueWithKey", "key2",
|
||||||
)
|
)
|
||||||
|
@ -464,16 +386,16 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
deployContract(t, true, "", false)
|
deployContract(t, true, "")
|
||||||
deployContract(t, false, "Global", false)
|
deployContract(t, false, "Global")
|
||||||
deployContract(t, true, "Global", false)
|
deployContract(t, true, "Global")
|
||||||
deployContract(t, false, "", true)
|
|
||||||
deployContract(t, true, "Global", true)
|
|
||||||
deployContract(t, true, "", true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeployWithSigners(t *testing.T) {
|
func TestDeployWithSigners(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -485,59 +407,62 @@ func TestDeployWithSigners(t *testing.T) {
|
||||||
|
|
||||||
t.Run("missing nef", func(t *testing.T) {
|
t.Run("missing nef", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", "", "--manifest", manifestName)
|
"--in", "", "--manifest", manifestName)
|
||||||
})
|
})
|
||||||
t.Run("missing manifest", func(t *testing.T) {
|
t.Run("missing manifest", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", "")
|
"--in", nefName, "--manifest", "")
|
||||||
})
|
})
|
||||||
t.Run("corrupted data", func(t *testing.T) {
|
t.Run("corrupted data", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"[", "str1")
|
"[", "str1")
|
||||||
})
|
})
|
||||||
t.Run("invalid data", func(t *testing.T) {
|
t.Run("invalid data", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"str1", "str2")
|
"str1", "str2")
|
||||||
})
|
})
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--address", testcli.ValidatorAddr,
|
"--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"[", "str1", "str2", "]")
|
"[", "str1", "str2", "]")
|
||||||
})
|
})
|
||||||
t.Run("missing RPC", func(t *testing.T) {
|
t.Run("missing RPC", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"[", "str1", "str2", "]")
|
"[", "str1", "str2", "]")
|
||||||
})
|
})
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "contract", "deploy",
|
e.Run(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"--force",
|
"--force",
|
||||||
"--", testcli.ValidatorAddr+":Global")
|
"--", validatorAddr+":Global")
|
||||||
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
|
tx, _ := e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
require.Equal(t, transaction.Global, tx.Signers[0].Scopes)
|
require.Equal(t, transaction.Global, tx.Signers[0].Scopes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractManifestGroups(t *testing.T) {
|
func TestContractManifestGroups(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
_, err := wallet.NewWalletFromFile(testcli.TestWalletPath)
|
_, err := wallet.NewWalletFromFile(testWalletPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -556,70 +481,93 @@ func TestContractManifestGroups(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid sender", func(t *testing.T) {
|
t.Run("invalid sender", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testWalletPath, "--address", testWalletAccount,
|
||||||
"--sender", "not-a-sender")
|
"--sender", "not-a-sender")
|
||||||
})
|
})
|
||||||
t.Run("invalid NEF file", func(t *testing.T) {
|
t.Run("invalid NEF file", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testWalletPath, "--address", testWalletAccount,
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", tmpDir)
|
"--sender", testWalletAccount, "--nef", tmpDir)
|
||||||
})
|
})
|
||||||
t.Run("corrupted NEF file", func(t *testing.T) {
|
t.Run("corrupted NEF file", func(t *testing.T) {
|
||||||
f := filepath.Join(tmpDir, "invalid.nef")
|
f := filepath.Join(tmpDir, "invalid.nef")
|
||||||
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testWalletPath, "--address", testWalletAccount,
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", f)
|
"--sender", testWalletAccount, "--nef", f)
|
||||||
})
|
})
|
||||||
t.Run("invalid manifest file", func(t *testing.T) {
|
t.Run("invalid manifest file", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testWalletPath, "--address", testWalletAccount,
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", nefName,
|
"--sender", testWalletAccount, "--nef", nefName,
|
||||||
"--manifest", tmpDir)
|
"--manifest", tmpDir)
|
||||||
})
|
})
|
||||||
t.Run("corrupted manifest file", func(t *testing.T) {
|
t.Run("corrupted manifest file", func(t *testing.T) {
|
||||||
f := filepath.Join(tmpDir, "invalid.manifest.json")
|
f := filepath.Join(tmpDir, "invalid.manifest.json")
|
||||||
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testWalletPath, "--address", testWalletAccount,
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", nefName,
|
"--sender", testWalletAccount, "--nef", nefName,
|
||||||
"--manifest", f)
|
"--manifest", f)
|
||||||
})
|
})
|
||||||
t.Run("unknown account", func(t *testing.T) {
|
t.Run("unknown account", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", util.Uint160{}.StringLE(),
|
"--wallet", testWalletPath, "--address", util.Uint160{}.StringLE(),
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", nefName,
|
"--sender", testWalletAccount, "--nef", nefName,
|
||||||
"--manifest", manifestName)
|
"--manifest", manifestName)
|
||||||
})
|
})
|
||||||
cmd := []string{"neo-go", "contract", "manifest", "add-group",
|
cmd := []string{"neo-go", "contract", "manifest", "add-group",
|
||||||
"--nef", nefName, "--manifest", manifestName}
|
"--nef", nefName, "--manifest", manifestName}
|
||||||
|
|
||||||
t.Run("excessive parameters", func(t *testing.T) {
|
t.Run("excessive parameters", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--wallet", testcli.TestWalletPath,
|
e.RunWithError(t, append(cmd, "--wallet", testWalletPath,
|
||||||
"--sender", testcli.TestWalletAccount, "--address", testcli.TestWalletAccount, "something")...)
|
"--sender", testWalletAccount, "--address", testWalletAccount, "something")...)
|
||||||
})
|
})
|
||||||
e.In.WriteString("testpass\r")
|
e.In.WriteString("testpass\r")
|
||||||
e.Run(t, append(cmd, "--wallet", testcli.TestWalletPath,
|
e.Run(t, append(cmd, "--wallet", testWalletPath,
|
||||||
"--sender", testcli.TestWalletAccount, "--address", testcli.TestWalletAccount)...)
|
"--sender", testWalletAccount, "--address", testWalletAccount)...)
|
||||||
|
|
||||||
e.In.WriteString("testpass\r") // should override signature with the previous sender
|
e.In.WriteString("testpass\r") // should override signature with the previous sender
|
||||||
e.Run(t, append(cmd, "--wallet", testcli.TestWalletPath,
|
e.Run(t, append(cmd, "--wallet", testWalletPath,
|
||||||
"--sender", testcli.ValidatorAddr, "--address", testcli.TestWalletAccount)...)
|
"--sender", validatorAddr, "--address", testWalletAccount)...)
|
||||||
|
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "contract", "deploy",
|
e.Run(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"--force",
|
"--force",
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr)
|
"--wallet", validatorWallet, "--address", validatorAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployVerifyContract(t *testing.T, e *testcli.Executor) util.Uint160 {
|
func deployVerifyContract(t *testing.T, e *executor) util.Uint160 {
|
||||||
return testcli.DeployContract(t, e, "testdata/verify.go", "testdata/verify.yml", testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
return deployContract(t, e, "testdata/verify.go", "testdata/verify.yml", validatorWallet, validatorAddr, "one")
|
||||||
|
}
|
||||||
|
|
||||||
|
func deployContract(t *testing.T, e *executor, inPath, configPath, wallet, address, pass string) util.Uint160 {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
nefName := filepath.Join(tmpDir, "contract.nef")
|
||||||
|
manifestName := filepath.Join(tmpDir, "contract.manifest.json")
|
||||||
|
e.Run(t, "neo-go", "contract", "compile",
|
||||||
|
"--in", inPath,
|
||||||
|
"--config", configPath,
|
||||||
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
e.In.WriteString(pass + "\r")
|
||||||
|
e.Run(t, "neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wallet, "--address", address,
|
||||||
|
"--force",
|
||||||
|
"--in", nefName, "--manifest", manifestName)
|
||||||
|
e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
|
line, err := e.Out.ReadString('\n')
|
||||||
|
require.NoError(t, err)
|
||||||
|
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
||||||
|
h, err := util.Uint160DecodeStringLE(line)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContract_TestInvokeScript(t *testing.T) {
|
func TestContract_TestInvokeScript(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
badNef := filepath.Join(tmpDir, "invalid.nef")
|
badNef := filepath.Join(tmpDir, "invalid.nef")
|
||||||
goodNef := filepath.Join(tmpDir, "deploy.nef")
|
goodNef := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -631,22 +579,22 @@ func TestContract_TestInvokeScript(t *testing.T) {
|
||||||
|
|
||||||
t.Run("missing in", func(t *testing.T) {
|
t.Run("missing in", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||||
})
|
})
|
||||||
t.Run("unexisting in", func(t *testing.T) {
|
t.Run("unexisting in", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--in", badNef)
|
"--in", badNef)
|
||||||
})
|
})
|
||||||
t.Run("invalid nef", func(t *testing.T) {
|
t.Run("invalid nef", func(t *testing.T) {
|
||||||
require.NoError(t, os.WriteFile(badNef, []byte("qwer"), os.ModePerm))
|
require.NoError(t, os.WriteFile(badNef, []byte("qwer"), os.ModePerm))
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--in", badNef)
|
"--in", badNef)
|
||||||
})
|
})
|
||||||
t.Run("invalid signers", func(t *testing.T) {
|
t.Run("invalid signers", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--in", goodNef, "--", "not-a-valid-signer")
|
"--in", goodNef, "--", "not-a-valid-signer")
|
||||||
})
|
})
|
||||||
t.Run("no RPC endpoint", func(t *testing.T) {
|
t.Run("no RPC endpoint", func(t *testing.T) {
|
||||||
|
@ -654,43 +602,13 @@ func TestContract_TestInvokeScript(t *testing.T) {
|
||||||
"--rpc-endpoint", "http://123456789",
|
"--rpc-endpoint", "http://123456789",
|
||||||
"--in", goodNef)
|
"--in", goodNef)
|
||||||
})
|
})
|
||||||
t.Run("good", func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--in", goodNef)
|
|
||||||
})
|
|
||||||
t.Run("good with hashed signer", func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--in", goodNef, "--", util.Uint160{1, 2, 3}.StringLE())
|
|
||||||
})
|
|
||||||
t.Run("good with addressed signer", func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--in", goodNef, "--", address.Uint160ToString(util.Uint160{1, 2, 3}))
|
|
||||||
})
|
|
||||||
t.Run("historic, invalid", func(t *testing.T) {
|
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--historic", "bad",
|
|
||||||
"--in", goodNef)
|
|
||||||
})
|
|
||||||
t.Run("historic, index", func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--historic", "0",
|
|
||||||
"--in", goodNef)
|
|
||||||
})
|
|
||||||
t.Run("historic, hash", func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--historic", e.Chain.GetHeaderHash(0).StringLE(),
|
|
||||||
"--in", goodNef)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComlileAndInvokeFunction(t *testing.T) {
|
func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -700,21 +618,31 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
|
// Check that it is possible to invoke before deploy.
|
||||||
|
// This doesn't make much sense, because every method has an offset
|
||||||
|
// which is contained in the manifest. This should be either removed or refactored.
|
||||||
|
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--in", nefName, "--", util.Uint160{1, 2, 3}.StringLE())
|
||||||
|
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--in", nefName, "--", address.Uint160ToString(util.Uint160{1, 2, 3}))
|
||||||
|
|
||||||
tmp := t.TempDir()
|
tmp := t.TempDir()
|
||||||
configPath := filepath.Join(tmp, "config.yaml")
|
configPath := filepath.Join(tmp, "config.yaml")
|
||||||
cfg := config.Wallet{
|
cfg := config.Wallet{
|
||||||
Path: testcli.ValidatorWallet,
|
Path: validatorWallet,
|
||||||
Password: testcli.ValidatorPass,
|
Password: "one",
|
||||||
}
|
}
|
||||||
yml, err := yaml.Marshal(cfg)
|
yml, err := yaml.Marshal(cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, os.WriteFile(configPath, yml, 0666))
|
require.NoError(t, os.WriteFile(configPath, yml, 0666))
|
||||||
e.Run(t, "neo-go", "contract", "deploy",
|
e.Run(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--force",
|
"--rpc-endpoint", "http://"+e.RPC.Addr, "--force",
|
||||||
"--wallet-config", configPath, "--address", testcli.ValidatorAddr,
|
"--wallet-config", configPath, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName)
|
"--in", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
e.CheckTxPersisted(t, "Sent invocation transaction ")
|
e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
line, err := e.Out.ReadString('\n')
|
line, err := e.Out.ReadString('\n')
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
||||||
|
@ -728,13 +656,13 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
"--manifest", manifestName)
|
"--manifest", manifestName)
|
||||||
|
|
||||||
e.Run(t, "neo-go", "contract", "calc-hash",
|
e.Run(t, "neo-go", "contract", "calc-hash",
|
||||||
"--sender", testcli.ValidatorAddr, "--in", nefName,
|
"--sender", validatorAddr, "--in", nefName,
|
||||||
"--manifest", manifestName)
|
"--manifest", manifestName)
|
||||||
e.CheckNextLine(t, h.StringLE())
|
e.checkNextLine(t, h.StringLE())
|
||||||
})
|
})
|
||||||
|
|
||||||
cmd := []string{"neo-go", "contract", "testinvokefunction",
|
cmd := []string{"neo-go", "contract", "testinvokefunction",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0]}
|
"--rpc-endpoint", "http://" + e.RPC.Addr}
|
||||||
t.Run("missing hash", func(t *testing.T) {
|
t.Run("missing hash", func(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
})
|
})
|
||||||
|
@ -761,21 +689,18 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
|
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
|
|
||||||
checkGetValueOut := func(str string) {
|
res := new(result.Invoke)
|
||||||
res := new(result.Invoke)
|
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
require.Len(t, res.Stack, 1)
|
||||||
require.Len(t, res.Stack, 1)
|
require.Equal(t, []byte("on create|sub create"), res.Stack[0].Value())
|
||||||
require.Equal(t, []byte(str), res.Stack[0].Value())
|
|
||||||
}
|
|
||||||
checkGetValueOut("on create|sub create")
|
|
||||||
|
|
||||||
// deploy verification contract
|
// deploy verification contract
|
||||||
hVerify := deployVerifyContract(t, e)
|
hVerify := deployVerifyContract(t, e)
|
||||||
|
|
||||||
t.Run("real invoke", func(t *testing.T) {
|
t.Run("real invoke", func(t *testing.T) {
|
||||||
cmd := []string{"neo-go", "contract", "invokefunction",
|
cmd := []string{"neo-go", "contract", "invokefunction",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0]}
|
"--rpc-endpoint", "http://" + e.RPC.Addr}
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
cmd := append(cmd, h.StringLE(), "getValue")
|
cmd := append(cmd, h.StringLE(), "getValue")
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
|
@ -795,28 +720,28 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
})
|
})
|
||||||
t.Run("non-existent address", func(t *testing.T) {
|
t.Run("non-existent address", func(t *testing.T) {
|
||||||
cmd := append(cmd, "--wallet", testcli.ValidatorWallet,
|
cmd := append(cmd, "--wallet", validatorWallet,
|
||||||
"--address", random.Uint160().StringLE(),
|
"--address", random.Uint160().StringLE(),
|
||||||
h.StringLE(), "getValue")
|
h.StringLE(), "getValue")
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
})
|
})
|
||||||
t.Run("invalid password", func(t *testing.T) {
|
t.Run("invalid password", func(t *testing.T) {
|
||||||
e.In.WriteString("invalid_password\r")
|
e.In.WriteString("invalid_password\r")
|
||||||
cmd := append(cmd, "--wallet", testcli.ValidatorWallet,
|
cmd := append(cmd, "--wallet", validatorWallet,
|
||||||
h.StringLE(), "getValue")
|
h.StringLE(), "getValue")
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
})
|
})
|
||||||
t.Run("good: default address", func(t *testing.T) {
|
t.Run("good: default address", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.In.WriteString("y\r")
|
e.In.WriteString("y\r")
|
||||||
e.Run(t, append(cmd, "--wallet", testcli.ValidatorWallet, h.StringLE(), "getValue")...)
|
e.Run(t, append(cmd, "--wallet", validatorWallet, h.StringLE(), "getValue")...)
|
||||||
})
|
})
|
||||||
t.Run("good: from wallet config", func(t *testing.T) {
|
t.Run("good: from wallet config", func(t *testing.T) {
|
||||||
e.In.WriteString("y\r")
|
e.In.WriteString("y\r")
|
||||||
e.Run(t, append(cmd, "--wallet-config", configPath, h.StringLE(), "getValue")...)
|
e.Run(t, append(cmd, "--wallet-config", configPath, h.StringLE(), "getValue")...)
|
||||||
})
|
})
|
||||||
|
|
||||||
cmd = append(cmd, "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr)
|
cmd = append(cmd, "--wallet", validatorWallet, "--address", validatorAddr)
|
||||||
t.Run("cancelled", func(t *testing.T) {
|
t.Run("cancelled", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.In.WriteString("n\r")
|
e.In.WriteString("n\r")
|
||||||
|
@ -841,13 +766,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.In.WriteString("y\r")
|
e.In.WriteString("y\r")
|
||||||
e.Run(t, append(cmd, h.StringLE(), "getValue",
|
e.Run(t, append(cmd, h.StringLE(), "getValue",
|
||||||
"--", testcli.ValidatorAddr, hVerify.StringLE())...)
|
"--", 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)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -855,9 +774,9 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
txout := filepath.Join(tmpDir, "test_contract_tx.json")
|
txout := filepath.Join(tmpDir, "test_contract_tx.json")
|
||||||
|
|
||||||
cmd = []string{"neo-go", "contract", "invokefunction",
|
cmd = []string{"neo-go", "contract", "invokefunction",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--out", txout,
|
"--out", txout,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("without cosigner", func(t *testing.T) {
|
t.Run("without cosigner", func(t *testing.T) {
|
||||||
|
@ -868,22 +787,22 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
t.Run("with cosigner", func(t *testing.T) {
|
t.Run("with cosigner", func(t *testing.T) {
|
||||||
t.Run("cosigner is sender (none)", func(t *testing.T) {
|
t.Run("cosigner is sender (none)", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.RunWithError(t, append(cmd, h.StringLE(), "checkSenderWitness", "--", testcli.ValidatorAddr+":None")...)
|
e.RunWithError(t, append(cmd, h.StringLE(), "checkSenderWitness", "--", validatorAddr+":None")...)
|
||||||
})
|
})
|
||||||
t.Run("cosigner is sender (customcontract)", func(t *testing.T) {
|
t.Run("cosigner is sender (customcontract)", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(cmd, h.StringLE(), "checkSenderWitness", "--", testcli.ValidatorAddr+":CustomContracts:"+h.StringLE())...)
|
e.Run(t, append(cmd, h.StringLE(), "checkSenderWitness", "--", validatorAddr+":CustomContracts:"+h.StringLE())...)
|
||||||
})
|
})
|
||||||
t.Run("cosigner is sender (global)", func(t *testing.T) {
|
t.Run("cosigner is sender (global)", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(cmd, h.StringLE(), "checkSenderWitness", "--", testcli.ValidatorAddr+":Global")...)
|
e.Run(t, append(cmd, h.StringLE(), "checkSenderWitness", "--", validatorAddr+":Global")...)
|
||||||
})
|
})
|
||||||
|
|
||||||
acc, err := wallet.NewAccount()
|
acc, err := wallet.NewAccount()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pk, err := keys.NewPrivateKey()
|
pk, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = acc.ConvertMultisig(2, keys.PublicKeys{acc.PublicKey(), pk.PublicKey()})
|
err = acc.ConvertMultisig(2, keys.PublicKeys{acc.PrivateKey().PublicKey(), pk.PublicKey()})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("cosigner is multisig account", func(t *testing.T) {
|
t.Run("cosigner is multisig account", func(t *testing.T) {
|
||||||
|
@ -894,7 +813,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
|
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(cmd, hVerify.StringLE(), "verify", "--", testcli.MultisigAddr)...)
|
e.Run(t, append(cmd, hVerify.StringLE(), "verify", "--", multisigAddr)...)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -914,7 +833,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
|
|
||||||
t.Run("test Storage.Find", func(t *testing.T) {
|
t.Run("test Storage.Find", func(t *testing.T) {
|
||||||
cmd := []string{"neo-go", "contract", "testinvokefunction",
|
cmd := []string{"neo-go", "contract", "testinvokefunction",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
h.StringLE(), "testFind"}
|
h.StringLE(), "testFind"}
|
||||||
|
|
||||||
t.Run("keys only", func(t *testing.T) {
|
t.Run("keys only", func(t *testing.T) {
|
||||||
|
@ -947,12 +866,6 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
var (
|
|
||||||
hashBeforeUpdate util.Uint256
|
|
||||||
indexBeforeUpdate uint32
|
|
||||||
indexAfterUpdate uint32
|
|
||||||
stateBeforeUpdate util.Uint256
|
|
||||||
)
|
|
||||||
t.Run("Update", func(t *testing.T) {
|
t.Run("Update", func(t *testing.T) {
|
||||||
nefName := filepath.Join(tmpDir, "updated.nef")
|
nefName := filepath.Join(tmpDir, "updated.nef")
|
||||||
manifestName := filepath.Join(tmpDir, "updated.manifest.json")
|
manifestName := filepath.Join(tmpDir, "updated.manifest.json")
|
||||||
|
@ -971,61 +884,35 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
rawManifest, err := os.ReadFile(manifestName)
|
rawManifest, err := os.ReadFile(manifestName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
indexBeforeUpdate = e.Chain.BlockHeight()
|
|
||||||
hashBeforeUpdate = e.Chain.CurrentHeaderHash()
|
|
||||||
mptBeforeUpdate, err := e.Chain.GetStateRoot(indexBeforeUpdate)
|
|
||||||
require.NoError(t, err)
|
|
||||||
stateBeforeUpdate = mptBeforeUpdate.Root
|
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
h.StringLE(), "update",
|
h.StringLE(), "update",
|
||||||
"bytes:"+hex.EncodeToString(rawNef),
|
"bytes:"+hex.EncodeToString(rawNef),
|
||||||
"bytes:"+hex.EncodeToString(rawManifest),
|
"bytes:"+hex.EncodeToString(rawManifest),
|
||||||
)
|
)
|
||||||
e.CheckTxPersisted(t, "Sent invocation transaction ")
|
e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
|
|
||||||
indexAfterUpdate = e.Chain.BlockHeight()
|
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
h.StringLE(), "getValue")
|
h.StringLE(), "getValue")
|
||||||
checkGetValueOut("on update|sub update")
|
|
||||||
})
|
res := new(result.Invoke)
|
||||||
t.Run("historic", func(t *testing.T) {
|
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||||
t.Run("bad ref", func(t *testing.T) {
|
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokefunction",
|
require.Len(t, res.Stack, 1)
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
require.Equal(t, []byte("on update|sub update"), res.Stack[0].Value())
|
||||||
"--historic", "bad",
|
|
||||||
h.StringLE(), "getValue")
|
|
||||||
})
|
|
||||||
for name, ref := range map[string]string{
|
|
||||||
"by index": strconv.FormatUint(uint64(indexBeforeUpdate), 10),
|
|
||||||
"by block hash": hashBeforeUpdate.StringLE(),
|
|
||||||
"by state hash": stateBeforeUpdate.StringLE(),
|
|
||||||
} {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--historic", ref,
|
|
||||||
h.StringLE(), "getValue")
|
|
||||||
})
|
|
||||||
checkGetValueOut("on create|sub create")
|
|
||||||
}
|
|
||||||
t.Run("updated historic", func(t *testing.T) {
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--historic", strconv.FormatUint(uint64(indexAfterUpdate), 10),
|
|
||||||
h.StringLE(), "getValue")
|
|
||||||
checkGetValueOut("on update|sub update")
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractInspect(t *testing.T) {
|
func TestContractInspect(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
const srcPath = "testdata/deploy/main.go"
|
const srcPath = "testdata/deploy/main.go"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
@ -1056,11 +943,14 @@ func TestContractInspect(t *testing.T) {
|
||||||
|
|
||||||
func TestCompileExamples(t *testing.T) {
|
func TestCompileExamples(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
const examplePath = "../../examples"
|
const examplePath = "../examples"
|
||||||
infos, err := os.ReadDir(examplePath)
|
infos, err := os.ReadDir(examplePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
e := testcli.NewExecutor(t, false)
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
|
|
||||||
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
if !info.IsDir() {
|
if !info.IsDir() {
|
||||||
|
@ -1068,10 +958,6 @@ func TestCompileExamples(t *testing.T) {
|
||||||
// there are also a couple of files inside the `/examples` which doesn't need to be compiled
|
// there are also a couple of files inside the `/examples` which doesn't need to be compiled
|
||||||
continue
|
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) {
|
t.Run(info.Name(), func(t *testing.T) {
|
||||||
infos, err := os.ReadDir(filepath.Join(examplePath, info.Name()))
|
infos, err := os.ReadDir(filepath.Join(examplePath, info.Name()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -1079,9 +965,6 @@ func TestCompileExamples(t *testing.T) {
|
||||||
|
|
||||||
outF := filepath.Join(tmpDir, info.Name()+".nef")
|
outF := filepath.Join(tmpDir, info.Name()+".nef")
|
||||||
manifestF := filepath.Join(tmpDir, info.Name()+".manifest.json")
|
manifestF := filepath.Join(tmpDir, info.Name()+".manifest.json")
|
||||||
bindingF := filepath.Join(tmpDir, info.Name()+".binding.yml")
|
|
||||||
wrapperF := filepath.Join(tmpDir, info.Name()+".go")
|
|
||||||
rpcWrapperF := filepath.Join(tmpDir, info.Name()+".rpc.go")
|
|
||||||
|
|
||||||
cfgName := filterFilename(infos, ".yml")
|
cfgName := filterFilename(infos, ".yml")
|
||||||
opts := []string{
|
opts := []string{
|
||||||
|
@ -1090,7 +973,6 @@ func TestCompileExamples(t *testing.T) {
|
||||||
"--out", outF,
|
"--out", outF,
|
||||||
"--manifest", manifestF,
|
"--manifest", manifestF,
|
||||||
"--config", filepath.Join(examplePath, info.Name(), cfgName),
|
"--config", filepath.Join(examplePath, info.Name(), cfgName),
|
||||||
"--bindings", bindingF,
|
|
||||||
}
|
}
|
||||||
e.Run(t, opts...)
|
e.Run(t, opts...)
|
||||||
|
|
||||||
|
@ -1109,16 +991,6 @@ func TestCompileExamples(t *testing.T) {
|
||||||
require.NotNil(t, m.ABI.GetMethod("put", 1))
|
require.NotNil(t, m.ABI.GetMethod("put", 1))
|
||||||
require.NotNil(t, m.ABI.GetMethod("put", 2))
|
require.NotNil(t, m.ABI.GetMethod("put", 2))
|
||||||
}
|
}
|
||||||
e.Run(t, "neo-go", "contract", "generate-wrapper",
|
|
||||||
"--manifest", manifestF,
|
|
||||||
"--config", bindingF,
|
|
||||||
"--out", wrapperF,
|
|
||||||
"--hash", "0x00112233445566778899aabbccddeeff00112233")
|
|
||||||
e.Run(t, "neo-go", "contract", "generate-rpcwrapper",
|
|
||||||
"--manifest", manifestF,
|
|
||||||
"--config", bindingF,
|
|
||||||
"--out", rpcWrapperF,
|
|
||||||
"--hash", "0x00112233445566778899aabbccddeeff00112233")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,27 +1020,3 @@ func filterFilename(infos []os.DirEntry, ext string) string {
|
||||||
}
|
}
|
||||||
return ""
|
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"))
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package server_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
@ -6,24 +6,19 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// generated via `go run ./scripts/gendump/main.go --out ./cli/server/testdata/chain50x2.acc --blocks 50 --txs 2`.
|
|
||||||
const inDump = "./testdata/chain50x2.acc"
|
|
||||||
|
|
||||||
func TestDBRestoreDump(t *testing.T) {
|
func TestDBRestoreDump(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
loadConfig := func(t *testing.T) config.Config {
|
loadConfig := func(t *testing.T) config.Config {
|
||||||
chainPath := filepath.Join(tmpDir, "neogotestchain")
|
chainPath := filepath.Join(tmpDir, "neogotestchain")
|
||||||
cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
|
cfg, err := config.LoadFile(filepath.Join("..", "config", "protocol.unit_testnet.yml"))
|
||||||
require.NoError(t, err, "could not load config")
|
require.NoError(t, err, "could not load config")
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
|
cfg.ApplicationConfiguration.DBConfiguration.Type = "leveldb"
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
@ -35,7 +30,9 @@ func TestDBRestoreDump(t *testing.T) {
|
||||||
cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml")
|
cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml")
|
||||||
require.NoError(t, os.WriteFile(cfgPath, out, os.ModePerm))
|
require.NoError(t, os.WriteFile(cfgPath, out, os.ModePerm))
|
||||||
|
|
||||||
e := testcli.NewExecutor(t, false)
|
// generated via `go run ./scripts/gendump/main.go --out ./cli/testdata/chain50x2.acc --blocks 50 --txs 2`
|
||||||
|
const inDump = "./testdata/chain50x2.acc"
|
||||||
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
stateDump := filepath.Join(tmpDir, "neogo.teststate")
|
stateDump := filepath.Join(tmpDir, "neogo.teststate")
|
||||||
baseArgs := []string{"neo-go", "db", "restore", "--unittest",
|
baseArgs := []string{"neo-go", "db", "restore", "--unittest",
|
||||||
|
@ -112,47 +109,3 @@ func TestDBRestoreDump(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, d1, d2, "dumps differ")
|
require.Equal(t, d1, d2, "dumps differ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBDumpRestoreIncremental(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
chainPath := filepath.Join(tmpDir, "neogotestchain")
|
|
||||||
nonincDump := filepath.Join(tmpDir, "nonincDump.acc")
|
|
||||||
incDump := filepath.Join(tmpDir, "incDump.acc")
|
|
||||||
|
|
||||||
cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
|
|
||||||
require.NoError(t, err, "could not load config")
|
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
|
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
|
||||||
out, err := yaml.Marshal(cfg)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml")
|
|
||||||
require.NoError(t, os.WriteFile(cfgPath, out, os.ModePerm))
|
|
||||||
|
|
||||||
e := testcli.NewExecutor(t, false)
|
|
||||||
|
|
||||||
// Create DB from dump.
|
|
||||||
e.Run(t, "neo-go", "db", "restore", "--unittest", "--config-path", tmpDir, "--in", inDump)
|
|
||||||
|
|
||||||
// Create two dumps: non-incremental and incremental.
|
|
||||||
dumpBaseArgs := []string{"neo-go", "db", "dump", "--unittest",
|
|
||||||
"--config-path", tmpDir}
|
|
||||||
|
|
||||||
// Dump first 15 blocks to a non-incremental dump.
|
|
||||||
e.Run(t, append(dumpBaseArgs, "--out", nonincDump, "--count", "15")...)
|
|
||||||
|
|
||||||
// Dump second 15 blocks to an incremental dump.
|
|
||||||
e.Run(t, append(dumpBaseArgs, "--out", incDump, "--start", "15", "--count", "15")...)
|
|
||||||
|
|
||||||
// Clean the DB.
|
|
||||||
require.NoError(t, os.RemoveAll(chainPath))
|
|
||||||
|
|
||||||
// Restore chain from two dumps.
|
|
||||||
restoreBaseArgs := []string{"neo-go", "db", "restore", "--unittest", "--config-path", tmpDir}
|
|
||||||
|
|
||||||
// Restore first 15 blocks from non-incremental dump.
|
|
||||||
e.Run(t, append(restoreBaseArgs, "--in", nonincDump)...)
|
|
||||||
|
|
||||||
// Restore second 15 blocks from incremental dump.
|
|
||||||
e.Run(t, append(restoreBaseArgs, "--in", incDump, "-n", "--count", "15")...)
|
|
||||||
}
|
|
|
@ -1,11 +1,4 @@
|
||||||
/*
|
package main
|
||||||
Package testcli contains auxiliary code to test CLI commands.
|
|
||||||
|
|
||||||
All testdata assets for it are contained in the cli directory and paths here
|
|
||||||
use `../` prefix to reference them because the package itself is used from
|
|
||||||
cli/* subpackages.
|
|
||||||
*/
|
|
||||||
package testcli
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -13,13 +6,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/app"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/consensus"
|
"github.com/nspcc-dev/neo-go/pkg/consensus"
|
||||||
|
@ -41,34 +32,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ValidatorWIF = "KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY"
|
validatorWIF = "KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY"
|
||||||
ValidatorAddr = "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP"
|
validatorAddr = "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP"
|
||||||
MultisigAddr = "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq"
|
multisigAddr = "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq"
|
||||||
|
|
||||||
TestWalletPath = "../testdata/testwallet.json"
|
testWalletPath = "testdata/testwallet.json"
|
||||||
TestWalletAccount = "Nfyz4KcsgYepRJw1W5C2uKCi6QWKf7v6gG"
|
testWalletAccount = "Nfyz4KcsgYepRJw1W5C2uKCi6QWKf7v6gG"
|
||||||
|
|
||||||
TestWalletMultiPath = "../testdata/testwallet_multi.json"
|
validatorWallet = "testdata/wallet1_solo.json"
|
||||||
TestWalletMultiAccount1 = "NgHcPxgEKZQV4QBedzyASJrgiANhJqBVLw"
|
validatorPass = "one"
|
||||||
TestWalletMultiAccount2 = "NLvHRfKAifjio2z9HiwLo9ZnpRPHUbAHgH"
|
|
||||||
TestWalletMultiAccount3 = "NcDfG8foJx79XSihcDDrx1df7cHAoJBfXj"
|
|
||||||
|
|
||||||
ValidatorWallet = "../testdata/wallet1_solo.json"
|
|
||||||
ValidatorPass = "one"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ValidatorHash, _ = address.StringToUint160(ValidatorAddr)
|
validatorHash, _ = address.StringToUint160(validatorAddr)
|
||||||
ValidatorPriv, _ = keys.NewPrivateKeyFromWIF(ValidatorWIF)
|
validatorPriv, _ = keys.NewPrivateKeyFromWIF(validatorWIF)
|
||||||
|
|
||||||
TestWalletMultiAccount1Hash, _ = address.StringToUint160(TestWalletMultiAccount1)
|
|
||||||
TestWalletMultiAccount2Hash, _ = address.StringToUint160(TestWalletMultiAccount2)
|
|
||||||
TestWalletMultiAccount3Hash, _ = address.StringToUint160(TestWalletMultiAccount3)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Executor represents context for a test instance.
|
// executor represents context for a test instance.
|
||||||
// It can be safely used in multiple tests, but not in parallel.
|
// It can be safely used in multiple tests, but not in parallel.
|
||||||
type Executor struct {
|
type executor struct {
|
||||||
// CLI is a cli application to test.
|
// CLI is a cli application to test.
|
||||||
CLI *cli.App
|
CLI *cli.App
|
||||||
// Chain is a blockchain instance (can be empty).
|
// Chain is a blockchain instance (can be empty).
|
||||||
|
@ -138,8 +120,8 @@ func (w *ConcurrentBuffer) Reset() {
|
||||||
w.buf.Reset()
|
w.buf.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockchain, *rpcsrv.Server, *network.Server) {
|
func newTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockchain, *rpcsrv.Server, *network.Server) {
|
||||||
configPath := "../../config/protocol.unit_testnet.single.yml"
|
configPath := "../config/protocol.unit_testnet.single.yml"
|
||||||
cfg, err := config.LoadFile(configPath)
|
cfg, err := config.LoadFile(configPath)
|
||||||
require.NoError(t, err, "could not load config")
|
require.NoError(t, err, "could not load config")
|
||||||
if f != nil {
|
if f != nil {
|
||||||
|
@ -148,15 +130,14 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
|
||||||
|
|
||||||
memoryStore := storage.NewMemoryStore()
|
memoryStore := storage.NewMemoryStore()
|
||||||
logger := zaptest.NewLogger(t)
|
logger := zaptest.NewLogger(t)
|
||||||
chain, err := core.NewBlockchain(memoryStore, cfg.Blockchain(), logger)
|
chain, err := core.NewBlockchain(memoryStore, cfg.ProtocolConfiguration, logger)
|
||||||
require.NoError(t, err, "could not create chain")
|
require.NoError(t, err, "could not create chain")
|
||||||
|
|
||||||
if run {
|
if run {
|
||||||
go chain.Run()
|
go chain.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig, err := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
require.NoError(t, err)
|
|
||||||
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.3-test")
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.3-test")
|
||||||
netSrv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), zap.NewNop())
|
netSrv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), zap.NewNop())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -164,16 +145,14 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
|
||||||
Logger: zap.NewNop(),
|
Logger: zap.NewNop(),
|
||||||
Broadcast: netSrv.BroadcastExtensible,
|
Broadcast: netSrv.BroadcastExtensible,
|
||||||
Chain: chain,
|
Chain: chain,
|
||||||
BlockQueue: netSrv.GetBlockQueue(),
|
ProtocolConfiguration: chain.GetConfig(),
|
||||||
ProtocolConfiguration: cfg.ProtocolConfiguration,
|
|
||||||
RequestTx: netSrv.RequestTx,
|
RequestTx: netSrv.RequestTx,
|
||||||
StopTxFlow: netSrv.StopTxFlow,
|
Wallet: &cfg.ApplicationConfiguration.UnlockWallet,
|
||||||
Wallet: cfg.ApplicationConfiguration.Consensus.UnlockWallet,
|
|
||||||
TimePerBlock: serverConfig.TimePerBlock,
|
TimePerBlock: serverConfig.TimePerBlock,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
netSrv.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
|
netSrv.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
|
||||||
netSrv.Start()
|
go netSrv.Start(make(chan error, 1))
|
||||||
errCh := make(chan error, 2)
|
errCh := make(chan error, 2)
|
||||||
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, netSrv, nil, logger, errCh)
|
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, netSrv, nil, logger, errCh)
|
||||||
rpcServer.Start()
|
rpcServer.Start()
|
||||||
|
@ -181,17 +160,17 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
|
||||||
return chain, &rpcServer, netSrv
|
return chain, &rpcServer, netSrv
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExecutor(t *testing.T, needChain bool) *Executor {
|
func newExecutor(t *testing.T, needChain bool) *executor {
|
||||||
return NewExecutorWithConfig(t, needChain, true, nil)
|
return newExecutorWithConfig(t, needChain, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExecutorSuspended(t *testing.T) *Executor {
|
func newExecutorSuspended(t *testing.T) *executor {
|
||||||
return NewExecutorWithConfig(t, true, false, nil)
|
return newExecutorWithConfig(t, true, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExecutorWithConfig(t *testing.T, needChain, runChain bool, f func(*config.Config)) *Executor {
|
func newExecutorWithConfig(t *testing.T, needChain, runChain bool, f func(*config.Config)) *executor {
|
||||||
e := &Executor{
|
e := &executor{
|
||||||
CLI: app.New(),
|
CLI: newApp(),
|
||||||
Out: NewConcurrentBuffer(),
|
Out: NewConcurrentBuffer(),
|
||||||
Err: bytes.NewBuffer(nil),
|
Err: bytes.NewBuffer(nil),
|
||||||
In: bytes.NewBuffer(nil),
|
In: bytes.NewBuffer(nil),
|
||||||
|
@ -199,7 +178,7 @@ func NewExecutorWithConfig(t *testing.T, needChain, runChain bool, f func(*confi
|
||||||
e.CLI.Writer = e.Out
|
e.CLI.Writer = e.Out
|
||||||
e.CLI.ErrWriter = e.Err
|
e.CLI.ErrWriter = e.Err
|
||||||
if needChain {
|
if needChain {
|
||||||
e.Chain, e.RPC, e.NetSrv = NewTestChain(t, f, runChain)
|
e.Chain, e.RPC, e.NetSrv = newTestChain(t, f, runChain)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
e.Close(t)
|
e.Close(t)
|
||||||
|
@ -207,7 +186,7 @@ func NewExecutorWithConfig(t *testing.T, needChain, runChain bool, f func(*confi
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) Close(t *testing.T) {
|
func (e *executor) Close(t *testing.T) {
|
||||||
input.Terminal = nil
|
input.Terminal = nil
|
||||||
if e.RPC != nil {
|
if e.RPC != nil {
|
||||||
e.RPC.Shutdown()
|
e.RPC.Shutdown()
|
||||||
|
@ -223,7 +202,7 @@ func (e *Executor) Close(t *testing.T) {
|
||||||
// GetTransaction returns tx with hash h after it has persisted.
|
// GetTransaction returns tx with hash h after it has persisted.
|
||||||
// If it is in mempool, we can just wait for the next block, otherwise
|
// If it is in mempool, we can just wait for the next block, otherwise
|
||||||
// it must be already in chain. 1 second is time per block in a unittest chain.
|
// it must be already in chain. 1 second is time per block in a unittest chain.
|
||||||
func (e *Executor) GetTransaction(t *testing.T, h util.Uint256) (*transaction.Transaction, uint32) {
|
func (e *executor) GetTransaction(t *testing.T, h util.Uint256) (*transaction.Transaction, uint32) {
|
||||||
var tx *transaction.Transaction
|
var tx *transaction.Transaction
|
||||||
var height uint32
|
var height uint32
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
|
@ -234,22 +213,22 @@ func (e *Executor) GetTransaction(t *testing.T, h util.Uint256) (*transaction.Tr
|
||||||
return tx, height
|
return tx, height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) GetNextLine(t *testing.T) string {
|
func (e *executor) getNextLine(t *testing.T) string {
|
||||||
line, err := e.Out.ReadString('\n')
|
line, err := e.Out.ReadString('\n')
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return strings.TrimSuffix(line, "\n")
|
return strings.TrimSuffix(line, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) CheckNextLine(t *testing.T, expected string) {
|
func (e *executor) checkNextLine(t *testing.T, expected string) {
|
||||||
line := e.GetNextLine(t)
|
line := e.getNextLine(t)
|
||||||
e.CheckLine(t, line, expected)
|
e.checkLine(t, line, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) CheckLine(t *testing.T, line, expected string) {
|
func (e *executor) checkLine(t *testing.T, line, expected string) {
|
||||||
require.Regexp(t, expected, line)
|
require.Regexp(t, expected, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) CheckEOF(t *testing.T) {
|
func (e *executor) checkEOF(t *testing.T) {
|
||||||
_, err := e.Out.ReadString('\n')
|
_, err := e.Out.ReadString('\n')
|
||||||
require.True(t, errors.Is(err, io.EOF))
|
require.True(t, errors.Is(err, io.EOF))
|
||||||
}
|
}
|
||||||
|
@ -274,33 +253,19 @@ func checkExit(t *testing.T, ch <-chan int, code int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunWithError runs command and checks that is exits with error.
|
// RunWithError runs command and checks that is exits with error.
|
||||||
func (e *Executor) RunWithError(t *testing.T, args ...string) {
|
func (e *executor) RunWithError(t *testing.T, args ...string) {
|
||||||
ch := setExitFunc()
|
ch := setExitFunc()
|
||||||
require.Error(t, e.run(args...))
|
require.Error(t, e.run(args...))
|
||||||
checkExit(t, ch, 1)
|
checkExit(t, ch, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs command and checks that there were no errors.
|
// Run runs command and checks that there were no errors.
|
||||||
func (e *Executor) Run(t *testing.T, args ...string) {
|
func (e *executor) Run(t *testing.T, args ...string) {
|
||||||
ch := setExitFunc()
|
ch := setExitFunc()
|
||||||
require.NoError(t, e.run(args...))
|
require.NoError(t, e.run(args...))
|
||||||
checkExit(t, ch, 0)
|
checkExit(t, ch, 0)
|
||||||
}
|
}
|
||||||
|
func (e *executor) run(args ...string) error {
|
||||||
// RunUnchecked runs command and ensures that proper exit code is set (0 if no error is returned, 1 is an error is returned).
|
|
||||||
// The resulting error is returned (if so).
|
|
||||||
func (e *Executor) RunUnchecked(t *testing.T, args ...string) error {
|
|
||||||
ch := setExitFunc()
|
|
||||||
err := e.run(args...)
|
|
||||||
if err != nil {
|
|
||||||
checkExit(t, ch, 1)
|
|
||||||
} else {
|
|
||||||
checkExit(t, ch, 0)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) run(args ...string) error {
|
|
||||||
e.Out.Reset()
|
e.Out.Reset()
|
||||||
e.Err.Reset()
|
e.Err.Reset()
|
||||||
input.Terminal = term.NewTerminal(input.ReadWriter{
|
input.Terminal = term.NewTerminal(input.ReadWriter{
|
||||||
|
@ -313,7 +278,7 @@ func (e *Executor) run(args ...string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) CheckTxPersisted(t *testing.T, prefix ...string) (*transaction.Transaction, uint32) {
|
func (e *executor) checkTxPersisted(t *testing.T, prefix ...string) (*transaction.Transaction, uint32) {
|
||||||
line, err := e.Out.ReadString('\n')
|
line, err := e.Out.ReadString('\n')
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -332,14 +297,7 @@ func (e *Executor) CheckTxPersisted(t *testing.T, prefix ...string) (*transactio
|
||||||
return tx, height
|
return tx, height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) CheckAwaitableTxPersisted(t *testing.T, prefix ...string) (*transaction.Transaction, uint32) {
|
func generateKeys(t *testing.T, n int) ([]*keys.PrivateKey, keys.PublicKeys) {
|
||||||
tx, vub := e.CheckTxPersisted(t, prefix...)
|
|
||||||
e.CheckNextLine(t, "OnChain:\ttrue")
|
|
||||||
e.CheckNextLine(t, "VMState:\tHALT")
|
|
||||||
return tx, vub
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateKeys(t *testing.T, n int) ([]*keys.PrivateKey, keys.PublicKeys) {
|
|
||||||
privs := make([]*keys.PrivateKey, n)
|
privs := make([]*keys.PrivateKey, n)
|
||||||
pubs := make(keys.PublicKeys, n)
|
pubs := make(keys.PublicKeys, n)
|
||||||
for i := range privs {
|
for i := range privs {
|
||||||
|
@ -350,44 +308,3 @@ func GenerateKeys(t *testing.T, n int) ([]*keys.PrivateKey, keys.PublicKeys) {
|
||||||
}
|
}
|
||||||
return privs, pubs
|
return privs, pubs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) CheckTxTestInvokeOutput(t *testing.T, scriptSize int) {
|
|
||||||
e.CheckNextLine(t, `Hash:\s+`)
|
|
||||||
e.CheckNextLine(t, `OnChain:\s+false`)
|
|
||||||
e.CheckNextLine(t, `ValidUntil:\s+\d+`)
|
|
||||||
e.CheckNextLine(t, `Signer:\s+\w+`)
|
|
||||||
e.CheckNextLine(t, `SystemFee:\s+(\d|\.)+`)
|
|
||||||
e.CheckNextLine(t, `NetworkFee:\s+(\d|\.)+`)
|
|
||||||
e.CheckNextLine(t, `Script:\s+\w+`)
|
|
||||||
e.CheckScriptDump(t, scriptSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) CheckScriptDump(t *testing.T, scriptSize int) {
|
|
||||||
e.CheckNextLine(t, `INDEX\s+`)
|
|
||||||
for i := 0; i < scriptSize; i++ {
|
|
||||||
e.CheckNextLine(t, `\d+\s+\w+`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeployContract(t *testing.T, e *Executor, inPath, configPath, wallet, address, pass string) util.Uint160 {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
nefName := filepath.Join(tmpDir, "contract.nef")
|
|
||||||
manifestName := filepath.Join(tmpDir, "contract.manifest.json")
|
|
||||||
e.Run(t, "neo-go", "contract", "compile",
|
|
||||||
"--in", inPath,
|
|
||||||
"--config", configPath,
|
|
||||||
"--out", nefName, "--manifest", manifestName)
|
|
||||||
e.In.WriteString(pass + "\r")
|
|
||||||
e.Run(t, "neo-go", "contract", "deploy",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
|
||||||
"--wallet", wallet, "--address", address,
|
|
||||||
"--force",
|
|
||||||
"--in", nefName, "--manifest", manifestName)
|
|
||||||
e.CheckTxPersisted(t, "Sent invocation transaction ")
|
|
||||||
line, err := e.Out.ReadString('\n')
|
|
||||||
require.NoError(t, err)
|
|
||||||
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
|
||||||
h, err := util.Uint160DecodeStringLE(line)
|
|
||||||
require.NoError(t, err)
|
|
||||||
return h
|
|
||||||
}
|
|
37
cli/main.go
37
cli/main.go
|
@ -1,15 +1,48 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/app"
|
"github.com/nspcc-dev/neo-go/cli/query"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/server"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/wallet"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctl := app.New()
|
ctl := newApp()
|
||||||
|
|
||||||
if err := ctl.Run(os.Args); err != nil {
|
if err := ctl.Run(os.Args); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func versionPrinter(c *cli.Context) {
|
||||||
|
_, _ = fmt.Fprintf(c.App.Writer, "NeoGo\nVersion: %s\nGoVersion: %s\n",
|
||||||
|
config.Version,
|
||||||
|
runtime.Version(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApp() *cli.App {
|
||||||
|
cli.VersionPrinter = versionPrinter
|
||||||
|
ctl := cli.NewApp()
|
||||||
|
ctl.Name = "neo-go"
|
||||||
|
ctl.Version = config.Version
|
||||||
|
ctl.Usage = "Official Go client for Neo"
|
||||||
|
ctl.ErrWriter = os.Stdout
|
||||||
|
|
||||||
|
ctl.Commands = append(ctl.Commands, server.NewCommands()...)
|
||||||
|
ctl.Commands = append(ctl.Commands, smartcontract.NewCommands()...)
|
||||||
|
ctl.Commands = append(ctl.Commands, wallet.NewCommands()...)
|
||||||
|
ctl.Commands = append(ctl.Commands, vm.NewCommands()...)
|
||||||
|
ctl.Commands = append(ctl.Commands, util.NewCommands()...)
|
||||||
|
ctl.Commands = append(ctl.Commands, query.NewCommands()...)
|
||||||
|
return ctl
|
||||||
|
}
|
||||||
|
|
14
cli/main_test.go
Normal file
14
cli/main_test.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCLIVersion(t *testing.T) {
|
||||||
|
e := newExecutor(t, false)
|
||||||
|
e.Run(t, "neo-go", "--version")
|
||||||
|
e.checkNextLine(t, "^NeoGo")
|
||||||
|
e.checkNextLine(t, "^Version:")
|
||||||
|
e.checkNextLine(t, "^GoVersion:")
|
||||||
|
e.checkEOF(t)
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package wallet_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -8,7 +9,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"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/encoding/address"
|
||||||
|
@ -24,9 +24,9 @@ import (
|
||||||
// 1. Transfer funds to a created multisig address.
|
// 1. Transfer funds to a created multisig address.
|
||||||
// 2. Transfer from multisig to another account.
|
// 2. Transfer from multisig to another account.
|
||||||
func TestSignMultisigTx(t *testing.T) {
|
func TestSignMultisigTx(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
privs, pubs := testcli.GenerateKeys(t, 3)
|
privs, pubs := generateKeys(t, 3)
|
||||||
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
multisigHash := hash.Hash160(script)
|
multisigHash := hash.Hash160(script)
|
||||||
|
@ -44,9 +44,9 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
"--wallet", w,
|
"--wallet", w,
|
||||||
"--wif", wif,
|
"--wif", wif,
|
||||||
"--min", "2",
|
"--min", "2",
|
||||||
pubs[0].StringCompressed(),
|
hex.EncodeToString(pubs[0].Bytes()),
|
||||||
pubs[1].StringCompressed(),
|
hex.EncodeToString(pubs[1].Bytes()),
|
||||||
pubs[2].StringCompressed())
|
hex.EncodeToString(pubs[2].Bytes()))
|
||||||
}
|
}
|
||||||
addAccount(wallet1Path, privs[0].WIF())
|
addAccount(wallet1Path, privs[0].WIF())
|
||||||
addAccount(wallet2Path, privs[1].WIF())
|
addAccount(wallet2Path, privs[1].WIF())
|
||||||
|
@ -54,13 +54,13 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
// Transfer funds to the multisig.
|
// Transfer funds to the multisig.
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
"NEO:"+multisigAddr+":4",
|
"NEO:"+multisigAddr+":4",
|
||||||
"GAS:"+multisigAddr+":1")
|
"GAS:"+multisigAddr+":1")
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
// Sign and transfer funds to another account.
|
// Sign and transfer funds to another account.
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
|
@ -73,7 +73,7 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
})
|
})
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet1Path, "--from", multisigAddr,
|
"--wallet", wallet1Path, "--from", multisigAddr,
|
||||||
"--to", priv.Address(), "--token", "NEO", "--amount", "1",
|
"--to", priv.Address(), "--token", "NEO", "--amount", "1",
|
||||||
"--out", txPath)
|
"--out", txPath)
|
||||||
|
@ -98,7 +98,7 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
// invalid out
|
// invalid out
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.RunWithError(t, "neo-go", "wallet", "sign",
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||||
"--in", txPath, "--out", t.TempDir())
|
"--in", txPath, "--out", t.TempDir())
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
})
|
})
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet1Path, "--from", multisigAddr,
|
"--wallet", wallet1Path, "--from", multisigAddr,
|
||||||
"--to", priv.Address(), "--token", "NEO", "--amount", "1",
|
"--to", priv.Address(), "--token", "NEO", "--amount", "1",
|
||||||
"--out", txPath)
|
"--out", txPath)
|
||||||
|
@ -145,19 +145,19 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
|
|
||||||
t.Run("no invoke", func(t *testing.T) {
|
t.Run("no invoke", func(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "util", "txdump", txPath)
|
e.Run(t, "neo-go", "util", "txdump", txPath)
|
||||||
e.CheckTxTestInvokeOutput(t, 11)
|
e.checkTxTestInvokeOutput(t, 11)
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("excessive parameters", func(t *testing.T) {
|
t.Run("excessive parameters", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "util", "txdump",
|
e.RunWithError(t, "neo-go", "util", "txdump",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
txPath, "garbage")
|
txPath, "garbage")
|
||||||
})
|
})
|
||||||
e.Run(t, "neo-go", "util", "txdump",
|
e.Run(t, "neo-go", "util", "txdump",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
txPath)
|
txPath)
|
||||||
e.CheckTxTestInvokeOutput(t, 11)
|
e.checkTxTestInvokeOutput(t, 11)
|
||||||
res := new(result.Invoke)
|
res := new(result.Invoke)
|
||||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||||
|
@ -193,15 +193,15 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
t.Run("sign, save and send", func(t *testing.T) {
|
t.Run("sign, save and send", func(t *testing.T) {
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.Run(t, "neo-go", "wallet", "sign",
|
e.Run(t, "neo-go", "wallet", "sign",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||||
"--in", txPath, "--out", txPath)
|
"--in", txPath, "--out", txPath)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
t.Run("double-sign", func(t *testing.T) {
|
t.Run("double-sign", func(t *testing.T) {
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.RunWithError(t, "neo-go", "wallet", "sign",
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||||
"--in", txPath, "--out", txPath)
|
"--in", txPath, "--out", txPath)
|
||||||
})
|
})
|
||||||
|
@ -216,13 +216,13 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
|
|
||||||
e.In.WriteString("acc\rpass\rpass\r")
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
e.Run(t, "neo-go", "wallet", "import-deployed",
|
e.Run(t, "neo-go", "wallet", "import-deployed",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet1Path, "--wif", simplePriv.WIF(),
|
"--wallet", wallet1Path, "--wif", simplePriv.WIF(),
|
||||||
"--contract", h.StringLE())
|
"--contract", h.StringLE())
|
||||||
|
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet1Path, "--address", multisigHash.StringLE(), // test with scripthash instead of address
|
"--wallet", wallet1Path, "--address", multisigHash.StringLE(), // test with scripthash instead of address
|
||||||
"--out", txPath,
|
"--out", txPath,
|
||||||
e.Chain.GoverningTokenHash().StringLE(), "transfer",
|
e.Chain.GoverningTokenHash().StringLE(), "transfer",
|
||||||
|
@ -248,10 +248,10 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
// Contract.
|
// Contract.
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.Run(t, "neo-go", "wallet", "sign",
|
e.Run(t, "neo-go", "wallet", "sign",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet1Path, "--address", address.Uint160ToString(h),
|
"--wallet", wallet1Path, "--address", address.Uint160ToString(h),
|
||||||
"--in", txPath, "--out", txPath)
|
"--in", txPath, "--out", txPath)
|
||||||
tx, _ := e.CheckTxPersisted(t)
|
tx, _ := e.checkTxPersisted(t)
|
||||||
require.Equal(t, 3, len(tx.Signers))
|
require.Equal(t, 3, len(tx.Signers))
|
||||||
|
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(priv.GetScriptHash())
|
b, _ := e.Chain.GetGoverningTokenBalance(priv.GetScriptHash())
|
||||||
|
@ -261,6 +261,20 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployVerifyContract(t *testing.T, e *testcli.Executor) util.Uint160 {
|
func (e *executor) checkTxTestInvokeOutput(t *testing.T, scriptSize int) {
|
||||||
return testcli.DeployContract(t, e, "../smartcontract/testdata/verify.go", "../smartcontract/testdata/verify.yml", testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
e.checkNextLine(t, `Hash:\s+`)
|
||||||
|
e.checkNextLine(t, `OnChain:\s+false`)
|
||||||
|
e.checkNextLine(t, `ValidUntil:\s+\d+`)
|
||||||
|
e.checkNextLine(t, `Signer:\s+\w+`)
|
||||||
|
e.checkNextLine(t, `SystemFee:\s+(\d|\.)+`)
|
||||||
|
e.checkNextLine(t, `NetworkFee:\s+(\d|\.)+`)
|
||||||
|
e.checkNextLine(t, `Script:\s+\w+`)
|
||||||
|
e.checkScriptDump(t, scriptSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *executor) checkScriptDump(t *testing.T, scriptSize int) {
|
||||||
|
e.checkNextLine(t, `INDEX\s+`)
|
||||||
|
for i := 0; i < scriptSize; i++ {
|
||||||
|
e.checkNextLine(t, `\d+\s+\w+`)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package nep_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -13,8 +13,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"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/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
@ -28,15 +26,12 @@ import (
|
||||||
const (
|
const (
|
||||||
// nftOwnerAddr is the owner of NFT-ND HASHY token (../examples/nft-nd/nft.go).
|
// nftOwnerAddr is the owner of NFT-ND HASHY token (../examples/nft-nd/nft.go).
|
||||||
nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
|
nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
|
||||||
nftOwnerWallet = "../../examples/my_wallet.json"
|
nftOwnerWallet = "../examples/my_wallet.json"
|
||||||
nftOwnerPass = "qwerty"
|
nftOwnerPass = "qwerty"
|
||||||
|
|
||||||
// Keep contract NEFs consistent between runs.
|
|
||||||
_ = versionutil.TestVersion
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNEP11Import(t *testing.T) {
|
func TestNEP11Import(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
walletPath := filepath.Join(tmpDir, "walletForImport.json")
|
walletPath := filepath.Join(tmpDir, "walletForImport.json")
|
||||||
|
@ -51,7 +46,7 @@ func TestNEP11Import(t *testing.T) {
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"neo-go", "wallet", "nep11", "import",
|
"neo-go", "wallet", "nep11", "import",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
}
|
}
|
||||||
// missing token hash
|
// missing token hash
|
||||||
|
@ -73,12 +68,12 @@ func TestNEP11Import(t *testing.T) {
|
||||||
e.RunWithError(t, append(args, "--token", neoContractHash.StringLE())...)
|
e.RunWithError(t, append(args, "--token", neoContractHash.StringLE())...)
|
||||||
|
|
||||||
checkInfo := func(t *testing.T, h util.Uint160, name string, symbol string, decimals int) {
|
checkInfo := func(t *testing.T, h util.Uint160, name string, symbol string, decimals int) {
|
||||||
e.CheckNextLine(t, "^Name:\\s*"+name)
|
e.checkNextLine(t, "^Name:\\s*"+name)
|
||||||
e.CheckNextLine(t, "^Symbol:\\s*"+symbol)
|
e.checkNextLine(t, "^Symbol:\\s*"+symbol)
|
||||||
e.CheckNextLine(t, "^Hash:\\s*"+h.StringLE())
|
e.checkNextLine(t, "^Hash:\\s*"+h.StringLE())
|
||||||
e.CheckNextLine(t, "^Decimals:\\s*"+strconv.Itoa(decimals))
|
e.checkNextLine(t, "^Decimals:\\s*"+strconv.Itoa(decimals))
|
||||||
e.CheckNextLine(t, "^Address:\\s*"+address.Uint160ToString(h))
|
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(h))
|
||||||
e.CheckNextLine(t, "^Standard:\\s*"+string(manifest.NEP11StandardName))
|
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP11StandardName))
|
||||||
}
|
}
|
||||||
t.Run("Info", func(t *testing.T) {
|
t.Run("Info", func(t *testing.T) {
|
||||||
t.Run("excessive parameters", func(t *testing.T) {
|
t.Run("excessive parameters", func(t *testing.T) {
|
||||||
|
@ -94,7 +89,7 @@ func TestNEP11Import(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "nep11", "info",
|
e.Run(t, "neo-go", "wallet", "nep11", "info",
|
||||||
"--wallet", walletPath)
|
"--wallet", walletPath)
|
||||||
checkInfo(t, nnsContractHash, "NameService", "NNS", 0)
|
checkInfo(t, nnsContractHash, "NameService", "NNS", 0)
|
||||||
e.CheckNextLine(t, "")
|
e.checkNextLine(t, "")
|
||||||
checkInfo(t, nfsContractHash, "NeoFS Object NFT", "NFSO", 2)
|
checkInfo(t, nfsContractHash, "NeoFS Object NFT", "NFSO", 2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -114,7 +109,7 @@ func TestNEP11Import(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
// copy wallet to temp dir in order not to overwrite the original file
|
// copy wallet to temp dir in order not to overwrite the original file
|
||||||
|
@ -127,14 +122,14 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
// transfer funds to contract owner
|
// transfer funds to contract owner
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--to", nftOwnerAddr,
|
"--to", nftOwnerAddr,
|
||||||
"--token", "GAS",
|
"--token", "GAS",
|
||||||
"--amount", "10000",
|
"--amount", "10000",
|
||||||
"--force",
|
"--force",
|
||||||
"--from", testcli.ValidatorAddr)
|
"--from", validatorAddr)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
// deploy NFT HASHY contract
|
// deploy NFT HASHY contract
|
||||||
h := deployNFTContract(t, e)
|
h := deployNFTContract(t, e)
|
||||||
|
@ -143,14 +138,14 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
// mint 1 HASHY token by transferring 10 GAS to HASHY contract
|
// mint 1 HASHY token by transferring 10 GAS to HASHY contract
|
||||||
e.In.WriteString(nftOwnerPass + "\r")
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--to", h.StringLE(),
|
"--to", h.StringLE(),
|
||||||
"--token", "GAS",
|
"--token", "GAS",
|
||||||
"--amount", "10",
|
"--amount", "10",
|
||||||
"--force",
|
"--force",
|
||||||
"--from", nftOwnerAddr)
|
"--from", nftOwnerAddr)
|
||||||
txMint, _ := e.CheckTxPersisted(t)
|
txMint, _ := e.checkTxPersisted(t)
|
||||||
|
|
||||||
// get NFT ID from AER
|
// get NFT ID from AER
|
||||||
aer, err := e.Chain.GetAppExecResults(txMint.Hash(), trigger.Application)
|
aer, err := e.Chain.GetAppExecResults(txMint.Hash(), trigger.Application)
|
||||||
|
@ -166,16 +161,15 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenID := mint(t)
|
tokenID := mint(t)
|
||||||
var hashBeforeTransfer = e.Chain.CurrentHeaderHash()
|
|
||||||
|
|
||||||
// check the balance
|
// check the balance
|
||||||
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--address", nftOwnerAddr}
|
"--address", nftOwnerAddr}
|
||||||
checkBalanceResult := func(t *testing.T, acc string, ids ...[]byte) {
|
checkBalanceResult := func(t *testing.T, acc string, ids ...[]byte) {
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+acc)
|
e.checkNextLine(t, "^\\s*Account\\s+"+acc)
|
||||||
e.CheckNextLine(t, "^\\s*HASHY:\\s+HASHY NFT \\("+h.StringLE()+"\\)")
|
e.checkNextLine(t, "^\\s*HASHY:\\s+HASHY NFT \\("+h.StringLE()+"\\)")
|
||||||
|
|
||||||
// Hashes can be ordered in any way, so make a regexp for them.
|
// Hashes can be ordered in any way, so make a regexp for them.
|
||||||
var tokstring = "("
|
var tokstring = "("
|
||||||
|
@ -188,11 +182,11 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
tokstring += ")"
|
tokstring += ")"
|
||||||
|
|
||||||
for range ids {
|
for range ids {
|
||||||
e.CheckNextLine(t, "^\\s*Token: "+tokstring+"\\s*$")
|
e.checkNextLine(t, "^\\s*Token: "+tokstring+"\\s*$")
|
||||||
e.CheckNextLine(t, "^\\s*Amount: 1\\s*$")
|
e.checkNextLine(t, "^\\s*Amount: 1\\s*$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated: [0-9]+\\s*$")
|
e.checkNextLine(t, "^\\s*Updated: [0-9]+\\s*$")
|
||||||
}
|
}
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
}
|
}
|
||||||
// balance check: by symbol, token is not imported
|
// balance check: by symbol, token is not imported
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", "HASHY")...)
|
e.Run(t, append(cmdCheckBalance, "--token", "HASHY")...)
|
||||||
|
@ -205,7 +199,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// import token
|
// import token
|
||||||
e.Run(t, "neo-go", "wallet", "nep11", "import",
|
e.Run(t, "neo-go", "wallet", "nep11", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--token", h.StringLE())
|
"--token", h.StringLE())
|
||||||
|
|
||||||
|
@ -215,7 +209,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// balance check: all accounts
|
// balance check: all accounts
|
||||||
e.Run(t, "neo-go", "wallet", "nep11", "balance",
|
e.Run(t, "neo-go", "wallet", "nep11", "balance",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--token", h.StringLE())
|
"--token", h.StringLE())
|
||||||
checkBalanceResult(t, nftOwnerAddr, tokenID)
|
checkBalanceResult(t, nftOwnerAddr, tokenID)
|
||||||
|
@ -227,7 +221,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// ownerOf: missing contract hash
|
// ownerOf: missing contract hash
|
||||||
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf",
|
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdOwnerOf...)
|
e.RunWithError(t, cmdOwnerOf...)
|
||||||
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
||||||
|
@ -238,11 +232,11 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// ownerOf: good
|
// ownerOf: good
|
||||||
e.Run(t, cmdOwnerOf...)
|
e.Run(t, cmdOwnerOf...)
|
||||||
e.CheckNextLine(t, nftOwnerAddr)
|
e.checkNextLine(t, nftOwnerAddr)
|
||||||
|
|
||||||
// tokensOf: missing contract hash
|
// tokensOf: missing contract hash
|
||||||
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithError(t, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
||||||
|
@ -253,12 +247,12 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// tokensOf: good
|
// tokensOf: good
|
||||||
e.Run(t, cmdTokensOf...)
|
e.Run(t, cmdTokensOf...)
|
||||||
require.Equal(t, hex.EncodeToString(tokenID), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(tokenID), e.getNextLine(t))
|
||||||
|
|
||||||
// properties: no contract
|
// properties: no contract
|
||||||
cmdProperties := []string{
|
cmdProperties := []string{
|
||||||
"neo-go", "wallet", "nep11", "properties",
|
"neo-go", "wallet", "nep11", "properties",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdProperties...)
|
e.RunWithError(t, cmdProperties...)
|
||||||
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
||||||
|
@ -269,7 +263,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// properties: ok
|
// properties: ok
|
||||||
e.Run(t, cmdProperties...)
|
e.Run(t, cmdProperties...)
|
||||||
require.Equal(t, fmt.Sprintf(`{"name":"HASHY %s"}`, base64.StdEncoding.EncodeToString(tokenID)), e.GetNextLine(t))
|
require.Equal(t, fmt.Sprintf(`{"name":"HASHY %s"}`, base64.StdEncoding.EncodeToString(tokenID)), e.getNextLine(t))
|
||||||
|
|
||||||
// tokensOf: good, several tokens
|
// tokensOf: good, several tokens
|
||||||
tokenID1 := mint(t)
|
tokenID1 := mint(t)
|
||||||
|
@ -279,12 +273,12 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
fst, snd = snd, fst
|
fst, snd = snd, fst
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, hex.EncodeToString(fst), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||||
require.Equal(t, hex.EncodeToString(snd), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||||
|
|
||||||
// tokens: missing contract hash
|
// tokens: missing contract hash
|
||||||
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokens...)
|
e.RunWithError(t, cmdTokens...)
|
||||||
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
||||||
|
@ -293,8 +287,8 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmdTokens, "additional")...)
|
e.RunWithError(t, append(cmdTokens, "additional")...)
|
||||||
// tokens: good, several tokens
|
// tokens: good, several tokens
|
||||||
e.Run(t, cmdTokens...)
|
e.Run(t, cmdTokens...)
|
||||||
require.Equal(t, hex.EncodeToString(fst), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||||
require.Equal(t, hex.EncodeToString(snd), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||||
|
|
||||||
// balance check: several tokens, ok
|
// balance check: several tokens, ok
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
|
@ -302,9 +296,9 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
cmdTransfer := []string{
|
cmdTransfer := []string{
|
||||||
"neo-go", "wallet", "nep11", "transfer",
|
"neo-go", "wallet", "nep11", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--to", testcli.ValidatorAddr,
|
"--to", validatorAddr,
|
||||||
"--from", nftOwnerAddr,
|
"--from", nftOwnerAddr,
|
||||||
"--force",
|
"--force",
|
||||||
}
|
}
|
||||||
|
@ -322,25 +316,17 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
// transfer: good
|
// transfer: good
|
||||||
e.In.WriteString(nftOwnerPass + "\r")
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
e.Run(t, append(cmdTransfer, "--id", hex.EncodeToString(tokenID))...)
|
e.Run(t, append(cmdTransfer, "--id", hex.EncodeToString(tokenID))...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
// check balance after transfer
|
// check balance after transfer
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
checkBalanceResult(t, nftOwnerAddr, tokenID1)
|
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
|
// transfer: good, to NEP-11-Payable contract, with data
|
||||||
verifyH := deployVerifyContract(t, e)
|
verifyH := deployVerifyContract(t, e)
|
||||||
cmdTransfer = []string{
|
cmdTransfer = []string{
|
||||||
"neo-go", "wallet", "nep11", "transfer",
|
"neo-go", "wallet", "nep11", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--to", verifyH.StringLE(),
|
"--to", verifyH.StringLE(),
|
||||||
"--from", nftOwnerAddr,
|
"--from", nftOwnerAddr,
|
||||||
|
@ -351,7 +337,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
}
|
}
|
||||||
e.In.WriteString(nftOwnerPass + "\r")
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
e.Run(t, cmdTransfer...)
|
e.Run(t, cmdTransfer...)
|
||||||
tx, _ := e.CheckTxPersisted(t)
|
tx, _ := e.checkTxPersisted(t)
|
||||||
// check OnNEP11Payment event
|
// check OnNEP11Payment event
|
||||||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -372,32 +358,14 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
// check balance after transfer
|
// check balance after transfer
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
checkBalanceResult(t, nftOwnerAddr)
|
checkBalanceResult(t, nftOwnerAddr)
|
||||||
|
|
||||||
// historic calls still remember the good old days.
|
|
||||||
cmdOwnerOf = append(cmdOwnerOf, "--historic", hashBeforeTransfer.StringLE())
|
|
||||||
e.Run(t, cmdOwnerOf...)
|
|
||||||
e.CheckNextLine(t, nftOwnerAddr)
|
|
||||||
|
|
||||||
cmdTokensOf = append(cmdTokensOf, "--historic", hashBeforeTransfer.StringLE())
|
|
||||||
e.Run(t, cmdTokensOf...)
|
|
||||||
require.Equal(t, hex.EncodeToString(tokenID), e.GetNextLine(t))
|
|
||||||
|
|
||||||
cmdTokens = append(cmdTokens, "--historic", hashBeforeTransfer.StringLE())
|
|
||||||
e.Run(t, cmdTokens...)
|
|
||||||
require.Equal(t, hex.EncodeToString(tokenID), e.GetNextLine(t))
|
|
||||||
|
|
||||||
// this one is not affected by transfer, but anyway
|
|
||||||
cmdProperties = append(cmdProperties, "--historic", hashBeforeTransfer.StringLE())
|
|
||||||
e.Run(t, cmdProperties...)
|
|
||||||
require.Equal(t, fmt.Sprintf(`{"name":"HASHY %s"}`, base64.StdEncoding.EncodeToString(tokenID)), e.GetNextLine(t))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
// copy wallet to temp dir in order not to overwrite the original file
|
// copy wallet to temp dir in order not to overwrite the original file
|
||||||
bytesRead, err := os.ReadFile(testcli.ValidatorWallet)
|
bytesRead, err := os.ReadFile(validatorWallet)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wall := filepath.Join(tmpDir, "my_wallet.json")
|
wall := filepath.Join(tmpDir, "my_wallet.json")
|
||||||
err = os.WriteFile(wall, bytesRead, 0755)
|
err = os.WriteFile(wall, bytesRead, 0755)
|
||||||
|
@ -408,18 +376,18 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
mint := func(t *testing.T, containerID, objectID util.Uint256) []byte {
|
mint := func(t *testing.T, containerID, objectID util.Uint256) []byte {
|
||||||
// mint 1.00 NFSO token by transferring 10 GAS to NFSO contract
|
// mint 1.00 NFSO token by transferring 10 GAS to NFSO contract
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString(validatorPass + "\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--to", h.StringLE(),
|
"--to", h.StringLE(),
|
||||||
"--token", "GAS",
|
"--token", "GAS",
|
||||||
"--amount", "10",
|
"--amount", "10",
|
||||||
"--force",
|
"--force",
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--", "[", "hash256:"+containerID.StringLE(), "hash256:"+objectID.StringLE(), "]",
|
"--", "[", "hash256:"+containerID.StringLE(), "hash256:"+objectID.StringLE(), "]",
|
||||||
)
|
)
|
||||||
txMint, _ := e.CheckTxPersisted(t)
|
txMint, _ := e.checkTxPersisted(t)
|
||||||
|
|
||||||
// get NFT ID from AER
|
// get NFT ID from AER
|
||||||
aer, err := e.Chain.GetAppExecResults(txMint.Hash(), trigger.Application)
|
aer, err := e.Chain.GetAppExecResults(txMint.Hash(), trigger.Application)
|
||||||
|
@ -444,15 +412,15 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// check properties
|
// check properties
|
||||||
e.Run(t, "neo-go", "wallet", "nep11", "properties",
|
e.Run(t, "neo-go", "wallet", "nep11", "properties",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--token", h.StringLE(),
|
"--token", h.StringLE(),
|
||||||
"--id", hex.EncodeToString(token1ID))
|
"--id", hex.EncodeToString(token1ID))
|
||||||
jProps := e.GetNextLine(t)
|
jProps := e.getNextLine(t)
|
||||||
props := make(map[string]string)
|
props := make(map[string]string)
|
||||||
require.NoError(t, json.Unmarshal([]byte(jProps), &props))
|
require.NoError(t, json.Unmarshal([]byte(jProps), &props))
|
||||||
require.Equal(t, base64.StdEncoding.EncodeToString(container1ID.BytesBE()), props["containerID"])
|
require.Equal(t, base64.StdEncoding.EncodeToString(container1ID.BytesBE()), props["containerID"])
|
||||||
require.Equal(t, base64.StdEncoding.EncodeToString(object1ID.BytesBE()), props["objectID"])
|
require.Equal(t, base64.StdEncoding.EncodeToString(object1ID.BytesBE()), props["objectID"])
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
|
|
||||||
type idAmount struct {
|
type idAmount struct {
|
||||||
id string
|
id string
|
||||||
|
@ -461,19 +429,19 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// check the balance
|
// check the balance
|
||||||
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--address", testcli.ValidatorAddr}
|
"--address", validatorAddr}
|
||||||
checkBalanceResult := func(t *testing.T, acc string, objs ...idAmount) {
|
checkBalanceResult := func(t *testing.T, acc string, objs ...idAmount) {
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+acc)
|
e.checkNextLine(t, "^\\s*Account\\s+"+acc)
|
||||||
e.CheckNextLine(t, "^\\s*NFSO:\\s+NeoFS Object NFT \\("+h.StringLE()+"\\)")
|
e.checkNextLine(t, "^\\s*NFSO:\\s+NeoFS Object NFT \\("+h.StringLE()+"\\)")
|
||||||
|
|
||||||
for _, o := range objs {
|
for _, o := range objs {
|
||||||
e.CheckNextLine(t, "^\\s*Token: "+o.id+"\\s*$")
|
e.checkNextLine(t, "^\\s*Token: "+o.id+"\\s*$")
|
||||||
e.CheckNextLine(t, "^\\s*Amount: "+o.amount+"\\s*$")
|
e.checkNextLine(t, "^\\s*Amount: "+o.amount+"\\s*$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated: [0-9]+\\s*$")
|
e.checkNextLine(t, "^\\s*Updated: [0-9]+\\s*$")
|
||||||
}
|
}
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
}
|
}
|
||||||
tokz := []idAmount{
|
tokz := []idAmount{
|
||||||
{hex.EncodeToString(token1ID), "1"},
|
{hex.EncodeToString(token1ID), "1"},
|
||||||
|
@ -481,29 +449,29 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
}
|
}
|
||||||
// balance check: by symbol, token is not imported
|
// balance check: by symbol, token is not imported
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", "NFSO")...)
|
e.Run(t, append(cmdCheckBalance, "--token", "NFSO")...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz...)
|
checkBalanceResult(t, validatorAddr, tokz...)
|
||||||
|
|
||||||
// overall NFSO balance check: by hash, ok
|
// overall NFSO balance check: by hash, ok
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz...)
|
checkBalanceResult(t, validatorAddr, tokz...)
|
||||||
|
|
||||||
// particular NFSO balance check: by hash, ok
|
// particular NFSO balance check: by hash, ok
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE(), "--id", hex.EncodeToString(token2ID))...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE(), "--id", hex.EncodeToString(token2ID))...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz[1])
|
checkBalanceResult(t, validatorAddr, tokz[1])
|
||||||
|
|
||||||
// import token
|
// import token
|
||||||
e.Run(t, "neo-go", "wallet", "nep11", "import",
|
e.Run(t, "neo-go", "wallet", "nep11", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--token", h.StringLE())
|
"--token", h.StringLE())
|
||||||
|
|
||||||
// overall balance check: by symbol, ok
|
// overall balance check: by symbol, ok
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", "NFSO")...)
|
e.Run(t, append(cmdCheckBalance, "--token", "NFSO")...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz...)
|
checkBalanceResult(t, validatorAddr, tokz...)
|
||||||
|
|
||||||
// particular balance check: by symbol, ok
|
// particular balance check: by symbol, ok
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", "NFSO", "--id", hex.EncodeToString(token1ID))...)
|
e.Run(t, append(cmdCheckBalance, "--token", "NFSO", "--id", hex.EncodeToString(token1ID))...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz[0])
|
checkBalanceResult(t, validatorAddr, tokz[0])
|
||||||
|
|
||||||
// remove token from wallet
|
// remove token from wallet
|
||||||
e.In.WriteString("y\r")
|
e.In.WriteString("y\r")
|
||||||
|
@ -512,7 +480,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// ownerOfD: missing contract hash
|
// ownerOfD: missing contract hash
|
||||||
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
|
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdOwnerOf...)
|
e.RunWithError(t, cmdOwnerOf...)
|
||||||
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
||||||
|
@ -523,29 +491,29 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// ownerOfD: good
|
// ownerOfD: good
|
||||||
e.Run(t, cmdOwnerOf...)
|
e.Run(t, cmdOwnerOf...)
|
||||||
e.CheckNextLine(t, testcli.ValidatorAddr)
|
e.checkNextLine(t, validatorAddr)
|
||||||
|
|
||||||
// tokensOf: missing contract hash
|
// tokensOf: missing contract hash
|
||||||
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithError(t, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
||||||
|
|
||||||
// tokensOf: missing owner address
|
// tokensOf: missing owner address
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithError(t, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--address", testcli.ValidatorAddr)
|
cmdTokensOf = append(cmdTokensOf, "--address", validatorAddr)
|
||||||
|
|
||||||
// tokensOf: good
|
// tokensOf: good
|
||||||
e.Run(t, cmdTokensOf...)
|
e.Run(t, cmdTokensOf...)
|
||||||
require.Equal(t, hex.EncodeToString(token1ID), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(token1ID), e.getNextLine(t))
|
||||||
require.Equal(t, hex.EncodeToString(token2ID), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(token2ID), e.getNextLine(t))
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
|
|
||||||
// properties: no contract
|
// properties: no contract
|
||||||
cmdProperties := []string{
|
cmdProperties := []string{
|
||||||
"neo-go", "wallet", "nep11", "properties",
|
"neo-go", "wallet", "nep11", "properties",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdProperties...)
|
e.RunWithError(t, cmdProperties...)
|
||||||
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
||||||
|
@ -559,12 +527,12 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
|
||||||
// properties: ok
|
// properties: ok
|
||||||
e.Run(t, cmdProperties...)
|
e.Run(t, cmdProperties...)
|
||||||
jProps = e.GetNextLine(t)
|
jProps = e.getNextLine(t)
|
||||||
props = make(map[string]string)
|
props = make(map[string]string)
|
||||||
require.NoError(t, json.Unmarshal([]byte(jProps), &props))
|
require.NoError(t, json.Unmarshal([]byte(jProps), &props))
|
||||||
require.Equal(t, base64.StdEncoding.EncodeToString(container2ID.BytesBE()), props["containerID"])
|
require.Equal(t, base64.StdEncoding.EncodeToString(container2ID.BytesBE()), props["containerID"])
|
||||||
require.Equal(t, base64.StdEncoding.EncodeToString(object2ID.BytesBE()), props["objectID"])
|
require.Equal(t, base64.StdEncoding.EncodeToString(object2ID.BytesBE()), props["objectID"])
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
|
|
||||||
// tokensOf: good, several tokens
|
// tokensOf: good, several tokens
|
||||||
e.Run(t, cmdTokensOf...)
|
e.Run(t, cmdTokensOf...)
|
||||||
|
@ -573,75 +541,75 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
fst, snd = snd, fst
|
fst, snd = snd, fst
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, hex.EncodeToString(fst), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||||
require.Equal(t, hex.EncodeToString(snd), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||||
|
|
||||||
// tokens: missing contract hash
|
// tokens: missing contract hash
|
||||||
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokens...)
|
e.RunWithError(t, cmdTokens...)
|
||||||
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
||||||
|
|
||||||
// tokens: good, several tokens
|
// tokens: good, several tokens
|
||||||
e.Run(t, cmdTokens...)
|
e.Run(t, cmdTokens...)
|
||||||
require.Equal(t, hex.EncodeToString(fst), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||||
require.Equal(t, hex.EncodeToString(snd), e.GetNextLine(t))
|
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||||
|
|
||||||
// balance check: several tokens, ok
|
// balance check: several tokens, ok
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz...)
|
checkBalanceResult(t, validatorAddr, tokz...)
|
||||||
|
|
||||||
cmdTransfer := []string{
|
cmdTransfer := []string{
|
||||||
"neo-go", "wallet", "nep11", "transfer",
|
"neo-go", "wallet", "nep11", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--to", nftOwnerAddr,
|
"--to", nftOwnerAddr,
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
}
|
}
|
||||||
|
|
||||||
// transfer: unimported token with symbol id specified
|
// transfer: unimported token with symbol id specified
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString(validatorPass + "\r")
|
||||||
e.RunWithError(t, append(cmdTransfer,
|
e.RunWithError(t, append(cmdTransfer,
|
||||||
"--token", "NFSO")...)
|
"--token", "NFSO")...)
|
||||||
cmdTransfer = append(cmdTransfer, "--token", h.StringLE())
|
cmdTransfer = append(cmdTransfer, "--token", h.StringLE())
|
||||||
|
|
||||||
// transfer: no id specified
|
// transfer: no id specified
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString(validatorPass + "\r")
|
||||||
e.RunWithError(t, cmdTransfer...)
|
e.RunWithError(t, cmdTransfer...)
|
||||||
|
|
||||||
// transfer: good
|
// transfer: good
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString(validatorPass + "\r")
|
||||||
e.Run(t, append(cmdTransfer, "--id", hex.EncodeToString(token1ID))...)
|
e.Run(t, append(cmdTransfer, "--id", hex.EncodeToString(token1ID))...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
// check balance after transfer
|
// check balance after transfer
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz[1]) // only token2ID expected to be on the balance
|
checkBalanceResult(t, validatorAddr, tokz[1]) // only token2ID expected to be on the balance
|
||||||
|
|
||||||
// transfer: good, 1/4 of the balance, to NEP-11-Payable contract, with data
|
// transfer: good, 1/4 of the balance, to NEP-11-Payable contract, with data
|
||||||
verifyH := deployVerifyContract(t, e)
|
verifyH := deployVerifyContract(t, e)
|
||||||
cmdTransfer = []string{
|
cmdTransfer = []string{
|
||||||
"neo-go", "wallet", "nep11", "transfer",
|
"neo-go", "wallet", "nep11", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", wall,
|
"--wallet", wall,
|
||||||
"--to", verifyH.StringLE(),
|
"--to", verifyH.StringLE(),
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--token", h.StringLE(),
|
"--token", h.StringLE(),
|
||||||
"--id", hex.EncodeToString(token2ID),
|
"--id", hex.EncodeToString(token2ID),
|
||||||
"--amount", "0.25",
|
"--amount", "0.25",
|
||||||
"--force",
|
"--force",
|
||||||
"string:some_data",
|
"string:some_data",
|
||||||
}
|
}
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString(validatorPass + "\r")
|
||||||
e.Run(t, cmdTransfer...)
|
e.Run(t, cmdTransfer...)
|
||||||
tx, _ := e.CheckTxPersisted(t)
|
tx, _ := e.checkTxPersisted(t)
|
||||||
// check OnNEP11Payment event
|
// check OnNEP11Payment event
|
||||||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(aer[0].Events))
|
require.Equal(t, 2, len(aer[0].Events))
|
||||||
validatorHash, err := address.StringToUint160(testcli.ValidatorAddr)
|
validatorHash, err := address.StringToUint160(validatorAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, state.NotificationEvent{
|
require.Equal(t, state.NotificationEvent{
|
||||||
ScriptHash: verifyH,
|
ScriptHash: verifyH,
|
||||||
|
@ -657,21 +625,17 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
// check balance after transfer
|
// check balance after transfer
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
tokz[1].amount = "0.75"
|
tokz[1].amount = "0.75"
|
||||||
checkBalanceResult(t, testcli.ValidatorAddr, tokz[1])
|
checkBalanceResult(t, validatorAddr, tokz[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployNFSContract(t *testing.T, e *testcli.Executor) util.Uint160 {
|
func deployNFSContract(t *testing.T, e *executor) util.Uint160 {
|
||||||
return testcli.DeployContract(t, e, "../../examples/nft-d/nft.go", "../../examples/nft-d/nft.yml", testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
return deployContract(t, e, "../examples/nft-d/nft.go", "../examples/nft-d/nft.yml", validatorWallet, validatorAddr, validatorPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployNFTContract(t *testing.T, e *testcli.Executor) util.Uint160 {
|
func deployNFTContract(t *testing.T, e *executor) util.Uint160 {
|
||||||
return testcli.DeployContract(t, e, "../../examples/nft-nd/nft.go", "../../examples/nft-nd/nft.yml", nftOwnerWallet, nftOwnerAddr, nftOwnerPass)
|
return deployContract(t, e, "../examples/nft-nd/nft.go", "../examples/nft-nd/nft.yml", nftOwnerWallet, nftOwnerAddr, nftOwnerPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployNNSContract(t *testing.T, e *testcli.Executor) util.Uint160 {
|
func deployNNSContract(t *testing.T, e *executor) util.Uint160 {
|
||||||
return testcli.DeployContract(t, e, "../../examples/nft-nd-nns/", "../../examples/nft-nd-nns/nns.yml", testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
return deployContract(t, e, "../examples/nft-nd-nns/", "../examples/nft-nd-nns/nns.yml", validatorWallet, validatorAddr, validatorPass)
|
||||||
}
|
|
||||||
|
|
||||||
func deployVerifyContract(t *testing.T, e *testcli.Executor) util.Uint160 {
|
|
||||||
return testcli.DeployContract(t, e, "../smartcontract/testdata/verify.go", "../smartcontract/testdata/verify.yml", testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package nep_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
@ -8,7 +8,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
@ -18,39 +17,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNEP17Balance(t *testing.T) {
|
func TestNEP17Balance(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := 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"}
|
cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
|
||||||
cmdbase := append(cmdbalance,
|
cmdbase := append(cmdbalance,
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.TestWalletMultiPath,
|
"--wallet", validatorWallet,
|
||||||
)
|
)
|
||||||
cmd := append(cmdbase, "--address", testcli.TestWalletMultiAccount1)
|
cmd := append(cmdbase, "--address", validatorAddr)
|
||||||
t.Run("excessive parameters", func(t *testing.T) {
|
t.Run("excessive parameters", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
|
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
|
||||||
})
|
})
|
||||||
t.Run("NEO", func(t *testing.T) {
|
t.Run("NEO", func(t *testing.T) {
|
||||||
b, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
b, index := e.Chain.GetGoverningTokenBalance(validatorHash)
|
||||||
checkResult := func(t *testing.T) {
|
checkResult := func(t *testing.T) {
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
|
e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr)
|
||||||
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
e.checkNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
e.checkNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
}
|
}
|
||||||
t.Run("Alias", func(t *testing.T) {
|
t.Run("Alias", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--token", "NEO")...)
|
e.Run(t, append(cmd, "--token", "NEO")...)
|
||||||
|
@ -63,55 +47,67 @@ func TestNEP17Balance(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("GAS", func(t *testing.T) {
|
t.Run("GAS", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--token", "GAS")...)
|
e.Run(t, append(cmd, "--token", "GAS")...)
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
|
e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr)
|
||||||
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
e.checkNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
||||||
b := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
b := e.Chain.GetUtilityTokenBalance(validatorHash)
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
|
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
|
||||||
})
|
})
|
||||||
t.Run("zero balance of known token", func(t *testing.T) {
|
t.Run("zero balance of known token", func(t *testing.T) {
|
||||||
e.Run(t, append(cmdbase, []string{"--token", "NEO", "--address", testcli.TestWalletMultiAccount2}...)...)
|
e.Run(t, append(cmdbase, []string{"--token", "NEO"}...)...)
|
||||||
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
|
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
|
||||||
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
require.NoError(t, err)
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
|
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr1))
|
||||||
e.CheckNextLine(t, "^\\s*Updated:")
|
e.checkNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
||||||
e.CheckEOF(t)
|
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
|
||||||
|
e.checkNextLine(t, "^\\s*Updated:")
|
||||||
|
e.checkNextLine(t, "^\\s*$")
|
||||||
})
|
})
|
||||||
t.Run("all accounts", func(t *testing.T) {
|
t.Run("all accounts", func(t *testing.T) {
|
||||||
e.Run(t, cmdbase...)
|
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.
|
// The order of assets is undefined.
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
line := e.GetNextLine(t)
|
line := e.getNextLine(t)
|
||||||
if strings.Contains(line, "GAS") {
|
if strings.Contains(line, "GAS") {
|
||||||
e.CheckLine(t, line, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
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*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated:")
|
e.checkNextLine(t, "^\\s*Updated:")
|
||||||
} else {
|
} else {
|
||||||
balance, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
balance, index := e.Chain.GetGoverningTokenBalance(validatorHash)
|
||||||
e.CheckLine(t, line, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
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*Amount\\s*:\\s*"+balance.String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
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, "^\\s*$")
|
addr4, err := address.StringToUint160("NQ3nAdFQXzemHC9uvr4af2Ysap6aZJpqgN") // deployed verify.go contract
|
||||||
|
require.NoError(t, err)
|
||||||
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount3)
|
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr4))
|
||||||
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
e.checkEOF(t)
|
||||||
balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount3Hash)
|
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
|
|
||||||
e.CheckNextLine(t, "^\\s*Updated:")
|
|
||||||
e.CheckEOF(t)
|
|
||||||
})
|
})
|
||||||
t.Run("Bad token", func(t *testing.T) {
|
t.Run("Bad token", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--token", "kek")...)
|
e.Run(t, append(cmd, "--token", "kek")...)
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
|
e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr)
|
||||||
e.CheckNextLine(t, `^\s*Can't find data for "kek" token\s*`)
|
e.checkNextLine(t, `^\s*Can't find data for "kek" token\s*`)
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
})
|
})
|
||||||
t.Run("Bad wallet", func(t *testing.T) {
|
t.Run("Bad wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null")...)
|
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null")...)
|
||||||
|
@ -119,18 +115,18 @@ func TestNEP17Balance(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEP17Transfer(t *testing.T) {
|
func TestNEP17Transfer(t *testing.T) {
|
||||||
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
|
w, err := wallet.NewWalletFromFile("testdata/testwallet.json")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
args := []string{
|
args := []string{
|
||||||
"neo-go", "wallet", "nep17", "transfer",
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--to", w.Accounts[0].Address,
|
"--to", w.Accounts[0].Address,
|
||||||
"--token", "NEO",
|
"--token", "NEO",
|
||||||
"--amount", "1",
|
"--amount", "1",
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("missing receiver", func(t *testing.T) {
|
t.Run("missing receiver", func(t *testing.T) {
|
||||||
|
@ -161,20 +157,23 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.In.WriteString("Y\r")
|
e.In.WriteString("Y\r")
|
||||||
e.Run(t, args...)
|
e.Run(t, args...)
|
||||||
e.CheckNextLine(t, `^Network fee:\s*(\d|\.)+`)
|
e.checkNextLine(t, `^Network fee:\s*(\d|\.)+`)
|
||||||
e.CheckNextLine(t, `^System fee:\s*(\d|\.)+`)
|
e.checkNextLine(t, `^System fee:\s*(\d|\.)+`)
|
||||||
e.CheckNextLine(t, `^Total fee:\s*(\d|\.)+`)
|
e.checkNextLine(t, `^Total fee:\s*(\d|\.)+`)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
sh := w.Accounts[0].ScriptHash()
|
sh, err := address.StringToUint160(w.Accounts[0].Address)
|
||||||
|
require.NoError(t, err)
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
||||||
require.Equal(t, big.NewInt(1), b)
|
require.Equal(t, big.NewInt(1), b)
|
||||||
|
|
||||||
t.Run("with force", func(t *testing.T) {
|
t.Run("with force", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(args, "--force")...)
|
e.Run(t, append(args, "--force")...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
sh, err := address.StringToUint160(w.Accounts[0].Address)
|
||||||
|
require.NoError(t, err)
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
||||||
require.Equal(t, big.NewInt(2), b)
|
require.Equal(t, big.NewInt(2), b)
|
||||||
})
|
})
|
||||||
|
@ -185,20 +184,22 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
t.Run("default address", func(t *testing.T) {
|
t.Run("default address", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
"NEO:"+validatorDefault+":42",
|
"NEO:"+validatorDefault+":42",
|
||||||
"GAS:"+validatorDefault+":7")
|
"GAS:"+validatorDefault+":7")
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
args := args[:len(args)-2] // cut '--from' argument
|
args := args[:len(args)-2] // cut '--from' argument
|
||||||
args = append(args, "--force")
|
args = append(args, "--force")
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, args...)
|
e.Run(t, args...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
sh, err := address.StringToUint160(w.Accounts[0].Address)
|
||||||
|
require.NoError(t, err)
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
||||||
require.Equal(t, big.NewInt(3), b)
|
require.Equal(t, big.NewInt(3), b)
|
||||||
|
|
||||||
|
@ -211,70 +212,63 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
t.Run("with signers", func(t *testing.T) {
|
t.Run("with signers", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
"NEO:"+validatorDefault+":42",
|
"NEO:"+validatorDefault+":42",
|
||||||
"GAS:"+validatorDefault+":7",
|
"GAS:"+validatorDefault+":7",
|
||||||
"--", testcli.ValidatorAddr+":Global")
|
"--", validatorAddr+":Global")
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
|
|
||||||
validTil := e.Chain.BlockHeight() + 100
|
validTil := e.Chain.BlockHeight() + 100
|
||||||
cmd := []string{
|
cmd := []string{
|
||||||
"neo-go", "wallet", "nep17", "transfer",
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
|
"--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
|
||||||
"--token", "GAS",
|
"--token", "GAS",
|
||||||
"--amount", "1",
|
"--amount", "1",
|
||||||
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
"--from", testcli.ValidatorAddr}
|
"[", validatorAddr, strconv.Itoa(int(validTil)), "]"}
|
||||||
|
|
||||||
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)), "]")
|
|
||||||
|
|
||||||
t.Run("with data", func(t *testing.T) {
|
t.Run("with data", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with data and signers", func(t *testing.T) {
|
t.Run("with data and signers", func(t *testing.T) {
|
||||||
t.Run("invalid sender's scope", func(t *testing.T) {
|
t.Run("invalid sender's scope", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.RunWithError(t, append(cmd, "--", testcli.ValidatorAddr+":None")...)
|
e.RunWithError(t, append(cmd, "--", validatorAddr+":None")...)
|
||||||
})
|
})
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(cmd, "--", testcli.ValidatorAddr+":Global")...) // CalledByEntry is enough, but it's the default value, so check something else
|
e.Run(t, append(cmd, "--", validatorAddr+":Global")...) // CalledByEntry is enough, but it's the default value, so check something else
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
t.Run("several signers", func(t *testing.T) {
|
t.Run("several signers", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(cmd, "--", testcli.ValidatorAddr, hVerify.StringLE())...)
|
e.Run(t, append(cmd, "--", validatorAddr, hVerify.StringLE())...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEP17MultiTransfer(t *testing.T) {
|
func TestNEP17MultiTransfer(t *testing.T) {
|
||||||
privs, _ := testcli.GenerateKeys(t, 3)
|
privs, _ := generateKeys(t, 3)
|
||||||
|
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
neoContractHash, err := e.Chain.GetNativeContractScriptHash(nativenames.Neo)
|
neoContractHash, err := e.Chain.GetNativeContractScriptHash(nativenames.Neo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
args := []string{
|
args := []string{
|
||||||
"neo-go", "wallet", "nep17", "multitransfer",
|
"neo-go", "wallet", "nep17", "multitransfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
"NEO:" + privs[0].Address() + ":42",
|
"NEO:" + privs[0].Address() + ":42",
|
||||||
"GAS:" + privs[1].Address() + ":7",
|
"GAS:" + privs[1].Address() + ":7",
|
||||||
|
@ -285,7 +279,7 @@ func TestNEP17MultiTransfer(t *testing.T) {
|
||||||
t.Run("no cosigners", func(t *testing.T) {
|
t.Run("no cosigners", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, args...)
|
e.Run(t, args...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(privs[0].GetScriptHash())
|
b, _ := e.Chain.GetGoverningTokenBalance(privs[0].GetScriptHash())
|
||||||
require.Equal(t, big.NewInt(42), b)
|
require.Equal(t, big.NewInt(42), b)
|
||||||
|
@ -298,24 +292,24 @@ func TestNEP17MultiTransfer(t *testing.T) {
|
||||||
t.Run("invalid sender scope", func(t *testing.T) {
|
t.Run("invalid sender scope", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.RunWithError(t, append(args,
|
e.RunWithError(t, append(args,
|
||||||
"--", testcli.ValidatorAddr+":None")...) // invalid sender scope
|
"--", validatorAddr+":None")...) // invalid sender scope
|
||||||
})
|
})
|
||||||
t.Run("Global sender scope", func(t *testing.T) {
|
t.Run("Global sender scope", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(args,
|
e.Run(t, append(args,
|
||||||
"--", testcli.ValidatorAddr+":Global")...)
|
"--", validatorAddr+":Global")...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
t.Run("Several cosigners", func(t *testing.T) {
|
t.Run("Several cosigners", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(args,
|
e.Run(t, append(args,
|
||||||
"--", testcli.ValidatorAddr, hVerify.StringLE())...)
|
"--", validatorAddr, hVerify.StringLE())...)
|
||||||
e.CheckTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEP17ImportToken(t *testing.T) {
|
func TestNEP17ImportToken(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
walletPath := filepath.Join(tmpDir, "walletForImport.json")
|
walletPath := filepath.Join(tmpDir, "walletForImport.json")
|
||||||
|
|
||||||
|
@ -328,37 +322,37 @@ func TestNEP17ImportToken(t *testing.T) {
|
||||||
|
|
||||||
// missing token hash
|
// missing token hash
|
||||||
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath)
|
"--wallet", walletPath)
|
||||||
|
|
||||||
// additional parameter
|
// additional parameter
|
||||||
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--token", gasContractHash.StringLE(), "useless")
|
"--token", gasContractHash.StringLE(), "useless")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "import",
|
e.Run(t, "neo-go", "wallet", "nep17", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--token", gasContractHash.StringLE())
|
"--token", gasContractHash.StringLE())
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "import",
|
e.Run(t, "neo-go", "wallet", "nep17", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--token", address.Uint160ToString(neoContractHash)) // try address instead of sh
|
"--token", address.Uint160ToString(neoContractHash)) // try address instead of sh
|
||||||
|
|
||||||
// not a NEP-17 token
|
// not a NEP-17 token
|
||||||
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--token", nnsContractHash.StringLE())
|
"--token", nnsContractHash.StringLE())
|
||||||
|
|
||||||
t.Run("Info", func(t *testing.T) {
|
t.Run("Info", func(t *testing.T) {
|
||||||
checkGASInfo := func(t *testing.T) {
|
checkGASInfo := func(t *testing.T) {
|
||||||
e.CheckNextLine(t, "^Name:\\s*GasToken")
|
e.checkNextLine(t, "^Name:\\s*GasToken")
|
||||||
e.CheckNextLine(t, "^Symbol:\\s*GAS")
|
e.checkNextLine(t, "^Symbol:\\s*GAS")
|
||||||
e.CheckNextLine(t, "^Hash:\\s*"+gasContractHash.StringLE())
|
e.checkNextLine(t, "^Hash:\\s*"+gasContractHash.StringLE())
|
||||||
e.CheckNextLine(t, "^Decimals:\\s*8")
|
e.checkNextLine(t, "^Decimals:\\s*8")
|
||||||
e.CheckNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash))
|
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash))
|
||||||
e.CheckNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName))
|
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName))
|
||||||
}
|
}
|
||||||
t.Run("excessive parameters", func(t *testing.T) {
|
t.Run("excessive parameters", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "nep17", "info",
|
e.RunWithError(t, "neo-go", "wallet", "nep17", "info",
|
||||||
|
@ -375,12 +369,12 @@ func TestNEP17ImportToken(t *testing.T) {
|
||||||
checkGASInfo(t)
|
checkGASInfo(t)
|
||||||
_, err := e.Out.ReadString('\n')
|
_, err := e.Out.ReadString('\n')
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
e.CheckNextLine(t, "^Name:\\s*NeoToken")
|
e.checkNextLine(t, "^Name:\\s*NeoToken")
|
||||||
e.CheckNextLine(t, "^Symbol:\\s*NEO")
|
e.checkNextLine(t, "^Symbol:\\s*NEO")
|
||||||
e.CheckNextLine(t, "^Hash:\\s*"+neoContractHash.StringLE())
|
e.checkNextLine(t, "^Hash:\\s*"+neoContractHash.StringLE())
|
||||||
e.CheckNextLine(t, "^Decimals:\\s*0")
|
e.checkNextLine(t, "^Decimals:\\s*0")
|
||||||
e.CheckNextLine(t, "^Address:\\s*"+address.Uint160ToString(neoContractHash))
|
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(neoContractHash))
|
||||||
e.CheckNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName))
|
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName))
|
||||||
})
|
})
|
||||||
t.Run("Remove", func(t *testing.T) {
|
t.Run("Remove", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "nep17", "remove",
|
e.RunWithError(t, "neo-go", "wallet", "nep17", "remove",
|
|
@ -1,28 +0,0 @@
|
||||||
package options
|
|
||||||
|
|
||||||
import "go.uber.org/zap/zapcore"
|
|
||||||
|
|
||||||
// FilteringCore is custom implementation of zapcore.Core that allows to filter
|
|
||||||
// log entries using custom filtering function.
|
|
||||||
type FilteringCore struct {
|
|
||||||
zapcore.Core
|
|
||||||
filter FilterFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterFunc is the filter function that is called to check whether the given
|
|
||||||
// entry together with the associated fields is to be written to a core or not.
|
|
||||||
type FilterFunc func(zapcore.Entry) bool
|
|
||||||
|
|
||||||
// NewFilteringCore returns a core middleware that uses the given filter function
|
|
||||||
// to decide whether to log this message or not.
|
|
||||||
func NewFilteringCore(next zapcore.Core, filter FilterFunc) zapcore.Core {
|
|
||||||
return &FilteringCore{next, filter}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check implements zapcore.Core interface and performs log entries filtering.
|
|
||||||
func (c *FilteringCore) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
|
||||||
if c.filter(e) {
|
|
||||||
return c.Core.Check(e, ce)
|
|
||||||
}
|
|
||||||
return ce
|
|
||||||
}
|
|
|
@ -6,61 +6,26 @@ package options
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"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/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"
|
||||||
"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"
|
"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 is the default timeout used for RPC requests.
|
const DefaultTimeout = 10 * time.Second
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
||||||
// check for flag presence in the context.
|
// check for flag presence in the context.
|
||||||
const RPCEndpointFlag = "rpc-endpoint"
|
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
|
// Network is a set of flags for choosing the network to operate on
|
||||||
// (privnet/mainnet/testnet).
|
// (privnet/mainnet/testnet).
|
||||||
var Network = []cli.Flag{
|
var Network = []cli.Flag{
|
||||||
cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration (if --config-file option is not specified)"},
|
cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration"},
|
||||||
cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration (if --config-file option is not specified)"},
|
cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration"},
|
||||||
cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration (if --config-file option is not specified)"},
|
cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration"},
|
||||||
cli.BoolFlag{Name: "unittest", Hidden: true},
|
cli.BoolFlag{Name: "unittest", Hidden: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,42 +42,7 @@ var RPC = []cli.Flag{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Historic is a flag for commands that can perform historic invocations.
|
|
||||||
var Historic = cli.StringFlag{
|
|
||||||
Name: "historic",
|
|
||||||
Usage: "Use historic state (height, block hash or state root hash)",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is a flag for commands that use node configuration.
|
|
||||||
var Config = cli.StringFlag{
|
|
||||||
Name: "config-path",
|
|
||||||
Usage: "path to directory with per-network configuration files (may be overridden by --config-file option for the configuration file)",
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigFile is a flag for commands that use node configuration and provide
|
|
||||||
// path to the specific config file instead of config path.
|
|
||||||
var ConfigFile = cli.StringFlag{
|
|
||||||
Name: "config-file",
|
|
||||||
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",
|
|
||||||
Usage: "enable debug logging (LOTS of output, overrides configuration)",
|
|
||||||
}
|
|
||||||
|
|
||||||
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
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
|
// GetNetwork examines Context's flags and returns the appropriate network. It
|
||||||
// defaults to PrivNet if no flags are given.
|
// defaults to PrivNet if no flags are given.
|
||||||
|
@ -136,9 +66,6 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
|
||||||
if dur == 0 {
|
if dur == 0 {
|
||||||
dur = DefaultTimeout
|
dur = DefaultTimeout
|
||||||
}
|
}
|
||||||
if !ctx.IsSet("timeout") && ctx.Bool("await") {
|
|
||||||
dur = DefaultAwaitableTimeout
|
|
||||||
}
|
|
||||||
return context.WithTimeout(context.Background(), dur)
|
return context.WithTimeout(context.Background(), dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,253 +85,3 @@ func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cl
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInvoker returns an invoker using the given RPC client, context and signers.
|
|
||||||
// It parses "--historic" parameter to adjust it.
|
|
||||||
func GetInvoker(c *rpcclient.Client, ctx *cli.Context, signers []transaction.Signer) (*invoker.Invoker, cli.ExitCoder) {
|
|
||||||
historic := ctx.String("historic")
|
|
||||||
if historic == "" {
|
|
||||||
return invoker.New(c, signers), nil
|
|
||||||
}
|
|
||||||
if index, err := strconv.ParseUint(historic, 10, 32); err == nil {
|
|
||||||
return invoker.NewHistoricAtHeight(uint32(index), c, signers), nil
|
|
||||||
}
|
|
||||||
if u256, err := util.Uint256DecodeStringLE(historic); err == nil {
|
|
||||||
// Might as well be a block hash, but it makes no practical difference.
|
|
||||||
return invoker.NewHistoricWithState(u256, c, signers), nil
|
|
||||||
}
|
|
||||||
return nil, cli.NewExitError(errInvalidHistoric, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRPCWithInvoker combines GetRPCClient with GetInvoker for cases where it's
|
|
||||||
// appropriate to do so.
|
|
||||||
func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transaction.Signer) (*rpcclient.Client, *invoker.Invoker, cli.ExitCoder) {
|
|
||||||
c, err := GetRPCClient(gctx, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
inv, err := GetInvoker(c, ctx, signers)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return c, inv, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
)
|
|
||||||
if len(configFile) != 0 {
|
|
||||||
return config.LoadFile(configFile, relativePath)
|
|
||||||
}
|
|
||||||
var configPath = "./config"
|
|
||||||
if argCp := ctx.String("config-path"); argCp != "" {
|
|
||||||
configPath = argCp
|
|
||||||
}
|
|
||||||
return config.Load(configPath, GetNetwork(ctx), relativePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// _winfileSinkRegistered denotes whether zap has registered
|
|
||||||
// user-supplied factory for all sinks with `winfile`-prefixed scheme.
|
|
||||||
_winfileSinkRegistered bool
|
|
||||||
_winfileSinkCloser func() error
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleLoggingParams reads logging parameters.
|
|
||||||
// If a user selected debug level -- function enables it.
|
|
||||||
// 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
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if len(cfg.LogLevel) > 0 {
|
|
||||||
level, err = zapcore.ParseLevel(cfg.LogLevel)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("log setting: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if debug {
|
|
||||||
level = zapcore.DebugLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
cc := zap.NewProductionConfig()
|
|
||||||
cc.DisableCaller = true
|
|
||||||
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.Encoding = "console"
|
|
||||||
cc.Level = zap.NewAtomicLevelAt(level)
|
|
||||||
cc.Sampling = nil
|
|
||||||
|
|
||||||
if logPath := cfg.LogPath; logPath != "" {
|
|
||||||
if err := io.MakeDirForFile(logPath, "logger"); err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if !_winfileSinkRegistered {
|
|
||||||
// See https://github.com/uber-go/zap/issues/621.
|
|
||||||
err := zap.RegisterSink("winfile", func(u *url.URL) (zap.Sink, error) {
|
|
||||||
if u.User != nil {
|
|
||||||
return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u)
|
|
||||||
}
|
|
||||||
if u.Fragment != "" {
|
|
||||||
return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u)
|
|
||||||
}
|
|
||||||
if u.RawQuery != "" {
|
|
||||||
return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u)
|
|
||||||
}
|
|
||||||
// Error messages are better if we check hostname and port separately.
|
|
||||||
if u.Port() != "" {
|
|
||||||
return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u)
|
|
||||||
}
|
|
||||||
if hn := u.Hostname(); hn != "" && hn != "localhost" {
|
|
||||||
return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u)
|
|
||||||
}
|
|
||||||
switch u.Path {
|
|
||||||
case "stdout":
|
|
||||||
return os.Stdout, nil
|
|
||||||
case "stderr":
|
|
||||||
return os.Stderr, nil
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile(u.Path[1:], // Remove leading slash left after url.Parse.
|
|
||||||
os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
|
||||||
_winfileSinkCloser = func() error {
|
|
||||||
_winfileSinkCloser = nil
|
|
||||||
return f.Close()
|
|
||||||
}
|
|
||||||
return f, err
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("failed to register windows-specific sinc: %w", err)
|
|
||||||
}
|
|
||||||
_winfileSinkRegistered = true
|
|
||||||
}
|
|
||||||
logPath = "winfile:///" + logPath
|
|
||||||
}
|
|
||||||
|
|
||||||
cc.OutputPaths = []string{logPath}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
package options_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/app"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetRPCClient(t *testing.T) {
|
func TestGetRPCClient(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
t.Run("no endpoint", func(t *testing.T) {
|
t.Run("no endpoint", func(t *testing.T) {
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
ctx := cli.NewContext(app.New(), set, nil)
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
gctx, _ := options.GetTimeoutContext(ctx)
|
gctx, _ := options.GetTimeoutContext(ctx)
|
||||||
_, ec := options.GetRPCClient(gctx, ctx)
|
_, ec := options.GetRPCClient(gctx, ctx)
|
||||||
require.Equal(t, 1, ec.ExitCode())
|
require.Equal(t, 1, ec.ExitCode())
|
||||||
|
@ -24,8 +22,8 @@ func TestGetRPCClient(t *testing.T) {
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
t.Run("success", func(t *testing.T) {
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
set.String(options.RPCEndpointFlag, "http://"+e.RPC.Addresses()[0], "")
|
set.String(options.RPCEndpointFlag, "http://"+e.RPC.Addr, "")
|
||||||
ctx := cli.NewContext(app.New(), set, nil)
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
gctx, _ := options.GetTimeoutContext(ctx)
|
gctx, _ := options.GetTimeoutContext(ctx)
|
||||||
_, ec := options.GetRPCClient(gctx, ctx)
|
_, ec := options.GetRPCClient(gctx, ctx)
|
||||||
require.Nil(t, ec)
|
require.Nil(t, ec)
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"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/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
)
|
)
|
||||||
|
@ -15,10 +16,16 @@ import (
|
||||||
// as an input to `multisig sign`. If a wallet.Account is given and can sign,
|
// as an input to `multisig sign`. If a wallet.Account is given and can sign,
|
||||||
// it's signed as well using it.
|
// it's signed as well using it.
|
||||||
func InitAndSave(net netmode.Magic, tx *transaction.Transaction, acc *wallet.Account, filename string) error {
|
func InitAndSave(net netmode.Magic, tx *transaction.Transaction, acc *wallet.Account, filename string) error {
|
||||||
scCtx := context.NewParameterContext(context.TransactionType, net, tx)
|
scCtx := context.NewParameterContext("Neo.Network.P2P.Payloads.Transaction", net, tx)
|
||||||
if acc != nil && acc.CanSign() {
|
if acc != nil && acc.CanSign() {
|
||||||
sign := acc.SignHashable(net, tx)
|
priv := acc.PrivateKey()
|
||||||
if err := scCtx.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
|
pub := priv.PublicKey()
|
||||||
|
sign := priv.SignHashable(uint32(net), tx)
|
||||||
|
h, err := address.StringToUint160(acc.Address)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid address: %s", acc.Address)
|
||||||
|
}
|
||||||
|
if err := scCtx.AddSignature(h, acc.Contract, pub, sign); err != nil {
|
||||||
return fmt.Errorf("can't add signature: %w", err)
|
return fmt.Errorf("can't add signature: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package query
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -110,10 +111,7 @@ func queryTx(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
|
DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,49 +120,47 @@ func DumpApplicationLog(
|
||||||
res *result.ApplicationLog,
|
res *result.ApplicationLog,
|
||||||
tx *transaction.Transaction,
|
tx *transaction.Transaction,
|
||||||
txMeta *result.TransactionMetadata,
|
txMeta *result.TransactionMetadata,
|
||||||
verbose bool) error {
|
verbose bool) {
|
||||||
var buf []byte
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
buf = fmt.Appendf(buf, "Hash:\t%s\n", tx.Hash().StringLE())
|
// Ignore the errors below because `Write` to buffer doesn't return error.
|
||||||
buf = fmt.Appendf(buf, "OnChain:\t%t\n", res != nil)
|
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 {
|
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 {
|
} else {
|
||||||
if txMeta != nil {
|
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 {
|
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 {
|
} 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 {
|
if verbose {
|
||||||
for _, sig := range tx.Signers {
|
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())
|
_, _ = tw.Write([]byte("SystemFee:\t" + fixedn.Fixed8(tx.SystemFee).String() + " GAS\n"))
|
||||||
buf = fmt.Appendf(buf, "NetworkFee:\t%s GAS\n", fixedn.Fixed8(tx.NetworkFee).String())
|
_, _ = tw.Write([]byte("NetworkFee:\t" + fixedn.Fixed8(tx.NetworkFee).String() + " GAS\n"))
|
||||||
buf = fmt.Appendf(buf, "Script:\t%s\n", base64.StdEncoding.EncodeToString(tx.Script))
|
_, _ = tw.Write([]byte("Script:\t" + base64.StdEncoding.EncodeToString(tx.Script) + "\n"))
|
||||||
v := vm.New()
|
v := vm.New()
|
||||||
v.Load(tx.Script)
|
v.Load(tx.Script)
|
||||||
opts := bytes.NewBuffer(nil)
|
v.PrintOps(tw)
|
||||||
v.PrintOps(opts)
|
|
||||||
buf = append(buf, opts.Bytes()...)
|
|
||||||
if res != nil {
|
if res != nil {
|
||||||
for _, e := range res.Executions {
|
for _, e := range res.Executions {
|
||||||
if e.VMState != vmstate.Halt {
|
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)
|
_ = tw.Flush()
|
||||||
_, err := tw.Write(buf)
|
fmt.Fprint(ctx.App.Writer, buf.String())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return tw.Flush()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryCandidates(ctx *cli.Context) error {
|
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
|
return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1
|
||||||
})
|
})
|
||||||
var res []byte
|
buf := bytes.NewBuffer(nil)
|
||||||
res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n")
|
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
|
||||||
|
_, _ = tw.Write([]byte("Key\tVotes\tCommittee\tConsensus\n"))
|
||||||
for _, val := range vals {
|
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)
|
_ = tw.Flush()
|
||||||
_, err = tw.Write(res)
|
fmt.Fprint(ctx.App.Writer, buf.String())
|
||||||
if err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
return tw.Flush()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryCommittee(ctx *cli.Context) error {
|
func queryCommittee(ctx *cli.Context) error {
|
||||||
|
@ -234,7 +228,7 @@ func queryCommittee(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range comm {
|
for _, k := range comm {
|
||||||
fmt.Fprintln(ctx.App.Writer, k.StringCompressed())
|
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes()))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -305,7 +299,7 @@ func queryVoter(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
voted := "null"
|
voted := "null"
|
||||||
if st.VoteTo != nil {
|
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, "\tVoted: %s\n", voted)
|
||||||
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package query_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
@ -10,7 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"github.com/nspcc-dev/neo-go/internal/random"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"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/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
@ -23,76 +22,78 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQueryTx(t *testing.T) {
|
func TestQueryTx(t *testing.T) {
|
||||||
e := testcli.NewExecutorSuspended(t)
|
e := newExecutorSuspended(t)
|
||||||
|
|
||||||
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
|
w, err := wallet.NewWalletFromFile("testdata/testwallet.json")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
transferArgs := []string{
|
transferArgs := []string{
|
||||||
"neo-go", "wallet", "nep17", "transfer",
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--to", w.Accounts[0].Address,
|
"--to", w.Accounts[0].Address,
|
||||||
"--token", "NEO",
|
"--token", "NEO",
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
}
|
}
|
||||||
|
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, append(transferArgs, "--amount", "1")...)
|
e.Run(t, append(transferArgs, "--amount", "1")...)
|
||||||
line := e.GetNextLine(t)
|
line := e.getNextLine(t)
|
||||||
txHash, err := util.Uint256DecodeStringLE(line)
|
txHash, err := util.Uint256DecodeStringLE(line)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tx, ok := e.Chain.GetMemPool().TryGetValue(txHash)
|
tx, ok := e.Chain.GetMemPool().TryGetValue(txHash)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
args := []string{"neo-go", "query", "tx", "--rpc-endpoint", "http://" + e.RPC.Addresses()[0]}
|
args := []string{"neo-go", "query", "tx", "--rpc-endpoint", "http://" + e.RPC.Addr}
|
||||||
e.Run(t, append(args, txHash.StringLE())...)
|
e.Run(t, append(args, txHash.StringLE())...)
|
||||||
e.CheckNextLine(t, `Hash:\s+`+txHash.StringLE())
|
e.checkNextLine(t, `Hash:\s+`+txHash.StringLE())
|
||||||
e.CheckNextLine(t, `OnChain:\s+false`)
|
e.checkNextLine(t, `OnChain:\s+false`)
|
||||||
e.CheckNextLine(t, `ValidUntil:\s+`+strconv.FormatUint(uint64(tx.ValidUntilBlock), 10))
|
e.checkNextLine(t, `ValidUntil:\s+`+strconv.FormatUint(uint64(tx.ValidUntilBlock), 10))
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
|
|
||||||
|
height := e.Chain.BlockHeight()
|
||||||
go e.Chain.Run()
|
go e.Chain.Run()
|
||||||
require.Eventually(t, func() bool { _, aerErr := e.Chain.GetAppExecResults(txHash, trigger.Application); return aerErr == nil }, time.Second*2, time.Millisecond*50)
|
require.Eventually(t, func() bool { return e.Chain.BlockHeight() > height }, time.Second*2, time.Millisecond*50)
|
||||||
|
|
||||||
e.Run(t, append(args, txHash.StringLE())...)
|
e.Run(t, append(args, txHash.StringLE())...)
|
||||||
e.CheckNextLine(t, `Hash:\s+`+txHash.StringLE())
|
e.checkNextLine(t, `Hash:\s+`+txHash.StringLE())
|
||||||
e.CheckNextLine(t, `OnChain:\s+true`)
|
e.checkNextLine(t, `OnChain:\s+true`)
|
||||||
|
|
||||||
_, height, err := e.Chain.GetTransaction(txHash)
|
_, height, err = e.Chain.GetTransaction(txHash)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
e.CheckNextLine(t, `BlockHash:\s+`+e.Chain.GetHeaderHash(height).StringLE())
|
e.checkNextLine(t, `BlockHash:\s+`+e.Chain.GetHeaderHash(int(height)).StringLE())
|
||||||
e.CheckNextLine(t, `Success:\s+true`)
|
e.checkNextLine(t, `Success:\s+true`)
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
|
|
||||||
t.Run("verbose", func(t *testing.T) {
|
t.Run("verbose", func(t *testing.T) {
|
||||||
e.Run(t, append(args, "--verbose", txHash.StringLE())...)
|
e.Run(t, append(args, "--verbose", txHash.StringLE())...)
|
||||||
compareQueryTxVerbose(t, e, tx)
|
e.compareQueryTxVerbose(t, tx)
|
||||||
|
|
||||||
t.Run("FAULT", func(t *testing.T) {
|
t.Run("FAULT", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", validatorWallet,
|
||||||
"--address", testcli.ValidatorAddr,
|
"--address", validatorAddr,
|
||||||
"--force",
|
"--force",
|
||||||
random.Uint160().StringLE(),
|
random.Uint160().StringLE(),
|
||||||
"randomMethod")
|
"randomMethod")
|
||||||
|
|
||||||
e.CheckNextLine(t, `Warning:`)
|
e.checkNextLine(t, `Warning:`)
|
||||||
e.CheckNextLine(t, "Sending transaction")
|
e.checkNextLine(t, "Sending transaction")
|
||||||
line := strings.TrimPrefix(e.GetNextLine(t), "Sent invocation transaction ")
|
line := strings.TrimPrefix(e.getNextLine(t), "Sent invocation transaction ")
|
||||||
txHash, err := util.Uint256DecodeStringLE(line)
|
txHash, err := util.Uint256DecodeStringLE(line)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Eventually(t, func() bool { _, aerErr := e.Chain.GetAppExecResults(txHash, trigger.Application); return aerErr == nil }, time.Second*2, time.Millisecond*50)
|
height := e.Chain.BlockHeight()
|
||||||
|
require.Eventually(t, func() bool { return e.Chain.BlockHeight() > height }, time.Second*2, time.Millisecond*50)
|
||||||
|
|
||||||
tx, _, err := e.Chain.GetTransaction(txHash)
|
tx, _, err := e.Chain.GetTransaction(txHash)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
e.Run(t, append(args, "--verbose", txHash.StringLE())...)
|
e.Run(t, append(args, "--verbose", txHash.StringLE())...)
|
||||||
compareQueryTxVerbose(t, e, tx)
|
e.compareQueryTxVerbose(t, tx)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -112,43 +113,43 @@ func TestQueryTx(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareQueryTxVerbose(t *testing.T, e *testcli.Executor, tx *transaction.Transaction) {
|
func (e *executor) compareQueryTxVerbose(t *testing.T, tx *transaction.Transaction) {
|
||||||
e.CheckNextLine(t, `Hash:\s+`+tx.Hash().StringLE())
|
e.checkNextLine(t, `Hash:\s+`+tx.Hash().StringLE())
|
||||||
e.CheckNextLine(t, `OnChain:\s+true`)
|
e.checkNextLine(t, `OnChain:\s+true`)
|
||||||
_, height, err := e.Chain.GetTransaction(tx.Hash())
|
_, height, err := e.Chain.GetTransaction(tx.Hash())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
e.CheckNextLine(t, `BlockHash:\s+`+e.Chain.GetHeaderHash(height).StringLE())
|
e.checkNextLine(t, `BlockHash:\s+`+e.Chain.GetHeaderHash(int(height)).StringLE())
|
||||||
|
|
||||||
res, _ := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
res, _ := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||||
e.CheckNextLine(t, fmt.Sprintf(`Success:\s+%t`, res[0].Execution.VMState == vmstate.Halt))
|
e.checkNextLine(t, fmt.Sprintf(`Success:\s+%t`, res[0].Execution.VMState == vmstate.Halt))
|
||||||
for _, s := range tx.Signers {
|
for _, s := range tx.Signers {
|
||||||
e.CheckNextLine(t, fmt.Sprintf(`Signer:\s+%s\s*\(%s\)`, address.Uint160ToString(s.Account), s.Scopes.String()))
|
e.checkNextLine(t, fmt.Sprintf(`Signer:\s+%s\s*\(%s\)`, address.Uint160ToString(s.Account), s.Scopes.String()))
|
||||||
}
|
}
|
||||||
e.CheckNextLine(t, `SystemFee:\s+`+fixedn.Fixed8(tx.SystemFee).String()+" GAS$")
|
e.checkNextLine(t, `SystemFee:\s+`+fixedn.Fixed8(tx.SystemFee).String()+" GAS$")
|
||||||
e.CheckNextLine(t, `NetworkFee:\s+`+fixedn.Fixed8(tx.NetworkFee).String()+" GAS$")
|
e.checkNextLine(t, `NetworkFee:\s+`+fixedn.Fixed8(tx.NetworkFee).String()+" GAS$")
|
||||||
e.CheckNextLine(t, `Script:\s+`+regexp.QuoteMeta(base64.StdEncoding.EncodeToString(tx.Script)))
|
e.checkNextLine(t, `Script:\s+`+regexp.QuoteMeta(base64.StdEncoding.EncodeToString(tx.Script)))
|
||||||
c := vm.NewContext(tx.Script)
|
c := vm.NewContext(tx.Script)
|
||||||
n := 0
|
n := 0
|
||||||
for ; c.NextIP() < c.LenInstr(); _, _, err = c.Next() {
|
for ; c.NextIP() < c.LenInstr(); _, _, err = c.Next() {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
e.CheckScriptDump(t, n)
|
e.checkScriptDump(t, n)
|
||||||
|
|
||||||
if res[0].Execution.VMState != vmstate.Halt {
|
if res[0].Execution.VMState != vmstate.Halt {
|
||||||
e.CheckNextLine(t, `Exception:\s+`+regexp.QuoteMeta(res[0].Execution.FaultException))
|
e.checkNextLine(t, `Exception:\s+`+regexp.QuoteMeta(res[0].Execution.FaultException))
|
||||||
}
|
}
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryHeight(t *testing.T) {
|
func TestQueryHeight(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
args := []string{"neo-go", "query", "height", "--rpc-endpoint", "http://" + e.RPC.Addresses()[0]}
|
args := []string{"neo-go", "query", "height", "--rpc-endpoint", "http://" + e.RPC.Addr}
|
||||||
e.Run(t, args...)
|
e.Run(t, args...)
|
||||||
e.CheckNextLine(t, `^Latest block: [0-9]+$`)
|
e.checkNextLine(t, `^Latest block: [0-9]+$`)
|
||||||
e.CheckNextLine(t, `^Validated state: [0-9]+$`)
|
e.checkNextLine(t, `^Validated state: [0-9]+$`)
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
t.Run("excessive arguments", func(t *testing.T) {
|
t.Run("excessive arguments", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(args, "something")...)
|
e.RunWithError(t, append(args, "something")...)
|
||||||
})
|
})
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -32,13 +34,22 @@ import (
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// _winfileSinkRegistered denotes whether zap has registered
|
||||||
|
// user-supplied factory for all sinks with `winfile`-prefixed scheme.
|
||||||
|
_winfileSinkRegistered bool
|
||||||
|
_winfileSinkCloser func() error
|
||||||
|
)
|
||||||
|
|
||||||
// NewCommands returns 'node' command.
|
// NewCommands returns 'node' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []cli.Command {
|
||||||
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
var cfgFlags = []cli.Flag{
|
||||||
|
cli.StringFlag{Name: "config-path", Usage: "path to directory with configuration files"},
|
||||||
|
}
|
||||||
cfgFlags = append(cfgFlags, options.Network...)
|
cfgFlags = append(cfgFlags, options.Network...)
|
||||||
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
|
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
|
||||||
copy(cfgWithCountFlags, cfgFlags)
|
copy(cfgWithCountFlags, cfgFlags)
|
||||||
cfgFlags = append(cfgFlags, options.Debug)
|
cfgFlags = append(cfgFlags, cli.BoolFlag{Name: "debug, d", Usage: "enable debug logging (LOTS of output)"})
|
||||||
|
|
||||||
cfgWithCountFlags = append(cfgWithCountFlags,
|
cfgWithCountFlags = append(cfgWithCountFlags,
|
||||||
cli.UintFlag{
|
cli.UintFlag{
|
||||||
|
@ -74,18 +85,11 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "use if dump is incremental",
|
Usage: "use if dump is incremental",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var cfgHeightFlags = make([]cli.Flag, len(cfgFlags)+1)
|
|
||||||
copy(cfgHeightFlags, cfgFlags)
|
|
||||||
cfgHeightFlags[len(cfgHeightFlags)-1] = cli.UintFlag{
|
|
||||||
Name: "height",
|
|
||||||
Usage: "Height of the state to reset DB to",
|
|
||||||
Required: true,
|
|
||||||
}
|
|
||||||
return []cli.Command{
|
return []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "node",
|
Name: "node",
|
||||||
Usage: "start a NeoGo node",
|
Usage: "start a NEO node",
|
||||||
UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t]",
|
||||||
Action: startServer,
|
Action: startServer,
|
||||||
Flags: cfgFlags,
|
Flags: cfgFlags,
|
||||||
},
|
},
|
||||||
|
@ -96,24 +100,17 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "dump blocks (starting with block #1) to the file",
|
Usage: "dump blocks (starting with block #1) to the file",
|
||||||
UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t]",
|
||||||
Action: dumpDB,
|
Action: dumpDB,
|
||||||
Flags: cfgCountOutFlags,
|
Flags: cfgCountOutFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "restore",
|
Name: "restore",
|
||||||
Usage: "restore blocks from the file",
|
Usage: "restore blocks from the file",
|
||||||
UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t]",
|
||||||
Action: restoreDB,
|
Action: restoreDB,
|
||||||
Flags: cfgCountInFlags,
|
Flags: cfgCountInFlags,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "reset",
|
|
||||||
Usage: "reset database to the previous state",
|
|
||||||
UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t] [--config-file file]",
|
|
||||||
Action: resetDB,
|
|
||||||
Flags: cfgHeightFlags,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -131,23 +128,103 @@ func newGraceContext() context.Context {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
configPath := "./config"
|
||||||
|
if argCp := ctx.String("config-path"); argCp != "" {
|
||||||
|
configPath = argCp
|
||||||
|
}
|
||||||
|
return config.Load(configPath, options.GetNetwork(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleLoggingParams reads logging parameters.
|
||||||
|
// If a user selected debug level -- function enables it.
|
||||||
|
// 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.
|
||||||
|
func handleLoggingParams(ctx *cli.Context, cfg config.ApplicationConfiguration) (*zap.Logger, func() error, error) {
|
||||||
|
level := zapcore.InfoLevel
|
||||||
|
if ctx.Bool("debug") {
|
||||||
|
level = zapcore.DebugLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
cc := zap.NewProductionConfig()
|
||||||
|
cc.DisableCaller = true
|
||||||
|
cc.DisableStacktrace = true
|
||||||
|
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
|
||||||
|
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||||
|
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||||
|
cc.Encoding = "console"
|
||||||
|
cc.Level = zap.NewAtomicLevelAt(level)
|
||||||
|
cc.Sampling = nil
|
||||||
|
|
||||||
|
if logPath := cfg.LogPath; logPath != "" {
|
||||||
|
if err := io.MakeDirForFile(logPath, "logger"); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
if !_winfileSinkRegistered {
|
||||||
|
// See https://github.com/uber-go/zap/issues/621.
|
||||||
|
err := zap.RegisterSink("winfile", func(u *url.URL) (zap.Sink, error) {
|
||||||
|
if u.User != nil {
|
||||||
|
return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
if u.Fragment != "" {
|
||||||
|
return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
if u.RawQuery != "" {
|
||||||
|
return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
// Error messages are better if we check hostname and port separately.
|
||||||
|
if u.Port() != "" {
|
||||||
|
return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
if hn := u.Hostname(); hn != "" && hn != "localhost" {
|
||||||
|
return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u)
|
||||||
|
}
|
||||||
|
switch u.Path {
|
||||||
|
case "stdout":
|
||||||
|
return os.Stdout, nil
|
||||||
|
case "stderr":
|
||||||
|
return os.Stderr, nil
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(u.Path[1:], // Remove leading slash left after url.Parse.
|
||||||
|
os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||||
|
_winfileSinkCloser = func() error {
|
||||||
|
_winfileSinkCloser = nil
|
||||||
|
return f.Close()
|
||||||
|
}
|
||||||
|
return f, err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to register windows-specific sinc: %w", err)
|
||||||
|
}
|
||||||
|
_winfileSinkRegistered = true
|
||||||
|
}
|
||||||
|
logPath = "winfile:///" + logPath
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.OutputPaths = []string{logPath}
|
||||||
|
}
|
||||||
|
|
||||||
|
log, err := cc.Build()
|
||||||
|
return log, _winfileSinkCloser, err
|
||||||
|
}
|
||||||
|
|
||||||
func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *metrics.Service, *metrics.Service, error) {
|
func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *metrics.Service, *metrics.Service, error) {
|
||||||
chain, _, err := initBlockChain(cfg, log)
|
chain, err := initBlockChain(cfg, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, cli.NewExitError(err, 1)
|
return nil, nil, nil, cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
configureAddresses(&cfg.ApplicationConfiguration)
|
||||||
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
||||||
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
|
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
|
||||||
|
|
||||||
go chain.Run()
|
go chain.Run()
|
||||||
err = prometheus.Start()
|
go prometheus.Start()
|
||||||
if err != nil {
|
go pprof.Start()
|
||||||
return nil, nil, nil, cli.NewExitError(fmt.Errorf("failed to start Prometheus service: %w", err), 1)
|
|
||||||
}
|
|
||||||
err = pprof.Start()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, cli.NewExitError(fmt.Errorf("failed to start Pprof service: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return chain, prometheus, pprof, nil
|
return chain, prometheus, pprof, nil
|
||||||
}
|
}
|
||||||
|
@ -156,11 +233,11 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := getConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
log, logCloser, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -197,9 +274,6 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
count = chainCount - start
|
count = chainCount - start
|
||||||
}
|
}
|
||||||
if start != 0 {
|
|
||||||
writer.WriteU32LE(start)
|
|
||||||
}
|
|
||||||
writer.WriteU32LE(count)
|
writer.WriteU32LE(count)
|
||||||
err = chaindump.Dump(chain, writer, start, count)
|
err = chaindump.Dump(chain, writer, start, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -212,11 +286,11 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := getConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
log, logCloser, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -237,7 +311,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
|
|
||||||
dumpDir := ctx.String("dump")
|
dumpDir := ctx.String("dump")
|
||||||
if dumpDir != "" {
|
if dumpDir != "" {
|
||||||
cfg.ApplicationConfiguration.SaveStorageBatch = true
|
cfg.ProtocolConfiguration.SaveStorageBatch = true
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||||
|
@ -325,47 +399,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetDB(ctx *cli.Context) error {
|
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (*oracle.Oracle, error) {
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
h := uint32(ctx.Uint("height"))
|
|
||||||
|
|
||||||
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
if logCloser != nil {
|
|
||||||
defer func() { _ = logCloser() }()
|
|
||||||
}
|
|
||||||
chain, store, err := initBlockChain(cfg, log)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create Blockchain instance: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = chain.Reset(h)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to reset chain state to height %d: %w", h, err), 1)
|
|
||||||
}
|
|
||||||
err = store.Close()
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to close the DB: %w", err), 1)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
if !config.Enabled {
|
if !config.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -385,19 +419,17 @@ func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *cor
|
||||||
return orc, nil
|
return orc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkConsensus(config config.Consensus, tpb time.Duration, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (consensus.Service, error) {
|
func mkConsensus(config config.Wallet, tpb time.Duration, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (consensus.Service, error) {
|
||||||
if !config.Enabled {
|
if len(config.Path) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
srv, err := consensus.NewService(consensus.Config{
|
srv, err := consensus.NewService(consensus.Config{
|
||||||
Logger: log,
|
Logger: log,
|
||||||
Broadcast: serv.BroadcastExtensible,
|
Broadcast: serv.BroadcastExtensible,
|
||||||
Chain: chain,
|
Chain: chain,
|
||||||
BlockQueue: serv.GetBlockQueue(),
|
ProtocolConfiguration: chain.GetConfig(),
|
||||||
ProtocolConfiguration: chain.GetConfig().ProtocolConfiguration,
|
|
||||||
RequestTx: serv.RequestTx,
|
RequestTx: serv.RequestTx,
|
||||||
StopTxFlow: serv.StopTxFlow,
|
Wallet: &config,
|
||||||
Wallet: config.UnlockWallet,
|
|
||||||
TimePerBlock: tpb,
|
TimePerBlock: tpb,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -422,7 +454,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 {
|
n, err := notary.NewNotary(cfg, serv.Net, serv.GetNotaryPool(), func(tx *transaction.Transaction) error {
|
||||||
err := serv.RelayTxn(tx)
|
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 fmt.Errorf("can't relay completed notary transaction: hash %s, error: %w", tx.Hash().StringLE(), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -440,12 +472,11 @@ func startServer(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := getConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
var logDebug = ctx.Bool("debug")
|
log, logCloser, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
||||||
log, logLevel, logCloser, err := options.HandleLoggingParams(logDebug, cfg.ApplicationConfiguration)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -456,10 +487,7 @@ func startServer(ctx *cli.Context) error {
|
||||||
grace, cancel := context.WithCancel(newGraceContext())
|
grace, cancel := context.WithCancel(newGraceContext())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
serverConfig, err := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -486,7 +514,7 @@ func startServer(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
dbftSrv, err := mkConsensus(cfg.ApplicationConfiguration.Consensus, serverConfig.TimePerBlock, chain, serv, log)
|
dbftSrv, err := mkConsensus(cfg.ApplicationConfiguration.UnlockWallet, serverConfig.TimePerBlock, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -498,12 +526,9 @@ func startServer(ctx *cli.Context) error {
|
||||||
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
||||||
serv.AddService(&rpcServer)
|
serv.AddService(&rpcServer)
|
||||||
|
|
||||||
serv.Start()
|
go serv.Start(errChan)
|
||||||
if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized {
|
if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized {
|
||||||
// Run RPC server in a separate routine. This is necessary to avoid a potential
|
rpcServer.Start()
|
||||||
// deadlock: Start() can write errors to errChan which is not yet read in the
|
|
||||||
// current execution context (see for-loop below).
|
|
||||||
go rpcServer.Start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
|
@ -523,10 +548,8 @@ Main:
|
||||||
shutdownErr = fmt.Errorf("server error: %w", err)
|
shutdownErr = fmt.Errorf("server error: %w", err)
|
||||||
cancel()
|
cancel()
|
||||||
case sig := <-sigCh:
|
case sig := <-sigCh:
|
||||||
var newLogLevel = zapcore.InvalidLevel
|
|
||||||
|
|
||||||
log.Info("signal received", zap.Stringer("name", sig))
|
log.Info("signal received", zap.Stringer("name", sig))
|
||||||
cfgnew, err := options.GetConfigFromContext(ctx)
|
cfgnew, err := getConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("can't reread the config file, signal ignored", zap.Error(err))
|
log.Warn("can't reread the config file, signal ignored", zap.Error(err))
|
||||||
break // Continue working.
|
break // Continue working.
|
||||||
|
@ -539,41 +562,22 @@ Main:
|
||||||
log.Warn("ApplicationConfiguration changed in incompatible way, signal ignored")
|
log.Warn("ApplicationConfiguration changed in incompatible way, signal ignored")
|
||||||
break // Continue working.
|
break // Continue working.
|
||||||
}
|
}
|
||||||
if !logDebug && cfgnew.ApplicationConfiguration.LogLevel != cfg.ApplicationConfiguration.LogLevel {
|
configureAddresses(&cfgnew.ApplicationConfiguration)
|
||||||
newLogLevel, err = zapcore.ParseLevel(cfgnew.ApplicationConfiguration.LogLevel)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("wrong LogLevel in ApplicationConfiguration, signal ignored", zap.Error(err))
|
|
||||||
break // Continue working.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch sig {
|
switch sig {
|
||||||
case sighup:
|
case sighup:
|
||||||
if newLogLevel != zapcore.InvalidLevel {
|
|
||||||
logLevel.SetLevel(newLogLevel)
|
|
||||||
log.Warn("using new logging level", zap.Stringer("level", newLogLevel))
|
|
||||||
}
|
|
||||||
serv.DelService(&rpcServer)
|
serv.DelService(&rpcServer)
|
||||||
rpcServer.Shutdown()
|
rpcServer.Shutdown()
|
||||||
rpcServer = rpcsrv.New(chain, cfgnew.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
rpcServer = rpcsrv.New(chain, cfgnew.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
||||||
serv.AddService(&rpcServer)
|
serv.AddService(&rpcServer)
|
||||||
if !cfgnew.ApplicationConfiguration.RPC.StartWhenSynchronized || serv.IsInSync() {
|
if !cfgnew.ApplicationConfiguration.RPC.StartWhenSynchronized || serv.IsInSync() {
|
||||||
// Here similar to the initial run (see above for-loop), so async.
|
rpcServer.Start()
|
||||||
go rpcServer.Start()
|
|
||||||
}
|
}
|
||||||
pprof.ShutDown()
|
pprof.ShutDown()
|
||||||
pprof = metrics.NewPprofService(cfgnew.ApplicationConfiguration.Pprof, log)
|
pprof = metrics.NewPprofService(cfgnew.ApplicationConfiguration.Pprof, log)
|
||||||
err = pprof.Start()
|
go pprof.Start()
|
||||||
if err != nil {
|
|
||||||
shutdownErr = fmt.Errorf("failed to start Pprof service: %w", err)
|
|
||||||
cancel() // Fatal error, like for RPC server.
|
|
||||||
}
|
|
||||||
prometheus.ShutDown()
|
prometheus.ShutDown()
|
||||||
prometheus = metrics.NewPrometheusService(cfgnew.ApplicationConfiguration.Prometheus, log)
|
prometheus = metrics.NewPrometheusService(cfgnew.ApplicationConfiguration.Prometheus, log)
|
||||||
err = prometheus.Start()
|
go prometheus.Start()
|
||||||
if err != nil {
|
|
||||||
shutdownErr = fmt.Errorf("failed to start Prometheus service: %w", err)
|
|
||||||
cancel() // Fatal error, like for RPC server.
|
|
||||||
}
|
|
||||||
case sigusr1:
|
case sigusr1:
|
||||||
if oracleSrv != nil {
|
if oracleSrv != nil {
|
||||||
serv.DelService(oracleSrv)
|
serv.DelService(oracleSrv)
|
||||||
|
@ -622,7 +626,7 @@ Main:
|
||||||
serv.DelConsensusService(dbftSrv)
|
serv.DelConsensusService(dbftSrv)
|
||||||
dbftSrv.Shutdown()
|
dbftSrv.Shutdown()
|
||||||
}
|
}
|
||||||
dbftSrv, err = mkConsensus(cfgnew.ApplicationConfiguration.Consensus, serverConfig.TimePerBlock, chain, serv, log)
|
dbftSrv, err = mkConsensus(cfgnew.ApplicationConfiguration.UnlockWallet, serverConfig.TimePerBlock, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to create consensus service", zap.Error(err))
|
log.Error("failed to create consensus service", zap.Error(err))
|
||||||
break // Whatever happens, I'll leave it all to chance.
|
break // Whatever happens, I'll leave it all to chance.
|
||||||
|
@ -646,29 +650,39 @@ Main:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initBlockChain initializes BlockChain with preselected DB.
|
// configureAddresses sets up addresses for RPC, Prometheus and Pprof depending from the provided config.
|
||||||
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
|
// In case RPC or Prometheus or Pprof Address provided each of them will use it.
|
||||||
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
|
||||||
if err != nil {
|
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
|
||||||
return nil, nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %w", err), 1)
|
func configureAddresses(cfg *config.ApplicationConfiguration) {
|
||||||
}
|
if cfg.Address != "" {
|
||||||
|
if cfg.RPC.Address == "" {
|
||||||
chain, err := core.NewBlockchain(store, cfg.Blockchain(), log)
|
cfg.RPC.Address = cfg.Address
|
||||||
if err != nil {
|
}
|
||||||
errText := "could not initialize blockchain: %w"
|
if cfg.Prometheus.Address == "" {
|
||||||
errArgs := []any{err}
|
cfg.Prometheus.Address = cfg.Address
|
||||||
closeErr := store.Close()
|
}
|
||||||
if closeErr != nil {
|
if cfg.Pprof.Address == "" {
|
||||||
errText += "; failed to close the DB: %w"
|
cfg.Pprof.Address = cfg.Address
|
||||||
errArgs = append(errArgs, closeErr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, cli.NewExitError(fmt.Errorf(errText, errArgs...), 1)
|
|
||||||
}
|
}
|
||||||
return chain, store, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logo returns NeoGo logo.
|
// initBlockChain initializes BlockChain with preselected DB.
|
||||||
|
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, error) {
|
||||||
|
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %w", err), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
chain, err := core.NewBlockchain(store, cfg.ProtocolConfiguration, log)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cli.NewExitError(fmt.Errorf("could not initialize blockchain: %w", err), 1)
|
||||||
|
}
|
||||||
|
return chain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logo returns Neo-Go logo.
|
||||||
func Logo() string {
|
func Logo() string {
|
||||||
return `
|
return `
|
||||||
_ ____________ __________
|
_ ____________ __________
|
||||||
|
|
|
@ -5,17 +5,14 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"go.uber.org/zap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,58 +28,13 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetConfigFromContext(t *testing.T) {
|
func TestGetConfigFromContext(t *testing.T) {
|
||||||
t.Run("config-path", func(t *testing.T) {
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
set.String("config-path", "../../config", "")
|
||||||
set.String("config-path", "../../config", "")
|
set.Bool("testnet", true, "")
|
||||||
set.Bool("testnet", true, "")
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
cfg, err := getConfigFromContext(ctx)
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
|
||||||
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
|
|
||||||
})
|
|
||||||
t.Run("config-file", func(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
|
||||||
set.String("config-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, 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) {
|
func TestHandleLoggingParams(t *testing.T) {
|
||||||
|
@ -92,74 +44,49 @@ func TestHandleLoggingParams(t *testing.T) {
|
||||||
t.Run("logdir is a file", func(t *testing.T) {
|
t.Run("logdir is a file", func(t *testing.T) {
|
||||||
logfile := filepath.Join(d, "logdir")
|
logfile := filepath.Join(d, "logdir")
|
||||||
require.NoError(t, os.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
require.NoError(t, os.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
cfg := config.ApplicationConfiguration{
|
cfg := config.ApplicationConfiguration{
|
||||||
LogPath: filepath.Join(logfile, "file.log"),
|
LogPath: filepath.Join(logfile, "file.log"),
|
||||||
}
|
}
|
||||||
_, lvl, closer, err := options.HandleLoggingParams(false, cfg)
|
_, closer, err := handleLoggingParams(ctx, cfg)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Nil(t, lvl)
|
|
||||||
require.Nil(t, closer)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("broken level", func(t *testing.T) {
|
|
||||||
cfg := config.ApplicationConfiguration{
|
|
||||||
LogPath: testLog,
|
|
||||||
LogLevel: "qwerty",
|
|
||||||
}
|
|
||||||
_, lvl, closer, err := options.HandleLoggingParams(false, cfg)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Nil(t, lvl)
|
|
||||||
require.Nil(t, closer)
|
require.Nil(t, closer)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("default", func(t *testing.T) {
|
t.Run("default", func(t *testing.T) {
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
cfg := config.ApplicationConfiguration{
|
cfg := config.ApplicationConfiguration{
|
||||||
LogPath: testLog,
|
LogPath: testLog,
|
||||||
}
|
}
|
||||||
logger, lvl, closer, err := options.HandleLoggingParams(false, cfg)
|
logger, closer, err := handleLoggingParams(ctx, cfg)
|
||||||
require.NotNil(t, lvl)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
if closer != nil {
|
if closer != nil {
|
||||||
require.NoError(t, closer())
|
require.NoError(t, closer())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
require.Equal(t, zapcore.InfoLevel, lvl.Level())
|
require.True(t, logger.Core().Enabled(zap.InfoLevel))
|
||||||
require.True(t, logger.Core().Enabled(zapcore.InfoLevel))
|
require.False(t, logger.Core().Enabled(zap.DebugLevel))
|
||||||
require.False(t, logger.Core().Enabled(zapcore.DebugLevel))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("warn", func(t *testing.T) {
|
|
||||||
cfg := config.ApplicationConfiguration{
|
|
||||||
LogPath: testLog,
|
|
||||||
LogLevel: "warn",
|
|
||||||
}
|
|
||||||
logger, lvl, closer, err := options.HandleLoggingParams(false, cfg)
|
|
||||||
require.NoError(t, err)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
if closer != nil {
|
|
||||||
require.NoError(t, closer())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
require.Equal(t, zapcore.WarnLevel, lvl.Level())
|
|
||||||
require.True(t, logger.Core().Enabled(zapcore.WarnLevel))
|
|
||||||
require.False(t, logger.Core().Enabled(zapcore.InfoLevel))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("debug", func(t *testing.T) {
|
t.Run("debug", func(t *testing.T) {
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
set.Bool("debug", true, "")
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
cfg := config.ApplicationConfiguration{
|
cfg := config.ApplicationConfiguration{
|
||||||
LogPath: testLog,
|
LogPath: testLog,
|
||||||
}
|
}
|
||||||
logger, lvl, closer, err := options.HandleLoggingParams(true, cfg)
|
logger, closer, err := handleLoggingParams(ctx, cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
if closer != nil {
|
if closer != nil {
|
||||||
require.NoError(t, closer())
|
require.NoError(t, closer())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
require.Equal(t, zapcore.DebugLevel, lvl.Level())
|
require.True(t, logger.Core().Enabled(zap.InfoLevel))
|
||||||
require.True(t, logger.Core().Enabled(zapcore.InfoLevel))
|
require.True(t, logger.Core().Enabled(zap.DebugLevel))
|
||||||
require.True(t, logger.Core().Enabled(zapcore.DebugLevel))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +101,9 @@ func TestInitBCWithMetrics(t *testing.T) {
|
||||||
set.Bool("testnet", true, "")
|
set.Bool("testnet", true, "")
|
||||||
set.Bool("debug", true, "")
|
set.Bool("debug", true, "")
|
||||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := getConfigFromContext(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
logger, _, closer, err := options.HandleLoggingParams(true, cfg.ApplicationConfiguration)
|
logger, closer, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
if closer != nil {
|
if closer != nil {
|
||||||
|
@ -358,35 +285,74 @@ func TestRestoreDB(t *testing.T) {
|
||||||
require.NoError(t, restoreDB(ctx))
|
require.NoError(t, restoreDB(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
configureAddresses(cfg)
|
||||||
|
require.Equal(t, defaultAddress, cfg.RPC.Address)
|
||||||
|
require.Equal(t, defaultAddress, cfg.Prometheus.Address)
|
||||||
|
require.Equal(t, defaultAddress, cfg.Pprof.Address)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("custom RPC address", func(t *testing.T) {
|
||||||
|
cfg := &config.ApplicationConfiguration{
|
||||||
|
Address: defaultAddress,
|
||||||
|
RPC: config.RPC{
|
||||||
|
Address: customAddress,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
configureAddresses(cfg)
|
||||||
|
require.Equal(t, cfg.RPC.Address, customAddress)
|
||||||
|
require.Equal(t, cfg.Prometheus.Address, defaultAddress)
|
||||||
|
require.Equal(t, cfg.Pprof.Address, defaultAddress)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("custom Pprof address", func(t *testing.T) {
|
||||||
|
cfg := &config.ApplicationConfiguration{
|
||||||
|
Address: defaultAddress,
|
||||||
|
Pprof: config.BasicService{
|
||||||
|
Address: customAddress,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
configureAddresses(cfg)
|
||||||
|
require.Equal(t, cfg.RPC.Address, defaultAddress)
|
||||||
|
require.Equal(t, cfg.Prometheus.Address, defaultAddress)
|
||||||
|
require.Equal(t, cfg.Pprof.Address, customAddress)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("custom Prometheus address", func(t *testing.T) {
|
||||||
|
cfg := &config.ApplicationConfiguration{
|
||||||
|
Address: defaultAddress,
|
||||||
|
Prometheus: config.BasicService{
|
||||||
|
Address: customAddress,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
configureAddresses(cfg)
|
||||||
|
require.Equal(t, cfg.RPC.Address, defaultAddress)
|
||||||
|
require.Equal(t, cfg.Prometheus.Address, customAddress)
|
||||||
|
require.Equal(t, cfg.Pprof.Address, defaultAddress)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestInitBlockChain(t *testing.T) {
|
func TestInitBlockChain(t *testing.T) {
|
||||||
t.Run("bad storage", func(t *testing.T) {
|
t.Run("bad storage", func(t *testing.T) {
|
||||||
_, _, err := initBlockChain(config.Config{}, nil)
|
_, err := initBlockChain(config.Config{}, nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("empty logger", func(t *testing.T) {
|
t.Run("empty logger", func(t *testing.T) {
|
||||||
_, _, err := initBlockChain(config.Config{
|
_, err := initBlockChain(config.Config{
|
||||||
ApplicationConfiguration: config.ApplicationConfiguration{
|
ApplicationConfiguration: config.ApplicationConfiguration{
|
||||||
DBConfiguration: dbconfig.DBConfiguration{
|
DBConfiguration: dbconfig.DBConfiguration{
|
||||||
Type: dbconfig.InMemoryDB,
|
Type: "inmemory",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResetDB(t *testing.T) {
|
|
||||||
d := t.TempDir()
|
|
||||||
err := os.Chdir(d)
|
|
||||||
require.NoError(t, err)
|
|
||||||
t.Cleanup(func() { require.NoError(t, os.Chdir(serverTestWD)) })
|
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
|
||||||
set.String("config-path", filepath.Join(serverTestWD, "..", "..", "config"), "")
|
|
||||||
set.Bool("privnet", true, "")
|
|
||||||
set.Bool("debug", true, "")
|
|
||||||
set.Int("height", 0, "")
|
|
||||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
|
||||||
err = resetDB(ctx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
96
cli/server/testdata/protocol.testnet.windows.yml
vendored
96
cli/server/testdata/protocol.testnet.windows.yml
vendored
|
@ -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"
|
|
|
@ -1,7 +1,6 @@
|
||||||
package server_test
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -11,22 +10,20 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/server"
|
"github.com/nspcc-dev/neo-go/cli/server"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServerStart(t *testing.T) {
|
func TestServerStart(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
goodCfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
|
goodCfg, err := config.LoadFile(filepath.Join("..", "config", "protocol.unit_testnet.yml"))
|
||||||
require.NoError(t, err, "could not load config")
|
require.NoError(t, err, "could not load config")
|
||||||
ptr := &goodCfg
|
ptr := &goodCfg
|
||||||
saveCfg := func(t *testing.T, f func(cfg *config.Config)) string {
|
saveCfg := func(t *testing.T, f func(cfg *config.Config)) string {
|
||||||
cfg := *ptr
|
cfg := *ptr
|
||||||
chainPath := filepath.Join(t.TempDir(), "neogotestchain")
|
chainPath := filepath.Join(t.TempDir(), "neogotestchain")
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
|
cfg.ApplicationConfiguration.DBConfiguration.Type = "leveldb"
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
||||||
f(&cfg)
|
f(&cfg)
|
||||||
out, err := yaml.Marshal(cfg)
|
out, err := yaml.Marshal(cfg)
|
||||||
|
@ -41,7 +38,7 @@ func TestServerStart(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
baseCmd := []string{"neo-go", "node", "--unittest", "--config-path", tmpDir}
|
baseCmd := []string{"neo-go", "node", "--unittest", "--config-path", tmpDir}
|
||||||
e := testcli.NewExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
t.Run("invalid config path", func(t *testing.T) {
|
t.Run("invalid config path", func(t *testing.T) {
|
||||||
e.RunWithError(t, baseCmd...)
|
e.RunWithError(t, baseCmd...)
|
||||||
|
@ -77,8 +74,7 @@ func TestServerStart(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid consensus config", func(t *testing.T) {
|
t.Run("invalid consensus config", func(t *testing.T) {
|
||||||
saveCfg(t, func(cfg *config.Config) {
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
cfg.ApplicationConfiguration.Consensus.Enabled = true
|
cfg.ApplicationConfiguration.UnlockWallet.Path = "bad_consensus_wallet.json"
|
||||||
cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path = "bad_consensus_wallet.json"
|
|
||||||
})
|
})
|
||||||
e.RunWithError(t, baseCmd...)
|
e.RunWithError(t, baseCmd...)
|
||||||
})
|
})
|
||||||
|
@ -114,7 +110,7 @@ func TestServerStart(t *testing.T) {
|
||||||
var line string
|
var line string
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
line, err = e.Out.ReadString('\n')
|
line, err = e.Out.ReadString('\n')
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
if err != nil && err != io.EOF {
|
||||||
t.Fatalf("unexpected error while reading CLI output: %s", err)
|
t.Fatalf("unexpected error while reading CLI output: %s", err)
|
||||||
}
|
}
|
||||||
return err == nil
|
return err == nil
|
||||||
|
@ -123,11 +119,11 @@ func TestServerStart(t *testing.T) {
|
||||||
for _, expected := range lines {
|
for _, expected := range lines {
|
||||||
// It should be regexp, so escape all backslashes.
|
// It should be regexp, so escape all backslashes.
|
||||||
expected = strings.ReplaceAll(expected, `\`, `\\`)
|
expected = strings.ReplaceAll(expected, `\`, `\\`)
|
||||||
e.CheckLine(t, line, expected)
|
e.checkLine(t, line, expected)
|
||||||
line = e.GetNextLine(t)
|
line = e.getNextLine(t)
|
||||||
}
|
}
|
||||||
e.CheckNextLine(t, "")
|
e.checkNextLine(t, "")
|
||||||
e.CheckEOF(t)
|
e.checkEOF(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,77 +7,45 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var generatorFlags = []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "config, c",
|
|
||||||
Usage: "Configuration file to use",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "manifest, m",
|
|
||||||
Required: true,
|
|
||||||
Usage: "Read contract manifest (*.manifest.json) file",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "out, o",
|
|
||||||
Required: true,
|
|
||||||
Usage: "Output of the compiled wrapper",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "hash",
|
|
||||||
Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var generateWrapperCmd = cli.Command{
|
var generateWrapperCmd = cli.Command{
|
||||||
Name: "generate-wrapper",
|
Name: "generate-wrapper",
|
||||||
Usage: "generate wrapper to use in other contracts",
|
Usage: "generate wrapper to use in other contracts",
|
||||||
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash>",
|
||||||
Description: `Generates a Go wrapper to use it in other smart contracts. If the
|
Description: ``,
|
||||||
--hash flag is provided, CALLT instruction is used for the target contract
|
Action: contractGenerateWrapper,
|
||||||
invocation as an optimization of the wrapper contract code. If omitted, the
|
Flags: []cli.Flag{
|
||||||
generated wrapper will be designed for dynamic hash usage, allowing
|
cli.StringFlag{
|
||||||
the hash to be specified at runtime.
|
Name: "config, c",
|
||||||
`,
|
Usage: "Configuration file to use",
|
||||||
Action: contractGenerateWrapper,
|
},
|
||||||
Flags: generatorFlags,
|
cli.StringFlag{
|
||||||
}
|
Name: "manifest, m",
|
||||||
|
Usage: "Read contract manifest (*.manifest.json) file",
|
||||||
var generateRPCWrapperCmd = cli.Command{
|
},
|
||||||
Name: "generate-rpcwrapper",
|
cli.StringFlag{
|
||||||
Usage: "generate RPC wrapper to use for data reads",
|
Name: "out, o",
|
||||||
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
Usage: "Output of the compiled contract",
|
||||||
Action: contractGenerateRPCWrapper,
|
},
|
||||||
Flags: generatorFlags,
|
cli.StringFlag{
|
||||||
|
Name: "hash",
|
||||||
|
Usage: "Smart-contract hash",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contractGenerateWrapper deploys contract.
|
||||||
func contractGenerateWrapper(ctx *cli.Context) error {
|
func contractGenerateWrapper(ctx *cli.Context) error {
|
||||||
return contractGenerateSomething(ctx, binding.Generate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func contractGenerateRPCWrapper(ctx *cli.Context) error {
|
|
||||||
return contractGenerateSomething(ctx, rpcbinding.Generate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// contractGenerateSomething reads generator parameters and calls the given callback.
|
|
||||||
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) error {
|
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var (
|
h, err := util.Uint160DecodeStringLE(strings.TrimPrefix(ctx.String("hash"), "0x"))
|
||||||
h util.Uint160
|
if err != nil {
|
||||||
err error
|
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
|
||||||
)
|
|
||||||
if hStr := ctx.String("hash"); len(hStr) != 0 {
|
|
||||||
h, err = util.Uint160DecodeStringLE(strings.TrimPrefix(hStr, "0x"))
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m, _, err := readManifest(ctx.String("manifest"), h)
|
m, _, err := readManifest(ctx.String("manifest"), h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -106,7 +74,7 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error)
|
||||||
|
|
||||||
cfg.Output = f
|
cfg.Output = f
|
||||||
|
|
||||||
err = cb(cfg)
|
err = binding.Generate(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("error during generation: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("error during generation: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package smartcontract
|
package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -46,15 +44,6 @@ func TestGenerate(t *testing.T) {
|
||||||
ReturnType: smartcontract.IntegerType,
|
ReturnType: smartcontract.IntegerType,
|
||||||
Safe: true,
|
Safe: true,
|
||||||
},
|
},
|
||||||
manifest.Method{
|
|
||||||
Name: "zum",
|
|
||||||
Parameters: []manifest.Parameter{
|
|
||||||
manifest.NewParameter("type", smartcontract.IntegerType),
|
|
||||||
manifest.NewParameter("typev", smartcontract.IntegerType),
|
|
||||||
manifest.NewParameter("func", smartcontract.IntegerType),
|
|
||||||
},
|
|
||||||
ReturnType: smartcontract.IntegerType,
|
|
||||||
},
|
|
||||||
manifest.Method{
|
manifest.Method{
|
||||||
Name: "justExecute",
|
Name: "justExecute",
|
||||||
Parameters: []manifest.Parameter{
|
Parameters: []manifest.Parameter{
|
||||||
|
@ -151,9 +140,7 @@ callflags:
|
||||||
"--hash", h.StringLE(),
|
"--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.
|
const expected = `// Package wrapper contains wrappers for MyContract contract.
|
||||||
|
|
||||||
// Package wrapper contains wrappers for MyContract contract.
|
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -174,8 +161,8 @@ func Sum(first int, second int) int {
|
||||||
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int)
|
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum2 invokes ` + "`sum`" + ` method of contract.
|
// Sum_3 invokes ` + "`sum`" + ` method of contract.
|
||||||
func Sum2(first int, second int, third int) int {
|
func Sum_3(first int, second int, third int) int {
|
||||||
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int)
|
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,13 +171,8 @@ func Sum3() int {
|
||||||
return neogointernal.CallWithToken(Hash, "sum3", int(contract.ReadOnly)).(int)
|
return neogointernal.CallWithToken(Hash, "sum3", int(contract.ReadOnly)).(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zum invokes ` + "`zum`" + ` method of contract.
|
|
||||||
func Zum(typev int, typev_ int, funcv int) int {
|
|
||||||
return neogointernal.CallWithToken(Hash, "zum", int(contract.All), typev, typev_, funcv).(int)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JustExecute invokes ` + "`justExecute`" + ` method of contract.
|
// JustExecute invokes ` + "`justExecute`" + ` method of contract.
|
||||||
func JustExecute(arr []any) {
|
func JustExecute(arr []interface{}) {
|
||||||
neogointernal.CallWithTokenNoRet(Hash, "justExecute", int(contract.All), arr)
|
neogointernal.CallWithTokenNoRet(Hash, "justExecute", int(contract.All), arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +182,7 @@ func GetPublicKey() interop.PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OtherTypes invokes ` + "`otherTypes`" + ` method of contract.
|
// OtherTypes invokes ` + "`otherTypes`" + ` method of contract.
|
||||||
func OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data any) bool {
|
func OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data interface{}) bool {
|
||||||
return neogointernal.CallWithToken(Hash, "otherTypes", int(contract.All), ctr, tx, sig, data).(bool)
|
return neogointernal.CallWithToken(Hash, "otherTypes", int(contract.All), ctr, tx, sig, data).(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +197,8 @@ func GetFromMap(intMap map[string]int, indices []string) []int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoSomething invokes ` + "`doSomething`" + ` method of contract.
|
// DoSomething invokes ` + "`doSomething`" + ` method of contract.
|
||||||
func DoSomething(bytes []byte, str string) any {
|
func DoSomething(bytes []byte, str string) interface{} {
|
||||||
return neogointernal.CallWithToken(Hash, "doSomething", int(contract.ReadStates), bytes, str).(any)
|
return neogointernal.CallWithToken(Hash, "doSomething", int(contract.ReadStates), bytes, str).(interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract.
|
// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract.
|
||||||
|
@ -233,99 +215,6 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expected, string(data))
|
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) {
|
func TestGenerateValidPackageName(t *testing.T) {
|
||||||
|
@ -335,7 +224,6 @@ func TestGenerateValidPackageName(t *testing.T) {
|
||||||
Name: "get",
|
Name: "get",
|
||||||
Parameters: []manifest.Parameter{},
|
Parameters: []manifest.Parameter{},
|
||||||
ReturnType: smartcontract.IntegerType,
|
ReturnType: smartcontract.IntegerType,
|
||||||
Safe: true,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -351,7 +239,7 @@ func TestGenerateValidPackageName(t *testing.T) {
|
||||||
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
|
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
|
||||||
}
|
}
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
|
app.Commands = []cli.Command{generateWrapperCmd}
|
||||||
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
||||||
"--manifest", manifestFile,
|
"--manifest", manifestFile,
|
||||||
"--out", outFile,
|
"--out", outFile,
|
||||||
|
@ -360,9 +248,7 @@ func TestGenerateValidPackageName(t *testing.T) {
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
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.
|
require.Equal(t, `// Package myspacecontract contains wrappers for My space contract contract.
|
||||||
|
|
||||||
// Package myspacecontract contains wrappers for My space contract contract.
|
|
||||||
package myspacecontract
|
package myspacecontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -375,176 +261,9 @@ const Hash = "\x04\x08\x15\x16\x23\x42\x43\x44\x00\x01\xca\xfe\xba\xbe\xde\xad\x
|
||||||
|
|
||||||
// Get invokes `+"`get`"+` method of contract.
|
// Get invokes `+"`get`"+` method of contract.
|
||||||
func Get() int {
|
func Get() int {
|
||||||
return neogointernal.CallWithToken(Hash, "get", int(contract.ReadOnly)).(int)
|
return neogointernal.CallWithToken(Hash, "get", int(contract.All)).(int)
|
||||||
}
|
}
|
||||||
`, string(data))
|
`, string(data))
|
||||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
|
||||||
"--manifest", manifestFile,
|
|
||||||
"--out", outFile,
|
|
||||||
"--hash", "0x" + h.StringLE(),
|
|
||||||
}))
|
|
||||||
|
|
||||||
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.
|
|
||||||
package myspacecontract
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash contains contract hash.
|
|
||||||
var Hash = util.Uint160{0x4, 0x8, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x0, 0x1, 0xca, 0xfe, 0xba, 0xbe, 0xde, 0xad, 0xbe, 0xef, 0x3, 0x4}
|
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
|
||||||
type Invoker interface {
|
|
||||||
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker) *ContractReader {
|
|
||||||
var hash = Hash
|
|
||||||
return &ContractReader{invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get invokes `+"`get`"+` method of contract.
|
|
||||||
func (c *ContractReader) Get() (*big.Int, error) {
|
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "get"))
|
|
||||||
}
|
|
||||||
`, string(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// rewriteExpectedOutputs denotes whether expected output files should be rewritten
|
|
||||||
// for TestGenerateRPCBindings and TestAssistedRPCBindings.
|
|
||||||
const rewriteExpectedOutputs = false
|
|
||||||
|
|
||||||
func TestGenerateRPCBindings(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
|
|
||||||
|
|
||||||
var checkBinding = func(manifest string, hash string, good string) {
|
|
||||||
t.Run(manifest, func(t *testing.T) {
|
|
||||||
outFile := filepath.Join(tmpDir, "out.go")
|
|
||||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
|
||||||
"--manifest", manifest,
|
|
||||||
"--out", outFile,
|
|
||||||
"--hash", hash,
|
|
||||||
}))
|
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
|
||||||
require.NoError(t, err)
|
|
||||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
|
||||||
if rewriteExpectedOutputs {
|
|
||||||
require.NoError(t, os.WriteFile(good, data, os.ModePerm))
|
|
||||||
} else {
|
|
||||||
expected, err := os.ReadFile(good)
|
|
||||||
require.NoError(t, err)
|
|
||||||
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
|
|
||||||
require.Equal(t, string(expected), string(data))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
checkBinding(filepath.Join("testdata", "nex", "nex.manifest.json"),
|
|
||||||
"0xa2a67f09e8cf22c6bfd5cea24adc0f4bf0a11aa8",
|
|
||||||
filepath.Join("testdata", "nex", "nex.go"))
|
|
||||||
checkBinding(filepath.Join("testdata", "nameservice", "nns.manifest.json"),
|
|
||||||
"0x50ac1c37690cc2cfc594472833cf57505d5f46de",
|
|
||||||
filepath.Join("testdata", "nameservice", "nns.go"))
|
|
||||||
checkBinding(filepath.Join("testdata", "gas", "gas.manifest.json"),
|
|
||||||
"0xd2a4cff31913016155e38e474a2c06d08be276cf",
|
|
||||||
filepath.Join("testdata", "gas", "gas.go"))
|
|
||||||
checkBinding(filepath.Join("testdata", "verifyrpc", "verify.manifest.json"),
|
|
||||||
"0x00112233445566778899aabbccddeeff00112233",
|
|
||||||
filepath.Join("testdata", "verifyrpc", "verify.go"))
|
|
||||||
checkBinding(filepath.Join("testdata", "nonepiter", "iter.manifest.json"),
|
|
||||||
"0x00112233445566778899aabbccddeeff00112233",
|
|
||||||
filepath.Join("testdata", "nonepiter", "iter.go"))
|
|
||||||
|
|
||||||
require.False(t, rewriteExpectedOutputs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAssistedRPCBindings(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Commands = NewCommands()
|
|
||||||
|
|
||||||
var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) {
|
|
||||||
testName := source
|
|
||||||
if len(suffix) != 0 {
|
|
||||||
testName += suffix[0]
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
configFile = filepath.Join(source, "config"+suffix[0]+".yml")
|
|
||||||
expectedFile = filepath.Join(source, "rpcbindings"+suffix[0]+".out")
|
|
||||||
} else if !hasDefinedHash {
|
|
||||||
expectedFile = filepath.Join(source, "rpcbindings_dynamic_hash.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 guessEventTypes {
|
|
||||||
cmd = append(cmd, "--guess-eventtypes")
|
|
||||||
}
|
|
||||||
require.NoError(t, app.Run(cmd))
|
|
||||||
|
|
||||||
cmds := []string{"", "contract", "generate-rpcwrapper",
|
|
||||||
"--config", bindingF,
|
|
||||||
"--manifest", manifestF,
|
|
||||||
"--out", outFile,
|
|
||||||
}
|
|
||||||
if hasDefinedHash {
|
|
||||||
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
|
|
||||||
}
|
|
||||||
require.NoError(t, app.Run(cmds))
|
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
|
||||||
require.NoError(t, err)
|
|
||||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
|
||||||
if rewriteExpectedOutputs {
|
|
||||||
require.NoError(t, os.WriteFile(expectedFile, data, os.ModePerm))
|
|
||||||
} else {
|
|
||||||
expected, err := os.ReadFile(expectedFile)
|
|
||||||
require.NoError(t, err)
|
|
||||||
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
|
|
||||||
require.Equal(t, string(expected), string(data))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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", "rpcbindings", "notifications"), true, false)
|
|
||||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false, "_extended")
|
|
||||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, true, "_guessed")
|
|
||||||
|
|
||||||
require.False(t, rewriteExpectedOutputs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerate_Errors(t *testing.T) {
|
func TestGenerate_Errors(t *testing.T) {
|
||||||
|
@ -558,18 +277,18 @@ func TestGenerate_Errors(t *testing.T) {
|
||||||
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
|
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
|
||||||
}
|
}
|
||||||
t.Run("invalid hash", func(t *testing.T) {
|
t.Run("invalid hash", func(t *testing.T) {
|
||||||
checkError(t, "invalid contract hash", "--hash", "xxx", "--manifest", "yyy", "--out", "zzz")
|
checkError(t, "invalid contract hash", "--hash", "xxx")
|
||||||
})
|
})
|
||||||
t.Run("missing manifest argument", func(t *testing.T) {
|
t.Run("missing manifest argument", func(t *testing.T) {
|
||||||
checkError(t, "Required flag \"manifest\" not set", "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
checkError(t, errNoManifestFile.Error(), "--hash", util.Uint160{}.StringLE())
|
||||||
})
|
})
|
||||||
t.Run("missing manifest file", func(t *testing.T) {
|
t.Run("missing manifest file", func(t *testing.T) {
|
||||||
checkError(t, "can't read contract manifest", "--manifest", "notexists", "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
checkError(t, "can't read contract manifest", "--manifest", "notexists", "--hash", util.Uint160{}.StringLE())
|
||||||
})
|
})
|
||||||
t.Run("empty manifest", func(t *testing.T) {
|
t.Run("empty manifest", func(t *testing.T) {
|
||||||
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
||||||
require.NoError(t, os.WriteFile(manifestFile, []byte("[]"), os.ModePerm))
|
require.NoError(t, os.WriteFile(manifestFile, []byte("[]"), os.ModePerm))
|
||||||
checkError(t, "json: cannot unmarshal array into Go value of type manifest.Manifest", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
checkError(t, "json: cannot unmarshal array into Go value of type manifest.Manifest", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE())
|
||||||
})
|
})
|
||||||
t.Run("invalid manifest", func(t *testing.T) {
|
t.Run("invalid manifest", func(t *testing.T) {
|
||||||
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
||||||
|
@ -577,7 +296,7 @@ func TestGenerate_Errors(t *testing.T) {
|
||||||
rawManifest, err := json.Marshal(m)
|
rawManifest, err := json.Marshal(m)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
|
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
|
||||||
checkError(t, "ABI: no methods", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
checkError(t, "ABI: no methods", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE())
|
||||||
})
|
})
|
||||||
|
|
||||||
manifestFile := filepath.Join(t.TempDir(), "manifest.json")
|
manifestFile := filepath.Join(t.TempDir(), "manifest.json")
|
||||||
|
@ -595,7 +314,7 @@ func TestGenerate_Errors(t *testing.T) {
|
||||||
t.Run("missing config", func(t *testing.T) {
|
t.Run("missing config", func(t *testing.T) {
|
||||||
checkError(t, "can't read config file",
|
checkError(t, "can't read config file",
|
||||||
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
||||||
"--config", filepath.Join(t.TempDir(), "not.exists.yml"), "--out", "zzz")
|
"--config", filepath.Join(t.TempDir(), "not.exists.yml"))
|
||||||
})
|
})
|
||||||
t.Run("invalid config", func(t *testing.T) {
|
t.Run("invalid config", func(t *testing.T) {
|
||||||
rawCfg := `package: wrapper
|
rawCfg := `package: wrapper
|
||||||
|
@ -607,106 +326,6 @@ callflags:
|
||||||
|
|
||||||
checkError(t, "can't parse config file",
|
checkError(t, "can't parse config file",
|
||||||
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
||||||
"--config", cfgPath, "--out", "zzz")
|
"--config", cfgPath)
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCompile_GuessEventTypes(t *testing.T) {
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Commands = NewCommands()
|
|
||||||
app.ExitErrHandler = func(*cli.Context, error) {}
|
|
||||||
|
|
||||||
checkError := func(t *testing.T, msg string, args ...string) {
|
|
||||||
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
|
|
||||||
err := app.Run(args)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
|
|
||||||
}
|
|
||||||
check := func(t *testing.T, source string, expectedErrText string) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
configFile := filepath.Join(source, "invalid.yml")
|
|
||||||
manifestF := filepath.Join(tmpDir, "invalid.manifest.json")
|
|
||||||
bindingF := filepath.Join(tmpDir, "invalid.binding.yml")
|
|
||||||
nefF := filepath.Join(tmpDir, "invalid.out.nef")
|
|
||||||
cmd := []string{"", "contract", "compile",
|
|
||||||
"--in", source,
|
|
||||||
"--config", configFile,
|
|
||||||
"--manifest", manifestF,
|
|
||||||
"--bindings", bindingF,
|
|
||||||
"--out", nefF,
|
|
||||||
"--guess-eventtypes",
|
|
||||||
}
|
|
||||||
checkError(t, expectedErrText, cmd...)
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
})
|
|
||||||
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")
|
|
||||||
})
|
|
||||||
/*
|
|
||||||
// TODO: this on is a controversial one. If event information is provided in the config file, then conversion code
|
|
||||||
// will be emitted by the compiler according to the parameter type provided via config. Thus, we can be sure that
|
|
||||||
// either event parameter has the type specified in the config file or the execution of the contract will fail.
|
|
||||||
// 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")
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
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")
|
|
||||||
})
|
|
||||||
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`")
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"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/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"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/nef"
|
||||||
|
@ -38,16 +37,15 @@ func manifestAddGroup(ctx *cli.Context) error {
|
||||||
|
|
||||||
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
||||||
|
|
||||||
gAcc, w, err := options.GetAccFromContext(ctx)
|
gAcc, _, err := getAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
||||||
}
|
}
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
|
|
||||||
sig := gAcc.PrivateKey().Sign(h.BytesBE())
|
sig := gAcc.PrivateKey().Sign(h.BytesBE())
|
||||||
pub := gAcc.PublicKey()
|
pub := gAcc.PrivateKey().PublicKey()
|
||||||
for i := range m.Groups {
|
for i := range m.Groups {
|
||||||
if m.Groups[i].PublicKey.Equal(pub) {
|
if m.Groups[i].PublicKey.Equal(pub) {
|
||||||
m.Groups[i].Signature = sig
|
m.Groups[i].Signature = sig
|
||||||
|
@ -110,7 +108,7 @@ func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byt
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
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 nil, nil, fmt.Errorf("manifest is invalid: %w", err)
|
||||||
}
|
}
|
||||||
return m, manifestBytes, nil
|
return m, manifestBytes, nil
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package smartcontract
|
package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ const (
|
||||||
permMethodKey = "methods"
|
permMethodKey = "methods"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p permission) MarshalYAML() (any, error) {
|
func (p permission) MarshalYAML() (interface{}, error) {
|
||||||
m := yaml.Node{Kind: yaml.MappingNode}
|
m := yaml.Node{Kind: yaml.MappingNode}
|
||||||
switch p.Contract.Type {
|
switch p.Contract.Type {
|
||||||
case manifest.PermissionWildcard:
|
case manifest.PermissionWildcard:
|
||||||
|
@ -27,14 +28,15 @@ func (p permission) MarshalYAML() (any, error) {
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
|
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
|
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
|
||||||
case manifest.PermissionGroup:
|
case manifest.PermissionGroup:
|
||||||
|
bs := p.Contract.Value.(*keys.PublicKey).Bytes()
|
||||||
m.Content = append(m.Content,
|
m.Content = append(m.Content,
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
|
&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:
|
default:
|
||||||
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
|
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
var val any = "*"
|
var val interface{} = "*"
|
||||||
if !p.Methods.IsWildcard() {
|
if !p.Methods.IsWildcard() {
|
||||||
val = p.Methods.Value
|
val = p.Methods.Value
|
||||||
}
|
}
|
||||||
|
@ -51,8 +53,8 @@ func (p permission) MarshalYAML() (any, error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *permission) UnmarshalYAML(unmarshal func(any) error) error {
|
func (p *permission) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
var m map[string]any
|
var m map[string]interface{}
|
||||||
if err := unmarshal(&m); err != nil {
|
if err := unmarshal(&m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -64,7 +66,7 @@ func (p *permission) UnmarshalYAML(unmarshal func(any) error) error {
|
||||||
return p.fillMethods(m)
|
return p.fillMethods(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *permission) fillType(m map[string]any) error {
|
func (p *permission) fillType(m map[string]interface{}) error {
|
||||||
vh, ok1 := m[permHashKey]
|
vh, ok1 := m[permHashKey]
|
||||||
vg, ok2 := m[permGroupKey]
|
vg, ok2 := m[permGroupKey]
|
||||||
switch {
|
switch {
|
||||||
|
@ -102,7 +104,7 @@ func (p *permission) fillType(m map[string]any) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *permission) fillMethods(m map[string]any) error {
|
func (p *permission) fillMethods(m map[string]interface{}) error {
|
||||||
methods, ok := m[permMethodKey]
|
methods, ok := m[permMethodKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("'methods' field is missing from permission")
|
return errors.New("'methods' field is missing from permission")
|
||||||
|
@ -114,7 +116,7 @@ func (p *permission) fillMethods(m map[string]any) error {
|
||||||
p.Methods.Value = nil
|
p.Methods.Value = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case []any:
|
case []interface{}:
|
||||||
ms := make([]string, len(mt))
|
ms := make([]string, len(mt))
|
||||||
for i := range mt {
|
for i := range mt {
|
||||||
ms[i], ok = mt[i].(string)
|
ms[i], ok = mt[i].(string)
|
||||||
|
|
|
@ -8,20 +8,23 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"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/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
|
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"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/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"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/encoding/fixedn"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"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/actor"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"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/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -36,17 +39,44 @@ import (
|
||||||
const addressFlagName = "address, a"
|
const addressFlagName = "address, a"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
|
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")
|
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")
|
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")
|
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")
|
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")
|
||||||
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
||||||
errFileExist = errors.New("A file with given smart-contract name already exists")
|
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
||||||
addressFlag = flags.AddressFlag{
|
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,
|
Name: addressFlagName,
|
||||||
Usage: "address to use as transaction signee (and gas source)",
|
Usage: "address to use as transaction signee (and gas source)",
|
||||||
}
|
}
|
||||||
|
gasFlag = flags.Fixed8Flag{
|
||||||
|
Name: "gas, g",
|
||||||
|
Usage: "network fee to add to the transaction (prioritizing it)",
|
||||||
|
}
|
||||||
|
sysGasFlag = flags.Fixed8Flag{
|
||||||
|
Name: "sysgas, e",
|
||||||
|
Usage: "system fee to add to transaction (compensating for execution)",
|
||||||
|
}
|
||||||
|
outFlag = cli.StringFlag{
|
||||||
|
Name: "out",
|
||||||
|
Usage: "file to put JSON transaction to",
|
||||||
|
}
|
||||||
|
forceFlag = cli.BoolFlag{
|
||||||
|
Name: "force",
|
||||||
|
Usage: "force-push the transaction in case of bad VM state after test script invocation",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// ModVersion contains `pkg/interop` module version
|
// ModVersion contains `pkg/interop` module version
|
||||||
|
@ -68,7 +98,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuntimeNotify sends runtime notification with "Hello world!" name
|
// RuntimeNotify sends runtime notification with "Hello world!" name
|
||||||
func RuntimeNotify(args []any) {
|
func RuntimeNotify(args []interface{}) {
|
||||||
runtime.Notify(notificationName, args)
|
runtime.Notify(notificationName, args)
|
||||||
}`
|
}`
|
||||||
)
|
)
|
||||||
|
@ -80,20 +110,17 @@ func NewCommands() []cli.Command {
|
||||||
Name: "in, i",
|
Name: "in, i",
|
||||||
Usage: "Input location of the .nef file that needs to be invoked",
|
Usage: "Input location of the .nef file that needs to be invoked",
|
||||||
},
|
},
|
||||||
options.Historic,
|
|
||||||
}
|
}
|
||||||
testInvokeScriptFlags = append(testInvokeScriptFlags, options.RPC...)
|
testInvokeScriptFlags = append(testInvokeScriptFlags, options.RPC...)
|
||||||
testInvokeFunctionFlags := []cli.Flag{options.Historic}
|
|
||||||
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
|
|
||||||
invokeFunctionFlags := []cli.Flag{
|
invokeFunctionFlags := []cli.Flag{
|
||||||
|
walletFlag,
|
||||||
|
walletConfigFlag,
|
||||||
addressFlag,
|
addressFlag,
|
||||||
txctx.GasFlag,
|
gasFlag,
|
||||||
txctx.SysGasFlag,
|
sysGasFlag,
|
||||||
txctx.OutFlag,
|
outFlag,
|
||||||
txctx.ForceFlag,
|
forceFlag,
|
||||||
txctx.AwaitFlag,
|
|
||||||
}
|
}
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
|
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
||||||
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
@ -105,24 +132,6 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "Manifest input file (*.manifest.json)",
|
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{{
|
return []cli.Command{{
|
||||||
Name: "contract",
|
Name: "contract",
|
||||||
Usage: "compile - debug - deploy smart contracts",
|
Usage: "compile - debug - deploy smart contracts",
|
||||||
|
@ -130,20 +139,12 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "compile",
|
Name: "compile",
|
||||||
Usage: "compile a smart contract to a .nef file",
|
Usage: "compile a smart contract to a .nef file",
|
||||||
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions] [--guess-eventtypes]",
|
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions]",
|
||||||
Description: `Compiles given smart contract to a .nef file and emits other associated
|
Action: contractCompile,
|
||||||
information (manifest, bindings configuration, debug information files) if
|
|
||||||
asked to. If none of --out, --manifest, --config, --bindings flags are specified,
|
|
||||||
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.
|
|
||||||
`,
|
|
||||||
Action: contractCompile,
|
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in, i",
|
||||||
Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
|
Usage: "Input file for the smart contract to be compiled",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "out, o",
|
Name: "out, o",
|
||||||
|
@ -177,10 +178,6 @@ func NewCommands() []cli.Command {
|
||||||
Name: "no-permissions",
|
Name: "no-permissions",
|
||||||
Usage: "do not check if invoked contracts are allowed in manifest",
|
Usage: "do not check if invoked contracts are allowed in manifest",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "guess-eventtypes",
|
|
||||||
Usage: "guess event types for smart-contract bindings configuration from the code usages",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "bindings",
|
Name: "bindings",
|
||||||
Usage: "output file for smart-contract bindings configuration",
|
Usage: "output file for smart-contract bindings configuration",
|
||||||
|
@ -190,29 +187,25 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "deploy",
|
Name: "deploy",
|
||||||
Usage: "deploy a smart contract (.nef with description)",
|
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
|
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
|
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
|
parameter is an optional parameter to be passed to '_deploy' method.
|
||||||
--await flag is specified, it waits for the transaction to be included
|
|
||||||
in a block.
|
|
||||||
`,
|
`,
|
||||||
Action: contractDeploy,
|
Action: contractDeploy,
|
||||||
Flags: deployFlags,
|
Flags: deployFlags,
|
||||||
},
|
},
|
||||||
generateWrapperCmd,
|
generateWrapperCmd,
|
||||||
generateRPCWrapperCmd,
|
|
||||||
{
|
{
|
||||||
Name: "invokefunction",
|
Name: "invokefunction",
|
||||||
Usage: "invoke deployed contract on the blockchain",
|
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,
|
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
|
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,
|
with None witness scope. If you'd like to change default sender's scope,
|
||||||
specify it via signers parameter. See testinvokefunction documentation for
|
specify it via signers parameter. See testinvokefunction documentation for
|
||||||
the details about parameters. It differs from testinvokefunction in that this
|
the details about parameters. It differs from testinvokefunction in that this
|
||||||
command sends an invocation transaction to the network. When --await flag is
|
command sends an invocation transaction to the network.
|
||||||
specified, it waits for the transaction to be included in a block.
|
|
||||||
`,
|
`,
|
||||||
Action: invokeFunction,
|
Action: invokeFunction,
|
||||||
Flags: invokeFunctionFlags,
|
Flags: invokeFunctionFlags,
|
||||||
|
@ -220,7 +213,7 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "testinvokefunction",
|
Name: "testinvokefunction",
|
||||||
Usage: "invoke deployed contract on the blockchain (test mode)",
|
Usage: "invoke deployed contract on the blockchain (test mode)",
|
||||||
UsageText: "neo-go contract testinvokefunction -r endpoint [--historic index/hash] scripthash [method] [arguments...] [--] [signers...]",
|
UsageText: "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [signers...]",
|
||||||
Description: `Executes given (as a script hash) deployed script with the given method,
|
Description: `Executes given (as a script hash) deployed script with the given method,
|
||||||
arguments and signers (sender is not included by default). If no method is given
|
arguments and signers (sender is not included by default). If no method is given
|
||||||
"" is passed to the script, if no arguments are given, an empty array is
|
"" is passed to the script, if no arguments are given, an empty array is
|
||||||
|
@ -230,17 +223,117 @@ func NewCommands() []cli.Command {
|
||||||
follow the regular convention of smart contract arguments (method string and
|
follow the regular convention of smart contract arguments (method string and
|
||||||
an array of other arguments).
|
an array of other arguments).
|
||||||
|
|
||||||
` + cmdargs.ParamsParsingDoc + `
|
Arguments always do have regular Neo smart contract parameter types, either
|
||||||
|
specified explicitly or being inferred from the value. To specify the type
|
||||||
|
manually use "type:value" syntax where the type is one of the following:
|
||||||
|
'signature', 'bool', 'int', 'hash160', 'hash256', 'bytes', 'key' or 'string'.
|
||||||
|
Array types are also supported: use special space-separated '[' and ']'
|
||||||
|
symbols around array values to denote array bounds. Nested arrays are also
|
||||||
|
supported.
|
||||||
|
|
||||||
` + cmdargs.SignersParsingDoc + `
|
There is ability to provide an argument of 'bytearray' type via file. Use a
|
||||||
|
special 'filebytes' argument type for this with a filepath specified after
|
||||||
|
the colon, e.g. 'filebytes:my_file.txt'.
|
||||||
|
|
||||||
|
Given values are type-checked against given types with the following
|
||||||
|
restrictions applied:
|
||||||
|
* 'signature' type values should be hex-encoded and have a (decoded)
|
||||||
|
length of 64 bytes.
|
||||||
|
* 'bool' type values are 'true' and 'false'.
|
||||||
|
* 'int' values are decimal integers that can be successfully converted
|
||||||
|
from the string.
|
||||||
|
* 'hash160' values are Neo addresses and hex-encoded 20-bytes long (after
|
||||||
|
decoding) strings.
|
||||||
|
* 'hash256' type values should be hex-encoded and have a (decoded)
|
||||||
|
length of 32 bytes.
|
||||||
|
* 'bytes' type values are any hex-encoded things.
|
||||||
|
* 'filebytes' type values are filenames with the argument value inside.
|
||||||
|
* 'key' type values are hex-encoded marshalled public keys.
|
||||||
|
* 'string' type values are any valid UTF-8 strings. In the value's part of
|
||||||
|
the string the colon looses it's special meaning as a separator between
|
||||||
|
type and value and is taken literally.
|
||||||
|
|
||||||
|
If no type is explicitly specified, it is inferred from the value using the
|
||||||
|
following logic:
|
||||||
|
- anything that can be interpreted as a decimal integer gets
|
||||||
|
an 'int' type
|
||||||
|
- 'true' and 'false' strings get 'bool' type
|
||||||
|
- valid Neo addresses and 20 bytes long hex-encoded strings get 'hash160'
|
||||||
|
type
|
||||||
|
- valid hex-encoded public keys get 'key' type
|
||||||
|
- 32 bytes long hex-encoded values get 'hash256' type
|
||||||
|
- 64 bytes long hex-encoded values get 'signature' type
|
||||||
|
- any other valid hex-encoded values get 'bytes' type
|
||||||
|
- anything else is a 'string'
|
||||||
|
|
||||||
|
Backslash character is used as an escape character and allows to use colon in
|
||||||
|
an implicitly typed string. For any other characters it has no special
|
||||||
|
meaning, to get a literal backslash in the string use the '\\' sequence.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
* 'int:42' is an integer with a value of 42
|
||||||
|
* '42' is an integer with a value of 42
|
||||||
|
* 'bad' is a string with a value of 'bad'
|
||||||
|
* 'dead' is a byte array with a value of 'dead'
|
||||||
|
* 'string:dead' is a string with a value of 'dead'
|
||||||
|
* 'filebytes:my_data.txt' is bytes decoded from a content of my_data.txt
|
||||||
|
* 'AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y' is a hash160 with a value
|
||||||
|
of '23ba2703c53263e8d6e522dc32203339dcd8eee9'
|
||||||
|
* '\4\2' is an integer with a value of 42
|
||||||
|
* '\\4\2' is a string with a value of '\42'
|
||||||
|
* 'string:string' is a string with a value of 'string'
|
||||||
|
* 'string\:string' is a string with a value of 'string:string'
|
||||||
|
* '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c' is a
|
||||||
|
key with a value of '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c'
|
||||||
|
* '[ a b c ]' is an array with strings values 'a', 'b' and 'c'
|
||||||
|
* '[ a b [ c d ] e ]' is an array with 4 values: string 'a', string 'b',
|
||||||
|
array of two strings 'c' and 'd', string 'e'
|
||||||
|
* '[ ]' is an empty array
|
||||||
|
|
||||||
|
Signers represent a set of Uint160 hashes with witness scopes and are used
|
||||||
|
to verify hashes in System.Runtime.CheckWitness syscall. First signer is treated
|
||||||
|
as a sender. To specify signers use signer[:scope] syntax where
|
||||||
|
* 'signer' is a signer's address (as Neo address or hex-encoded 160 bit (20 byte)
|
||||||
|
LE value with or without '0x' prefix).
|
||||||
|
* 'scope' is a comma-separated set of cosigner's scopes, which could be:
|
||||||
|
- 'None' - default witness scope which may be used for the sender
|
||||||
|
to only pay fee for the transaction.
|
||||||
|
- 'Global' - allows this witness in all contexts. This cannot be combined
|
||||||
|
with other flags.
|
||||||
|
- 'CalledByEntry' - means that this condition must hold: EntryScriptHash
|
||||||
|
== CallingScriptHash. The witness/permission/signature
|
||||||
|
given on first invocation will automatically expire if
|
||||||
|
entering deeper internal invokes. This can be default
|
||||||
|
safe choice for native NEO/GAS.
|
||||||
|
- 'CustomContracts' - define valid custom contract hashes for witness check.
|
||||||
|
Hashes are be provided as hex-encoded LE value string.
|
||||||
|
At lest one hash must be provided. Multiple hashes
|
||||||
|
are separated by ':'.
|
||||||
|
- 'CustomGroups' - define custom public keys for group members. Public keys are
|
||||||
|
provided as short-form (1-byte prefix + 32 bytes) hex-encoded
|
||||||
|
values. At least one key must be provided. Multiple keys
|
||||||
|
are separated by ':'.
|
||||||
|
|
||||||
|
If no scopes were specified, 'CalledByEntry' used as default. If no signers were
|
||||||
|
specified, no array is passed. Note that scopes are properly handled by
|
||||||
|
neo-go RPC server only. C# implementation does not support scopes capability.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
* 'NNQk4QXsxvsrr3GSozoWBUxEmfag7B6hz5'
|
||||||
|
* 'NVquyZHoPirw6zAEPvY1ZezxM493zMWQqs:Global'
|
||||||
|
* '0x0000000009070e030d0f0e020d0c06050e030c02'
|
||||||
|
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
||||||
|
`CustomGroups:0206d7495ceb34c197093b5fc1cccf1996ada05e69ef67e765462a7f5d88ee14d0'
|
||||||
|
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
||||||
|
`CustomContracts:1011120009070e030d0f0e020d0c06050e030c02:0x1211100009070e030d0f0e020d0c06050e030c02'
|
||||||
`,
|
`,
|
||||||
Action: testInvokeFunction,
|
Action: testInvokeFunction,
|
||||||
Flags: testInvokeFunctionFlags,
|
Flags: options.RPC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "testinvokescript",
|
Name: "testinvokescript",
|
||||||
Usage: "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)",
|
Usage: "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)",
|
||||||
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [--historic index/hash] [signers...]",
|
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [signers...]",
|
||||||
Description: `Executes given compiled AVM instructions in NEF format with the given set of
|
Description: `Executes given compiled AVM instructions in NEF format with the given set of
|
||||||
signers not included sender by default. See testinvokefunction documentation
|
signers not included sender by default. See testinvokefunction documentation
|
||||||
for the details about parameters.
|
for the details about parameters.
|
||||||
|
@ -309,7 +402,26 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "adds group to the manifest",
|
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",
|
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
||||||
Action: manifestAddGroup,
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -346,15 +458,13 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
SourceURL: "http://example.com/",
|
SourceURL: "http://example.com/",
|
||||||
SupportedStandards: []string{},
|
SupportedStandards: []string{},
|
||||||
SafeMethods: []string{},
|
SafeMethods: []string{},
|
||||||
Events: []compiler.HybridEvent{
|
Events: []manifest.Event{
|
||||||
{
|
{
|
||||||
Name: "Hello world!",
|
Name: "Hello world!",
|
||||||
Parameters: []compiler.HybridParameter{
|
Parameters: []manifest.Parameter{
|
||||||
{
|
{
|
||||||
Parameter: manifest.Parameter{
|
Name: "args",
|
||||||
Name: "args",
|
Type: smartcontract.ArrayType,
|
||||||
Type: smartcontract.ArrayType,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -375,9 +485,6 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
gm := []byte("module " + contractName + `
|
gm := []byte("module " + contractName + `
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
|
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
|
||||||
)`)
|
)`)
|
||||||
|
@ -406,48 +513,20 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
manifestFile := ctx.String("manifest")
|
manifestFile := ctx.String("manifest")
|
||||||
confFile := ctx.String("config")
|
confFile := ctx.String("config")
|
||||||
debugFile := ctx.String("debug")
|
debugFile := ctx.String("debug")
|
||||||
out := ctx.String("out")
|
if len(confFile) == 0 && (len(manifestFile) != 0 || len(debugFile) != 0) {
|
||||||
bindings := ctx.String("bindings")
|
|
||||||
if len(confFile) == 0 && (len(manifestFile) != 0 || len(debugFile) != 0 || len(bindings) != 0) {
|
|
||||||
return cli.NewExitError(errNoConfFile, 1)
|
return cli.NewExitError(errNoConfFile, 1)
|
||||||
}
|
}
|
||||||
autocomplete := len(manifestFile) == 0 &&
|
|
||||||
len(confFile) == 0 &&
|
|
||||||
len(out) == 0 &&
|
|
||||||
len(bindings) == 0
|
|
||||||
if autocomplete {
|
|
||||||
var root string
|
|
||||||
fileInfo, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to stat source file or directory: %w", err), 1)
|
|
||||||
}
|
|
||||||
if fileInfo.IsDir() {
|
|
||||||
base := filepath.Base(fileInfo.Name())
|
|
||||||
if base == string(filepath.Separator) {
|
|
||||||
base = "contract"
|
|
||||||
}
|
|
||||||
root = filepath.Join(src, base)
|
|
||||||
} else {
|
|
||||||
root = strings.TrimSuffix(src, ".go")
|
|
||||||
}
|
|
||||||
manifestFile = root + ".manifest.json"
|
|
||||||
confFile = root + ".yml"
|
|
||||||
out = root + ".nef"
|
|
||||||
bindings = root + ".bindings.yml"
|
|
||||||
}
|
|
||||||
|
|
||||||
o := &compiler.Options{
|
o := &compiler.Options{
|
||||||
Outfile: out,
|
Outfile: ctx.String("out"),
|
||||||
|
|
||||||
DebugInfo: debugFile,
|
DebugInfo: debugFile,
|
||||||
ManifestFile: manifestFile,
|
ManifestFile: manifestFile,
|
||||||
BindingsFile: bindings,
|
BindingsFile: ctx.String("bindings"),
|
||||||
|
|
||||||
NoStandardCheck: ctx.Bool("no-standards"),
|
NoStandardCheck: ctx.Bool("no-standards"),
|
||||||
NoEventsCheck: ctx.Bool("no-events"),
|
NoEventsCheck: ctx.Bool("no-events"),
|
||||||
NoPermissionsCheck: ctx.Bool("no-permissions"),
|
NoPermissionsCheck: ctx.Bool("no-permissions"),
|
||||||
|
|
||||||
GuessEventTypes: ctx.Bool("guess-eventtypes"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(confFile) != 0 {
|
if len(confFile) != 0 {
|
||||||
|
@ -458,7 +537,6 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
o.Name = conf.Name
|
o.Name = conf.Name
|
||||||
o.SourceURL = conf.SourceURL
|
o.SourceURL = conf.SourceURL
|
||||||
o.ContractEvents = conf.Events
|
o.ContractEvents = conf.Events
|
||||||
o.DeclaredNamedTypes = conf.NamedTypes
|
|
||||||
o.ContractSupportedStandards = conf.SupportedStandards
|
o.ContractSupportedStandards = conf.SupportedStandards
|
||||||
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
|
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
|
||||||
for i := range conf.Permissions {
|
for i := range conf.Permissions {
|
||||||
|
@ -530,9 +608,8 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
err error
|
err error
|
||||||
exitErr *cli.ExitError
|
exitErr *cli.ExitError
|
||||||
operation string
|
operation string
|
||||||
params []any
|
params = make([]smartcontract.Parameter, 0)
|
||||||
paramsStart = 1
|
paramsStart = 1
|
||||||
scParams []smartcontract.Parameter
|
|
||||||
cosigners []transaction.Signer
|
cosigners []transaction.Signer
|
||||||
cosignersOffset = 0
|
cosignersOffset = 0
|
||||||
)
|
)
|
||||||
|
@ -552,14 +629,10 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
paramsStart++
|
paramsStart++
|
||||||
|
|
||||||
if len(args) > paramsStart {
|
if len(args) > paramsStart {
|
||||||
cosignersOffset, scParams, err = cmdargs.ParseParams(args[paramsStart:], true)
|
cosignersOffset, params, err = cmdargs.ParseParams(args[paramsStart:], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
params = make([]any, len(scParams))
|
|
||||||
for i := range scParams {
|
|
||||||
params[i] = scParams[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosignersStart := paramsStart + cosignersOffset
|
cosignersStart := paramsStart + cosignersOffset
|
||||||
|
@ -573,54 +646,60 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
w *wallet.Wallet
|
w *wallet.Wallet
|
||||||
)
|
)
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
acc, w, err = options.GetAccFromContext(ctx)
|
acc, w, err = getAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
defer w.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return invokeWithArgs(ctx, acc, w, script, operation, params, cosigners)
|
_, err = invokeWithArgs(ctx, acc, w, script, operation, params, cosigners)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []any, cosigners []transaction.Signer) error {
|
func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []smartcontract.Parameter, cosigners []transaction.Signer) (util.Uint160, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
gas, sysgas fixedn.Fixed8
|
||||||
signersAccounts []actor.SignerAccount
|
signersAccounts []actor.SignerAccount
|
||||||
resp *result.Invoke
|
resp *result.Invoke
|
||||||
|
sender util.Uint160
|
||||||
signAndPush = acc != nil
|
signAndPush = acc != nil
|
||||||
inv *invoker.Invoker
|
|
||||||
act *actor.Actor
|
act *actor.Actor
|
||||||
)
|
)
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
|
gas = flags.Fixed8FromContext(ctx, "gas")
|
||||||
|
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
||||||
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
return sender, cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
sender = signersAccounts[0].Signer.Account
|
||||||
}
|
}
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return sender, err
|
||||||
|
}
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
_, act, err = options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
act, err = actor.New(c, signersAccounts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return sender, cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
||||||
}
|
|
||||||
inv = &act.Invoker
|
|
||||||
} else {
|
|
||||||
_, inv, err = options.GetRPCWithInvoker(gctx, ctx, cosigners)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out := ctx.String("out")
|
out := ctx.String("out")
|
||||||
resp, err = inv.Call(script, operation, params...)
|
// It's a bit easier to keep this as is (not using invoker.Invoker)
|
||||||
|
// during transition period. Mostly because of the need to convert params
|
||||||
|
// to []interface{}.
|
||||||
|
resp, err = c.InvokeFunction(script, operation, params, cosigners)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return sender, cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
if resp.State != "HALT" {
|
if resp.State != "HALT" {
|
||||||
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s", resp.State, resp.FaultException)
|
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s", resp.State, resp.FaultException)
|
||||||
if !signAndPush {
|
if !signAndPush {
|
||||||
return cli.NewExitError(errText, 1)
|
return sender, cli.NewExitError(errText, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
action := "send"
|
action := "send"
|
||||||
|
@ -630,27 +709,55 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
process = "Saving"
|
process = "Saving"
|
||||||
}
|
}
|
||||||
if !ctx.Bool("force") {
|
if !ctx.Bool("force") {
|
||||||
return cli.NewExitError(errText+".\nUse --force flag to "+action+" the transaction anyway.", 1)
|
return sender, cli.NewExitError(errText+".\nUse --force flag to "+action+" the transaction anyway.", 1)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(ctx.App.Writer, errText+".\n"+process+" transaction...")
|
fmt.Fprintln(ctx.App.Writer, errText+".\n"+process+" transaction...")
|
||||||
}
|
}
|
||||||
if !signAndPush {
|
if !signAndPush {
|
||||||
b, err := json.MarshalIndent(resp, "", " ")
|
b, err := json.MarshalIndent(resp, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return sender, cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, string(b))
|
fmt.Fprintln(ctx.App.Writer, string(b))
|
||||||
return nil
|
} else {
|
||||||
|
if len(resp.Script) == 0 {
|
||||||
|
return sender, cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
||||||
|
}
|
||||||
|
ver := act.GetVersion()
|
||||||
|
tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed+int64(sysgas), nil)
|
||||||
|
if err != nil {
|
||||||
|
return sender, cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
||||||
|
}
|
||||||
|
tx.NetworkFee += int64(gas)
|
||||||
|
if out != "" {
|
||||||
|
// Make a long-lived transaction, it's to be signed manually.
|
||||||
|
tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2
|
||||||
|
m := act.GetNetwork()
|
||||||
|
if err := paramcontext.InitAndSave(m, tx, acc, out); err != nil {
|
||||||
|
return sender, cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
||||||
|
} else {
|
||||||
|
if !ctx.Bool("force") {
|
||||||
|
promptTime := time.Now()
|
||||||
|
err := input.ConfirmTx(ctx.App.Writer, tx)
|
||||||
|
if err != nil {
|
||||||
|
return sender, cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
waitTime := time.Since(promptTime)
|
||||||
|
// Compensate for confirmation waiting.
|
||||||
|
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
|
||||||
|
}
|
||||||
|
txHash, _, err := act.SignAndSend(tx)
|
||||||
|
if err != nil {
|
||||||
|
return sender, cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(ctx.App.Writer, "Sent invocation transaction %s\n", txHash.StringLE())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(resp.Script) == 0 {
|
|
||||||
return cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
return sender, nil
|
||||||
}
|
|
||||||
tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed, nil)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
|
||||||
}
|
|
||||||
return txctx.SignAndSend(ctx, act, acc, tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvokeScript(ctx *cli.Context) error {
|
func testInvokeScript(ctx *cli.Context) error {
|
||||||
|
@ -676,12 +783,12 @@ func testInvokeScript(ctx *cli.Context) error {
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
_, inv, err := options.GetRPCWithInvoker(gctx, ctx, signers)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := inv.Run(nefFile.Script)
|
resp, err := c.InvokeScript(nefFile.Script, signers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -702,10 +809,9 @@ type ProjectConfig struct {
|
||||||
SourceURL string
|
SourceURL string
|
||||||
SafeMethods []string
|
SafeMethods []string
|
||||||
SupportedStandards []string
|
SupportedStandards []string
|
||||||
Events []compiler.HybridEvent
|
Events []manifest.Event
|
||||||
Permissions []permission
|
Permissions []permission
|
||||||
Overloads map[string]string `yaml:"overloads,omitempty"`
|
Overloads map[string]string `yaml:"overloads,omitempty"`
|
||||||
NamedTypes map[string]binding.ExtendedType `yaml:"namedtypes,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspect(ctx *cli.Context) error {
|
func inspect(ctx *cli.Context) error {
|
||||||
|
@ -744,6 +850,68 @@ func inspect(ctx *cli.Context) error {
|
||||||
return nil
|
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.PrivateKey() != nil {
|
||||||
|
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.
|
// contractDeploy deploys contract.
|
||||||
func contractDeploy(ctx *cli.Context) error {
|
func contractDeploy(ctx *cli.Context) error {
|
||||||
nefFile, f, err := readNEFFile(ctx.String("in"))
|
nefFile, f, err := readNEFFile(ctx.String("in"))
|
||||||
|
@ -756,8 +924,16 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to read manifest file: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to read manifest file: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var appCallParams = []any{f, manifestBytes}
|
appCallParams := []smartcontract.Parameter{
|
||||||
|
{
|
||||||
|
Type: smartcontract.ByteArrayType,
|
||||||
|
Value: f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: smartcontract.ByteArrayType,
|
||||||
|
Value: manifestBytes,
|
||||||
|
},
|
||||||
|
}
|
||||||
signOffset, data, err := cmdargs.ParseParams(ctx.Args(), true)
|
signOffset, data, err := cmdargs.ParseParams(ctx.Args(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1)
|
||||||
|
@ -769,12 +945,10 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
appCallParams = append(appCallParams, data[0])
|
appCallParams = append(appCallParams, data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
acc, w, err := options.GetAccFromContext(ctx)
|
acc, w, err := getAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||||
}
|
}
|
||||||
defer w.Close()
|
|
||||||
sender := acc.ScriptHash()
|
|
||||||
|
|
||||||
cosigners, sgnErr := cmdargs.GetSignersFromContext(ctx, signOffset)
|
cosigners, sgnErr := cmdargs.GetSignersFromContext(ctx, signOffset)
|
||||||
if sgnErr != nil {
|
if sgnErr != nil {
|
||||||
|
@ -786,7 +960,7 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
extErr := invokeWithArgs(ctx, acc, w, management.Hash, "deploy", appCallParams, cosigners)
|
sender, extErr := invokeWithArgs(ctx, acc, w, management.Hash, "deploy", appCallParams, cosigners)
|
||||||
if extErr != nil {
|
if extErr != nil {
|
||||||
return extErr
|
return extErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package smartcontract
|
package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -50,7 +51,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuntimeNotify sends runtime notification with "Hello world!" name
|
// RuntimeNotify sends runtime notification with "Hello world!" name
|
||||||
func RuntimeNotify(args []any) {
|
func RuntimeNotify(args []interface{}) {
|
||||||
runtime.Notify(notificationName, args)
|
runtime.Notify(notificationName, args)
|
||||||
}`, string(main))
|
}`, string(main))
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ func TestPermissionMarshal(t *testing.T) {
|
||||||
p.Methods.Add("abc")
|
p.Methods.Add("abc")
|
||||||
p.Methods.Add("lamao")
|
p.Methods.Add("lamao")
|
||||||
testPermissionMarshal(t, p,
|
testPermissionMarshal(t, p,
|
||||||
"group: "+priv.PublicKey().StringCompressed()+"\n"+
|
"group: "+hex.EncodeToString(priv.PublicKey().Bytes())+"\n"+
|
||||||
"methods:\n - abc\n - lamao\n")
|
"methods:\n - abc\n - lamao\n")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -117,7 +118,7 @@ func TestPermissionUnmarshalInvalid(t *testing.T) {
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pub := priv.PublicKey().StringCompressed()
|
pub := hex.EncodeToString(priv.PublicKey().Bytes())
|
||||||
u160 := random.Uint160().StringLE()
|
u160 := random.Uint160().StringLE()
|
||||||
testCases := []string{
|
testCases := []string{
|
||||||
"hash: []\nmethods: '*'\n", // invalid hash type
|
"hash: []\nmethods: '*'\n", // invalid hash type
|
||||||
|
|
52
cli/smartcontract/testdata/gas/gas.go
vendored
52
cli/smartcontract/testdata/gas/gas.go
vendored
|
@ -1,52 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash contains contract hash.
|
|
||||||
var Hash = util.Uint160{0xcf, 0x76, 0xe2, 0x8b, 0xd0, 0x6, 0x2c, 0x4a, 0x47, 0x8e, 0xe3, 0x55, 0x61, 0x1, 0x13, 0x19, 0xf3, 0xcf, 0xa4, 0xd2}
|
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
|
||||||
type Invoker interface {
|
|
||||||
nep17.Invoker
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actor is used by Contract to call state-changing methods.
|
|
||||||
type Actor interface {
|
|
||||||
Invoker
|
|
||||||
|
|
||||||
nep17.Actor
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
nep17.TokenReader
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contract implements all contract methods.
|
|
||||||
type Contract struct {
|
|
||||||
ContractReader
|
|
||||||
nep17.TokenWriter
|
|
||||||
actor Actor
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker) *ContractReader {
|
|
||||||
var hash = Hash
|
|
||||||
return &ContractReader{*nep17.NewReader(invoker, hash), invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates an instance of Contract using Hash and the given Actor.
|
|
||||||
func New(actor Actor) *Contract {
|
|
||||||
var hash = Hash
|
|
||||||
var nep17t = nep17.New(actor, hash)
|
|
||||||
return &Contract{ContractReader{nep17t.TokenReader, actor, hash}, nep17t.TokenWriter, actor, hash}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}
|
|
511
cli/smartcontract/testdata/nameservice/nns.go
vendored
511
cli/smartcontract/testdata/nameservice/nns.go
vendored
|
@ -1,511 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"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/nep11"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
"math/big"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash contains contract hash.
|
|
||||||
var Hash = util.Uint160{0xde, 0x46, 0x5f, 0x5d, 0x50, 0x57, 0xcf, 0x33, 0x28, 0x47, 0x94, 0xc5, 0xcf, 0xc2, 0xc, 0x69, 0x37, 0x1c, 0xac, 0x50}
|
|
||||||
|
|
||||||
// SetAdminEvent represents "SetAdmin" event emitted by the contract.
|
|
||||||
type SetAdminEvent struct {
|
|
||||||
Name string
|
|
||||||
OldAdmin util.Uint160
|
|
||||||
NewAdmin util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewEvent represents "Renew" event emitted by the contract.
|
|
||||||
type RenewEvent struct {
|
|
||||||
Name string
|
|
||||||
OldExpiration *big.Int
|
|
||||||
NewExpiration *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
|
||||||
type Invoker interface {
|
|
||||||
nep11.Invoker
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actor is used by Contract to call state-changing methods.
|
|
||||||
type Actor interface {
|
|
||||||
Invoker
|
|
||||||
|
|
||||||
nep11.Actor
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
nep11.NonDivisibleReader
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contract implements all contract methods.
|
|
||||||
type Contract struct {
|
|
||||||
ContractReader
|
|
||||||
nep11.BaseWriter
|
|
||||||
actor Actor
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker) *ContractReader {
|
|
||||||
var hash = Hash
|
|
||||||
return &ContractReader{*nep11.NewNonDivisibleReader(invoker, hash), invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates an instance of Contract using Hash and the given Actor.
|
|
||||||
func New(actor Actor) *Contract {
|
|
||||||
var hash = Hash
|
|
||||||
var nep11ndt = nep11.NewNonDivisible(actor, hash)
|
|
||||||
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor, hash}, nep11ndt.BaseWriter, actor, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roots invokes `roots` method of contract.
|
|
||||||
func (c *ContractReader) Roots() (uuid.UUID, result.Iterator, error) {
|
|
||||||
return unwrap.SessionIterator(c.invoker.Call(c.hash, "roots"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RootsExpanded is similar to Roots (uses the same contract
|
|
||||||
// method), but can be useful if the server used doesn't support sessions and
|
|
||||||
// doesn't expand iterators. It creates a script that will get the specified
|
|
||||||
// number of result items from the iterator right in the VM and return them to
|
|
||||||
// you. It's only limited by VM stack and GAS available for RPC invocations.
|
|
||||||
func (c *ContractReader) RootsExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) {
|
|
||||||
return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "roots", _numOfIteratorItems))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPrice invokes `getPrice` method of contract.
|
|
||||||
func (c *ContractReader) GetPrice(length *big.Int) (*big.Int, error) {
|
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "getPrice", length))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAvailable invokes `isAvailable` method of contract.
|
|
||||||
func (c *ContractReader) IsAvailable(name string) (bool, error) {
|
|
||||||
return unwrap.Bool(c.invoker.Call(c.hash, "isAvailable", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRecord invokes `getRecord` method of contract.
|
|
||||||
func (c *ContractReader) GetRecord(name string, typev *big.Int) (string, error) {
|
|
||||||
return unwrap.UTF8String(c.invoker.Call(c.hash, "getRecord", name, typev))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllRecords invokes `getAllRecords` method of contract.
|
|
||||||
func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) {
|
|
||||||
return unwrap.SessionIterator(c.invoker.Call(c.hash, "getAllRecords", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract
|
|
||||||
// method), but can be useful if the server used doesn't support sessions and
|
|
||||||
// doesn't expand iterators. It creates a script that will get the specified
|
|
||||||
// number of result items from the iterator right in the VM and return them to
|
|
||||||
// you. It's only limited by VM stack and GAS available for RPC invocations.
|
|
||||||
func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) {
|
|
||||||
return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "getAllRecords", _numOfIteratorItems, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve invokes `resolve` method of contract.
|
|
||||||
func (c *ContractReader) Resolve(name string, typev *big.Int) (string, error) {
|
|
||||||
return unwrap.UTF8String(c.invoker.Call(c.hash, "resolve", name, typev))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update creates a transaction invoking `update` 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) Update(nef []byte, manifest string) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "update", nef, manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateTransaction creates a transaction invoking `update` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) UpdateTransaction(nef []byte, manifest string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "update", nef, manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateUnsigned creates a transaction invoking `update` 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) UpdateUnsigned(nef []byte, manifest string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "update", nil, nef, manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRoot creates a transaction invoking `addRoot` 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) AddRoot(root string) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "addRoot", root)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRootTransaction creates a transaction invoking `addRoot` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) AddRootTransaction(root string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "addRoot", root)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRootUnsigned creates a transaction invoking `addRoot` 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) AddRootUnsigned(root string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "addRoot", nil, root)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPrice creates a transaction invoking `setPrice` 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) SetPrice(priceList []any) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "setPrice", priceList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPriceTransaction creates a transaction invoking `setPrice` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) SetPriceTransaction(priceList []any) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "setPrice", priceList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPriceUnsigned creates a transaction invoking `setPrice` 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) SetPriceUnsigned(priceList []any) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "setPrice", nil, priceList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Contract) scriptForRegister(name string, owner util.Uint160) ([]byte, error) {
|
|
||||||
return smartcontract.CreateCallWithAssertScript(c.hash, "register", name, owner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register creates a transaction invoking `register` 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) Register(name string, owner util.Uint160) (util.Uint256, uint32, error) {
|
|
||||||
script, err := c.scriptForRegister(name, owner)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, 0, err
|
|
||||||
}
|
|
||||||
return c.actor.SendRun(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterTransaction creates a transaction invoking `register` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
script, err := c.scriptForRegister(name, owner)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.actor.MakeRun(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterUnsigned creates a transaction invoking `register` 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) RegisterUnsigned(name string, owner util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
script, err := c.scriptForRegister(name, owner)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.actor.MakeUnsignedRun(script, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew 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) Renew(name string) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "renew", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewTransaction 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) RenewTransaction(name string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "renew", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewUnsigned 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) 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.
|
|
||||||
// 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) {
|
|
||||||
return c.actor.SendCall(c.hash, "renew", name, years)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew2Transaction 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) {
|
|
||||||
return c.actor.MakeCall(c.hash, "renew", name, years)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew2Unsigned 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) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name, years)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAdmin creates a transaction invoking `setAdmin` 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) SetAdmin(name string, admin util.Uint160) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "setAdmin", name, admin)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAdminTransaction creates a transaction invoking `setAdmin` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) SetAdminTransaction(name string, admin util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "setAdmin", name, admin)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAdminUnsigned creates a transaction invoking `setAdmin` 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) SetAdminUnsigned(name string, admin util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "setAdmin", nil, name, admin)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRecord creates a transaction invoking `setRecord` 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) SetRecord(name string, typev *big.Int, data string) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "setRecord", name, typev, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRecordTransaction creates a transaction invoking `setRecord` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) SetRecordTransaction(name string, typev *big.Int, data string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "setRecord", name, typev, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRecordUnsigned creates a transaction invoking `setRecord` 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) SetRecordUnsigned(name string, typev *big.Int, data string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "setRecord", nil, name, typev, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecord creates a transaction invoking `deleteRecord` 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) DeleteRecord(name string, typev *big.Int) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "deleteRecord", name, typev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecordTransaction creates a transaction invoking `deleteRecord` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) DeleteRecordTransaction(name string, typev *big.Int) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "deleteRecord", name, typev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecordUnsigned creates a transaction invoking `deleteRecord` 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) DeleteRecordUnsigned(name string, typev *big.Int) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "deleteRecord", nil, name, typev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAdminEventsFromApplicationLog retrieves a set of all emitted events
|
|
||||||
// with "SetAdmin" name from the provided [result.ApplicationLog].
|
|
||||||
func SetAdminEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetAdminEvent, error) {
|
|
||||||
if log == nil {
|
|
||||||
return nil, errors.New("nil application log")
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*SetAdminEvent
|
|
||||||
for i, ex := range log.Executions {
|
|
||||||
for j, e := range ex.Events {
|
|
||||||
if e.Name != "SetAdmin" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
event := new(SetAdminEvent)
|
|
||||||
err := event.FromStackItem(e.Item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to deserialize SetAdminEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
|
||||||
}
|
|
||||||
res = append(res, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem converts provided [stackitem.Array] to SetAdminEvent or
|
|
||||||
// returns an error if it's not possible to do to so.
|
|
||||||
func (e *SetAdminEvent) 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) != 3 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
e.Name, 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 Name: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.OldAdmin, 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 OldAdmin: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.NewAdmin, 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 NewAdmin: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewEventsFromApplicationLog retrieves a set of all emitted events
|
|
||||||
// with "Renew" name from the provided [result.ApplicationLog].
|
|
||||||
func RenewEventsFromApplicationLog(log *result.ApplicationLog) ([]*RenewEvent, error) {
|
|
||||||
if log == nil {
|
|
||||||
return nil, errors.New("nil application log")
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*RenewEvent
|
|
||||||
for i, ex := range log.Executions {
|
|
||||||
for j, e := range ex.Events {
|
|
||||||
if e.Name != "Renew" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
event := new(RenewEvent)
|
|
||||||
err := event.FromStackItem(e.Item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to deserialize RenewEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
|
||||||
}
|
|
||||||
res = append(res, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem converts provided [stackitem.Array] to RenewEvent or
|
|
||||||
// returns an error if it's not possible to do to so.
|
|
||||||
func (e *RenewEvent) 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) != 3 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
e.Name, 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 Name: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.OldExpiration, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field OldExpiration: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.NewExpiration, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NewExpiration: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,441 +0,0 @@
|
||||||
{
|
|
||||||
"abi" : {
|
|
||||||
"events" : [
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "from",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "to",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "amount",
|
|
||||||
"type" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "ByteArray",
|
|
||||||
"name" : "tokenId"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "Transfer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "String",
|
|
||||||
"name" : "name"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "oldAdmin"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "newAdmin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "SetAdmin"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "Renew",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "oldExpiration"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "newExpiration",
|
|
||||||
"type" : "Integer"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"methods" : [
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"parameters" : [],
|
|
||||||
"name" : "symbol",
|
|
||||||
"returntype" : "String",
|
|
||||||
"offset" : 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters" : [],
|
|
||||||
"name" : "decimals",
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"safe" : true,
|
|
||||||
"offset" : 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 8,
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"name" : "totalSupply",
|
|
||||||
"parameters" : [],
|
|
||||||
"safe" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 53,
|
|
||||||
"safe" : true,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "ByteArray",
|
|
||||||
"name" : "tokenId"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "ownerOf",
|
|
||||||
"returntype" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"name" : "properties",
|
|
||||||
"returntype" : "Map",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "ByteArray",
|
|
||||||
"name" : "tokenId"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 184
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"name" : "balanceOf",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "owner",
|
|
||||||
"type" : "Hash160"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 341
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "InteropInterface",
|
|
||||||
"name" : "tokens",
|
|
||||||
"parameters" : [],
|
|
||||||
"offset" : 453
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"name" : "tokensOf",
|
|
||||||
"returntype" : "InteropInterface",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "owner",
|
|
||||||
"type" : "Hash160"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 494
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 600,
|
|
||||||
"safe" : false,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "to"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "tokenId",
|
|
||||||
"type" : "ByteArray"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "data",
|
|
||||||
"type" : "Any"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "transfer",
|
|
||||||
"returntype" : "Boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "update",
|
|
||||||
"returntype" : "Void",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "ByteArray",
|
|
||||||
"name" : "nef"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "manifest",
|
|
||||||
"type" : "String"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : false,
|
|
||||||
"offset" : 1121
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1291,
|
|
||||||
"returntype" : "Void",
|
|
||||||
"name" : "addRoot",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "root",
|
|
||||||
"type" : "String"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1725,
|
|
||||||
"safe" : true,
|
|
||||||
"parameters" : [],
|
|
||||||
"returntype" : "InteropInterface",
|
|
||||||
"name" : "roots"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1757,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Array",
|
|
||||||
"name" : "priceList"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "setPrice",
|
|
||||||
"returntype" : "Void",
|
|
||||||
"safe" : false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1952,
|
|
||||||
"safe" : true,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "length",
|
|
||||||
"type" : "Integer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "getPrice",
|
|
||||||
"returntype" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 2017,
|
|
||||||
"safe" : true,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "String",
|
|
||||||
"name" : "name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "isAvailable",
|
|
||||||
"returntype" : "Boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 2405,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "String",
|
|
||||||
"name" : "name"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "owner"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "register",
|
|
||||||
"returntype" : "Boolean",
|
|
||||||
"safe" : false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "renew",
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "String",
|
|
||||||
"name" : "name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : false,
|
|
||||||
"offset" : 3113
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 3123,
|
|
||||||
"safe" : false,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "years",
|
|
||||||
"type" : "Integer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "renew",
|
|
||||||
"returntype" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 3697,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "String",
|
|
||||||
"name" : "name"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "admin",
|
|
||||||
"type" : "Hash160"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "setAdmin",
|
|
||||||
"returntype" : "Void",
|
|
||||||
"safe" : false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void",
|
|
||||||
"name" : "setRecord",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "type"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "data",
|
|
||||||
"type" : "String"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 3921
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "getRecord",
|
|
||||||
"returntype" : "String",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "type"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : true,
|
|
||||||
"offset" : 5877
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"returntype" : "InteropInterface",
|
|
||||||
"name" : "getAllRecords",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : true,
|
|
||||||
"offset" : 6201
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void",
|
|
||||||
"name" : "deleteRecord",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "type"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 6281
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 6565,
|
|
||||||
"name" : "resolve",
|
|
||||||
"returntype" : "String",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "name",
|
|
||||||
"type" : "String"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "type"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : false,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "data",
|
|
||||||
"type" : "Any"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "update",
|
|
||||||
"type" : "Boolean"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "_deploy",
|
|
||||||
"returntype" : "Void",
|
|
||||||
"offset" : 7152
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 7514,
|
|
||||||
"parameters" : [],
|
|
||||||
"returntype" : "Void",
|
|
||||||
"name" : "_initialize",
|
|
||||||
"safe" : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"supportedstandards" : [
|
|
||||||
"NEP-11"
|
|
||||||
],
|
|
||||||
"permissions" : [
|
|
||||||
{
|
|
||||||
"contract" : "0x726cb6e0cd8628a1350a611384688911ab75f51b",
|
|
||||||
"methods" : [
|
|
||||||
"ripemd160"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contract" : "0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0",
|
|
||||||
"methods" : [
|
|
||||||
"atoi",
|
|
||||||
"deserialize",
|
|
||||||
"serialize",
|
|
||||||
"stringSplit"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contract" : "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5",
|
|
||||||
"methods" : [
|
|
||||||
"getCommittee"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contract" : "0xfffdc93764dbaddd97c48f252a53ea4643faa3fd",
|
|
||||||
"methods" : [
|
|
||||||
"getContract",
|
|
||||||
"update"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"methods" : [
|
|
||||||
"onNEP11Payment"
|
|
||||||
],
|
|
||||||
"contract" : "*"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"features" : {},
|
|
||||||
"name" : "NameService",
|
|
||||||
"trusts" : [],
|
|
||||||
"extra" : {
|
|
||||||
"Author" : "The Neo Project",
|
|
||||||
"Description" : "Neo Name Service",
|
|
||||||
"Email" : "dev@neo.org"
|
|
||||||
},
|
|
||||||
"groups" : []
|
|
||||||
}
|
|
339
cli/smartcontract/testdata/nex/nex.go
vendored
339
cli/smartcontract/testdata/nex/nex.go
vendored
|
@ -1,339 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"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/rpcclient/nep17"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash contains contract hash.
|
|
||||||
var Hash = util.Uint160{0xa8, 0x1a, 0xa1, 0xf0, 0x4b, 0xf, 0xdc, 0x4a, 0xa2, 0xce, 0xd5, 0xbf, 0xc6, 0x22, 0xcf, 0xe8, 0x9, 0x7f, 0xa6, 0xa2}
|
|
||||||
|
|
||||||
// OnMintEvent represents "OnMint" event emitted by the contract.
|
|
||||||
type OnMintEvent struct {
|
|
||||||
From util.Uint160
|
|
||||||
To util.Uint160
|
|
||||||
Amount *big.Int
|
|
||||||
SwapId *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
|
||||||
type Invoker interface {
|
|
||||||
nep17.Invoker
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actor is used by Contract to call state-changing methods.
|
|
||||||
type Actor interface {
|
|
||||||
Invoker
|
|
||||||
|
|
||||||
nep17.Actor
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
nep17.TokenReader
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contract implements all contract methods.
|
|
||||||
type Contract struct {
|
|
||||||
ContractReader
|
|
||||||
nep17.TokenWriter
|
|
||||||
actor Actor
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker) *ContractReader {
|
|
||||||
var hash = Hash
|
|
||||||
return &ContractReader{*nep17.NewReader(invoker, hash), invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates an instance of Contract using Hash and the given Actor.
|
|
||||||
func New(actor Actor) *Contract {
|
|
||||||
var hash = Hash
|
|
||||||
var nep17t = nep17.New(actor, hash)
|
|
||||||
return &Contract{ContractReader{nep17t.TokenReader, actor, hash}, nep17t.TokenWriter, actor, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cap invokes `cap` method of contract.
|
|
||||||
func (c *ContractReader) Cap() (*big.Int, error) {
|
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "cap"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMinter invokes `getMinter` method of contract.
|
|
||||||
func (c *ContractReader) GetMinter() (*keys.PublicKey, error) {
|
|
||||||
return unwrap.PublicKey(c.invoker.Call(c.hash, "getMinter"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOwner invokes `getOwner` method of contract.
|
|
||||||
func (c *ContractReader) GetOwner() (util.Uint160, error) {
|
|
||||||
return unwrap.Uint160(c.invoker.Call(c.hash, "getOwner"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TotalMinted invokes `totalMinted` method of contract.
|
|
||||||
func (c *ContractReader) TotalMinted() (*big.Int, error) {
|
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "totalMinted"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeMinter creates a transaction invoking `changeMinter` 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) ChangeMinter(newMinter *keys.PublicKey) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "changeMinter", newMinter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeMinterTransaction creates a transaction invoking `changeMinter` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) ChangeMinterTransaction(newMinter *keys.PublicKey) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "changeMinter", newMinter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeMinterUnsigned creates a transaction invoking `changeMinter` 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) ChangeMinterUnsigned(newMinter *keys.PublicKey) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "changeMinter", nil, newMinter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeOwner creates a transaction invoking `changeOwner` 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) ChangeOwner(newOwner util.Uint160) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "changeOwner", newOwner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeOwnerTransaction creates a transaction invoking `changeOwner` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) ChangeOwnerTransaction(newOwner util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "changeOwner", newOwner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeOwnerUnsigned creates a transaction invoking `changeOwner` 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) ChangeOwnerUnsigned(newOwner util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "changeOwner", nil, newOwner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy creates a transaction invoking `destroy` 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) Destroy() (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "destroy")
|
|
||||||
}
|
|
||||||
|
|
||||||
// DestroyTransaction creates a transaction invoking `destroy` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) DestroyTransaction() (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "destroy")
|
|
||||||
}
|
|
||||||
|
|
||||||
// DestroyUnsigned creates a transaction invoking `destroy` 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) DestroyUnsigned() (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "destroy", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxSupply creates a transaction invoking `maxSupply` 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) MaxSupply() (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "maxSupply")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxSupplyTransaction creates a transaction invoking `maxSupply` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) MaxSupplyTransaction() (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "maxSupply")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxSupplyUnsigned creates a transaction invoking `maxSupply` 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) MaxSupplyUnsigned() (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "maxSupply", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mint creates a transaction invoking `mint` 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) Mint(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "mint", from, to, amount, swapId, signature, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MintTransaction creates a transaction invoking `mint` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) MintTransaction(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "mint", from, to, amount, swapId, signature, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MintUnsigned creates a transaction invoking `mint` 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) MintUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "mint", nil, from, to, amount, swapId, signature, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update creates a transaction invoking `update` 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) Update(nef []byte, manifest []byte) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "update", nef, manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateTransaction creates a transaction invoking `update` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) UpdateTransaction(nef []byte, manifest []byte) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "update", nef, manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateUnsigned creates a transaction invoking `update` 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) UpdateUnsigned(nef []byte, manifest []byte) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "update", nil, nef, manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCap creates a transaction invoking `updateCap` 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) UpdateCap(newCap *big.Int) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "updateCap", newCap)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCapTransaction creates a transaction invoking `updateCap` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) UpdateCapTransaction(newCap *big.Int) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "updateCap", newCap)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCapUnsigned creates a transaction invoking `updateCap` 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) UpdateCapUnsigned(newCap *big.Int) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "updateCap", nil, newCap)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnMintEventsFromApplicationLog retrieves a set of all emitted events
|
|
||||||
// with "OnMint" name from the provided [result.ApplicationLog].
|
|
||||||
func OnMintEventsFromApplicationLog(log *result.ApplicationLog) ([]*OnMintEvent, error) {
|
|
||||||
if log == nil {
|
|
||||||
return nil, errors.New("nil application log")
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*OnMintEvent
|
|
||||||
for i, ex := range log.Executions {
|
|
||||||
for j, e := range ex.Events {
|
|
||||||
if e.Name != "OnMint" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
event := new(OnMintEvent)
|
|
||||||
err := event.FromStackItem(e.Item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to deserialize OnMintEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
|
||||||
}
|
|
||||||
res = append(res, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem converts provided [stackitem.Array] to OnMintEvent or
|
|
||||||
// returns an error if it's not possible to do to so.
|
|
||||||
func (e *OnMintEvent) 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) != 4 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
e.From, 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 From: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.To, 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 To: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.Amount, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Amount: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.SwapId, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field SwapId: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
275
cli/smartcontract/testdata/nex/nex.manifest.json
vendored
275
cli/smartcontract/testdata/nex/nex.manifest.json
vendored
|
@ -1,275 +0,0 @@
|
||||||
{
|
|
||||||
"name" : "NEX Token",
|
|
||||||
"abi" : {
|
|
||||||
"events" : [
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "from"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "to",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "amount",
|
|
||||||
"type" : "Integer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "Transfer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "OnMint",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "from",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "to"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "amount"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "swapId",
|
|
||||||
"type" : "Integer"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"methods" : [
|
|
||||||
{
|
|
||||||
"parameters" : [],
|
|
||||||
"offset" : 0,
|
|
||||||
"name" : "_initialize",
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Any",
|
|
||||||
"name" : "data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "isUpdate",
|
|
||||||
"type" : "Boolean"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 3,
|
|
||||||
"name" : "_deploy",
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "holder"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 484,
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"safe" : true,
|
|
||||||
"name" : "balanceOf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"name" : "cap",
|
|
||||||
"offset" : 1881,
|
|
||||||
"parameters" : []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "changeMinter",
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void",
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "newMinter",
|
|
||||||
"type" : "PublicKey"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 1678
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "newOwner"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"offset" : 1659,
|
|
||||||
"name" : "changeOwner",
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 466,
|
|
||||||
"parameters" : [],
|
|
||||||
"safe" : true,
|
|
||||||
"name" : "decimals",
|
|
||||||
"returntype" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"returntype" : "Void",
|
|
||||||
"safe" : false,
|
|
||||||
"name" : "destroy",
|
|
||||||
"parameters" : [],
|
|
||||||
"offset" : 1194
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "PublicKey",
|
|
||||||
"name" : "getMinter",
|
|
||||||
"offset" : 1671,
|
|
||||||
"parameters" : []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters" : [],
|
|
||||||
"offset" : 1652,
|
|
||||||
"name" : "getOwner",
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "maxSupply",
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Integer",
|
|
||||||
"parameters" : [],
|
|
||||||
"offset" : 468
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1222,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "from",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "to",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "amount"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "swapId",
|
|
||||||
"type" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "signature",
|
|
||||||
"type" : "Signature"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "data",
|
|
||||||
"type" : "Any"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : false,
|
|
||||||
"name" : "mint",
|
|
||||||
"returntype" : "Void"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"safe" : true,
|
|
||||||
"name" : "symbol",
|
|
||||||
"returntype" : "String",
|
|
||||||
"parameters" : [],
|
|
||||||
"offset" : 460
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1854,
|
|
||||||
"parameters" : [],
|
|
||||||
"name" : "totalMinted",
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 478,
|
|
||||||
"parameters" : [],
|
|
||||||
"name" : "totalSupply",
|
|
||||||
"safe" : true,
|
|
||||||
"returntype" : "Integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 543,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"name" : "from",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "to",
|
|
||||||
"type" : "Hash160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "amount"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "data",
|
|
||||||
"type" : "Any"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "transfer",
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1205,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "ByteArray",
|
|
||||||
"name" : "nef"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name" : "manifest",
|
|
||||||
"type" : "ByteArray"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"safe" : false,
|
|
||||||
"returntype" : "Void",
|
|
||||||
"name" : "update"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1717,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "newCap"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"returntype" : "Void",
|
|
||||||
"safe" : false,
|
|
||||||
"name" : "updateCap"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"supportedstandards" : [
|
|
||||||
"NEP-17"
|
|
||||||
],
|
|
||||||
"extra" : null,
|
|
||||||
"trusts" : [],
|
|
||||||
"features" : {},
|
|
||||||
"groups" : [],
|
|
||||||
"permissions" : [
|
|
||||||
{
|
|
||||||
"methods" : [
|
|
||||||
"onNEP17Payment"
|
|
||||||
],
|
|
||||||
"contract" : "*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"methods" : [
|
|
||||||
"update",
|
|
||||||
"destroy"
|
|
||||||
],
|
|
||||||
"contract" : "0xfffdc93764dbaddd97c48f252a53ea4643faa3fd"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
63
cli/smartcontract/testdata/nonepiter/iter.go
vendored
63
cli/smartcontract/testdata/nonepiter/iter.go
vendored
|
@ -1,63 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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}
|
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
|
||||||
type Invoker interface {
|
|
||||||
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
|
||||||
CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...any) (*result.Invoke, error)
|
|
||||||
TerminateSession(sessionID uuid.UUID) error
|
|
||||||
TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker) *ContractReader {
|
|
||||||
var hash = Hash
|
|
||||||
return &ContractReader{invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tokens invokes `tokens` method of contract.
|
|
||||||
func (c *ContractReader) Tokens() (uuid.UUID, result.Iterator, error) {
|
|
||||||
return unwrap.SessionIterator(c.invoker.Call(c.hash, "tokens"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokensExpanded is similar to Tokens (uses the same contract
|
|
||||||
// method), but can be useful if the server used doesn't support sessions and
|
|
||||||
// doesn't expand iterators. It creates a script that will get the specified
|
|
||||||
// number of result items from the iterator right in the VM and return them to
|
|
||||||
// you. It's only limited by VM stack and GAS available for RPC invocations.
|
|
||||||
func (c *ContractReader) TokensExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) {
|
|
||||||
return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "tokens", _numOfIteratorItems))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllRecords invokes `getAllRecords` method of contract.
|
|
||||||
func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) {
|
|
||||||
return unwrap.SessionIterator(c.invoker.Call(c.hash, "getAllRecords", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract
|
|
||||||
// method), but can be useful if the server used doesn't support sessions and
|
|
||||||
// doesn't expand iterators. It creates a script that will get the specified
|
|
||||||
// number of result items from the iterator right in the VM and return them to
|
|
||||||
// you. It's only limited by VM stack and GAS available for RPC invocations.
|
|
||||||
func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) {
|
|
||||||
return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "getAllRecords", _numOfIteratorItems, name))
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"groups" : [],
|
|
||||||
"abi" : {
|
|
||||||
"events" : [],
|
|
||||||
"methods" : [
|
|
||||||
{
|
|
||||||
"parameters" : [],
|
|
||||||
"safe" : true,
|
|
||||||
"name" : "tokens",
|
|
||||||
"offset" : 0,
|
|
||||||
"returntype" : "InteropInterface"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset" : 1,
|
|
||||||
"returntype" : "InteropInterface",
|
|
||||||
"safe" : true,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "String",
|
|
||||||
"name" : "name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "getAllRecords"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"supportedstandards" : [],
|
|
||||||
"trusts" : [],
|
|
||||||
"extra" : {},
|
|
||||||
"permissions" : [],
|
|
||||||
"name" : "Non-NEPXX contract with iterators",
|
|
||||||
"features" : {}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package invalid1
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
||||||
|
|
||||||
func Main() {
|
|
||||||
runtime.Notify("Non declared event")
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
name: Test undeclared event
|
|
|
@ -1,7 +0,0 @@
|
||||||
package invalid2
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
||||||
|
|
||||||
func Main() {
|
|
||||||
runtime.Notify("SomeEvent", "p1", "p2")
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
name: Test undeclared event
|
|
||||||
events:
|
|
||||||
- name: SomeEvent
|
|
||||||
parameters:
|
|
||||||
- name: p1
|
|
||||||
type: String
|
|
|
@ -1,7 +0,0 @@
|
||||||
package invalid3
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
||||||
|
|
||||||
func Main() {
|
|
||||||
runtime.Notify("SomeEvent", "p1", 5)
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
name: Test undeclared event
|
|
||||||
events:
|
|
||||||
- name: SomeEvent
|
|
||||||
parameters:
|
|
||||||
- name: p1
|
|
||||||
type: String
|
|
||||||
- name: p2
|
|
||||||
type: String
|
|
|
@ -1,17 +0,0 @@
|
||||||
package invalid4
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
||||||
|
|
||||||
type SomeStruct1 struct {
|
|
||||||
Field1 int
|
|
||||||
}
|
|
||||||
|
|
||||||
type SomeStruct2 struct {
|
|
||||||
Field2 string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Main() {
|
|
||||||
// Inconsistent event params usages (different named types throughout the usages).
|
|
||||||
runtime.Notify("SomeEvent", SomeStruct1{Field1: 123})
|
|
||||||
runtime.Notify("SomeEvent", SomeStruct2{Field2: "str"})
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
name: Test undeclared event
|
|
||||||
events:
|
|
||||||
- name: SomeEvent
|
|
||||||
parameters:
|
|
||||||
- name: p1
|
|
||||||
type: Array
|
|
|
@ -1,12 +0,0 @@
|
||||||
package invalid5
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
||||||
|
|
||||||
type NamedStruct struct {
|
|
||||||
SomeInt int
|
|
||||||
}
|
|
||||||
|
|
||||||
func Main() NamedStruct {
|
|
||||||
runtime.Notify("SomeEvent", []interface{}{123})
|
|
||||||
return NamedStruct{SomeInt: 123}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
name: Test undeclared event
|
|
||||||
events:
|
|
||||||
- name: SomeEvent
|
|
||||||
parameters:
|
|
||||||
- name: p1
|
|
||||||
type: Array
|
|
||||||
extendedtype:
|
|
||||||
base: Array
|
|
||||||
name: invalid5.NamedStruct
|
|
||||||
namedtypes:
|
|
||||||
invalid5.NamedStruct:
|
|
||||||
base: Array
|
|
||||||
name: invalid5.NamedStruct
|
|
||||||
fields:
|
|
||||||
- field: SomeInt
|
|
||||||
base: Integer
|
|
|
@ -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})
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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})
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
name: Test duplicating autogenerated event fields
|
|
||||||
events:
|
|
||||||
- name: SomeEvent
|
|
||||||
parameters:
|
|
||||||
- name: p1
|
|
||||||
type: Struct
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
name: Test duplicating struct fields
|
|
|
@ -1,23 +0,0 @@
|
||||||
name: "Notifications"
|
|
||||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
|
||||||
events:
|
|
||||||
- name: "! complicated name %$#"
|
|
||||||
parameters:
|
|
||||||
- name: ! complicated param @#$%
|
|
||||||
type: String
|
|
||||||
- name: "SomeMap"
|
|
||||||
parameters:
|
|
||||||
- name: m
|
|
||||||
type: Map
|
|
||||||
- name: "SomeStruct"
|
|
||||||
parameters:
|
|
||||||
- name: s
|
|
||||||
type: Struct
|
|
||||||
- name: "SomeArray"
|
|
||||||
parameters:
|
|
||||||
- name: a
|
|
||||||
type: Array
|
|
||||||
- name: "SomeUnexportedField"
|
|
||||||
parameters:
|
|
||||||
- name: s
|
|
||||||
type: Struct
|
|
|
@ -1,60 +0,0 @@
|
||||||
name: "Notifications"
|
|
||||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
|
||||||
events:
|
|
||||||
- name: "! complicated name %$#"
|
|
||||||
parameters:
|
|
||||||
- name: ! complicated param @#$%
|
|
||||||
type: String
|
|
||||||
- name: "SomeMap"
|
|
||||||
parameters:
|
|
||||||
- name: m
|
|
||||||
type: Map
|
|
||||||
extendedtype:
|
|
||||||
base: Map
|
|
||||||
key: Integer
|
|
||||||
value:
|
|
||||||
base: Map
|
|
||||||
key: String
|
|
||||||
value:
|
|
||||||
base: Array
|
|
||||||
value:
|
|
||||||
base: Hash160
|
|
||||||
- name: "SomeStruct"
|
|
||||||
parameters:
|
|
||||||
- name: s
|
|
||||||
type: Struct
|
|
||||||
extendedtype:
|
|
||||||
base: Struct
|
|
||||||
name: crazyStruct
|
|
||||||
- name: "SomeArray"
|
|
||||||
parameters:
|
|
||||||
- name: a
|
|
||||||
type: Array
|
|
||||||
extendedtype:
|
|
||||||
base: Array
|
|
||||||
value:
|
|
||||||
base: Array
|
|
||||||
value:
|
|
||||||
base: Integer
|
|
||||||
- name: "SomeUnexportedField"
|
|
||||||
parameters:
|
|
||||||
- name: s
|
|
||||||
type: Struct
|
|
||||||
extendedtype:
|
|
||||||
base: Struct
|
|
||||||
name: simpleStruct
|
|
||||||
namedtypes:
|
|
||||||
crazyStruct:
|
|
||||||
base: Struct
|
|
||||||
name: crazyStruct
|
|
||||||
fields:
|
|
||||||
- field: I
|
|
||||||
base: Integer
|
|
||||||
- field: B
|
|
||||||
base: Boolean
|
|
||||||
simpleStruct:
|
|
||||||
base: Struct
|
|
||||||
name: simpleStruct
|
|
||||||
fields:
|
|
||||||
- field: i
|
|
||||||
base: Integer
|
|
|
@ -1,23 +0,0 @@
|
||||||
name: "Notifications"
|
|
||||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
|
||||||
events:
|
|
||||||
- name: "! complicated name %$#"
|
|
||||||
parameters:
|
|
||||||
- name: ! complicated param @#$%
|
|
||||||
type: String
|
|
||||||
- name: "SomeMap"
|
|
||||||
parameters:
|
|
||||||
- name: m
|
|
||||||
type: Map
|
|
||||||
- name: "SomeStruct"
|
|
||||||
parameters:
|
|
||||||
- name: s
|
|
||||||
type: Struct
|
|
||||||
- name: "SomeArray"
|
|
||||||
parameters:
|
|
||||||
- name: a
|
|
||||||
type: Array
|
|
||||||
- name: "SomeUnexportedField"
|
|
||||||
parameters:
|
|
||||||
- name: s
|
|
||||||
type: Struct
|
|
|
@ -1,33 +0,0 @@
|
||||||
package structs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Main() {
|
|
||||||
runtime.Notify("! complicated name %$#", "str1")
|
|
||||||
}
|
|
||||||
|
|
||||||
func CrazyMap() {
|
|
||||||
runtime.Notify("SomeMap", map[int][]map[string][]interop.Hash160{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Struct() {
|
|
||||||
runtime.Notify("SomeStruct", struct {
|
|
||||||
I int
|
|
||||||
B bool
|
|
||||||
}{I: 123, B: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
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})
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -1,623 +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"
|
|
||||||
"math/big"
|
|
||||||
"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}
|
|
||||||
|
|
||||||
// CrazyStruct is a contract-specific crazyStruct type used by its methods.
|
|
||||||
type CrazyStruct struct {
|
|
||||||
I *big.Int
|
|
||||||
B bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleStruct is a contract-specific simpleStruct type used by its methods.
|
|
||||||
type SimpleStruct struct {
|
|
||||||
I *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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[*big.Int]map[string][]util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
|
|
||||||
type SomeStructEvent struct {
|
|
||||||
S *CrazyStruct
|
|
||||||
}
|
|
||||||
|
|
||||||
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToCrazyStruct converts stack item into *CrazyStruct.
|
|
||||||
func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(CrazyStruct)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of CrazyStruct from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *CrazyStruct) 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToSimpleStruct converts stack item into *SimpleStruct.
|
|
||||||
func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(SimpleStruct)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of SimpleStruct 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 {
|
|
||||||
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) {
|
|
||||||
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[*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())
|
|
||||||
}
|
|
||||||
res := make(map[*big.Int]map[string][]util.Uint160)
|
|
||||||
for i := range m {
|
|
||||||
k, err := m[i].Key.TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
|
||||||
}
|
|
||||||
res[k] = v
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(m[i].Value)
|
|
||||||
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 = itemToCrazyStruct(arr[index], nil)
|
|
||||||
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) ([][]*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) {
|
|
||||||
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 = arr[i].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, 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 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
|
|
||||||
}
|
|
|
@ -1,636 +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"
|
|
||||||
"math/big"
|
|
||||||
"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}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// SomeMapEvent represents "SomeMap" event emitted by the contract.
|
|
||||||
type SomeMapEvent struct {
|
|
||||||
M map[*big.Int][]map[string][]util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
|
|
||||||
type SomeStructEvent struct {
|
|
||||||
S *Unnamed
|
|
||||||
}
|
|
||||||
|
|
||||||
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) != 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
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[*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())
|
|
||||||
}
|
|
||||||
res := make(map[*big.Int][]map[string][]util.Uint160)
|
|
||||||
for i := range m {
|
|
||||||
k, err := m[i].Key.TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
|
||||||
}
|
|
||||||
res[k] = v
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(m[i].Value)
|
|
||||||
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 = itemToUnnamed(arr[index], nil)
|
|
||||||
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) ([][]*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) {
|
|
||||||
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 = arr[i].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, 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 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
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
name: "Types"
|
|
||||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
|
||||||
safemethods: ["contract", "block", "transaction", "struct"]
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
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"]
|
|
|
@ -1,444 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"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/rpcclient/unwrap"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
"math/big"
|
|
||||||
"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}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker) *ContractReader {
|
|
||||||
var hash = Hash
|
|
||||||
return &ContractReader{invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AAAStrings invokes `aAAStrings` method of contract.
|
|
||||||
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
|
||||||
return func(item stackitem.Item, err error) ([][][]string, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any invokes `any` method of contract.
|
|
||||||
func (c *ContractReader) Any(a any) (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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
res := make(map[*big.Int]any)
|
|
||||||
for i := range m {
|
|
||||||
k, err := m[i].Key.TryInteger()
|
|
||||||
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
|
|
||||||
}(item)
|
|
||||||
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool invokes `bool` method of contract.
|
|
||||||
func (c *ContractReader) Bool(b bool) (bool, error) {
|
|
||||||
return unwrap.Bool(c.invoker.Call(c.hash, "bool", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bools invokes `bools` method of contract.
|
|
||||||
func (c *ContractReader) Bools(b []bool) ([]bool, error) {
|
|
||||||
return unwrap.ArrayOfBools(c.invoker.Call(c.hash, "bools", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes invokes `bytes` method of contract.
|
|
||||||
func (c *ContractReader) Bytes(b []byte) ([]byte, error) {
|
|
||||||
return unwrap.Bytes(c.invoker.Call(c.hash, "bytes", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytess invokes `bytess` method of contract.
|
|
||||||
func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
|
|
||||||
return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "bytess", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
res := make(map[*big.Int][]map[string][]util.Uint160)
|
|
||||||
for i := range m {
|
|
||||||
k, err := m[i].Key.TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
|
||||||
}
|
|
||||||
res[k] = v
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash160 invokes `hash160` method of contract.
|
|
||||||
func (c *ContractReader) Hash160(h util.Uint160) (util.Uint160, error) {
|
|
||||||
return unwrap.Uint160(c.invoker.Call(c.hash, "hash160", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash160s invokes `hash160s` method of contract.
|
|
||||||
func (c *ContractReader) Hash160s(h []util.Uint160) ([]util.Uint160, error) {
|
|
||||||
return unwrap.ArrayOfUint160(c.invoker.Call(c.hash, "hash160s", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash256 invokes `hash256` method of contract.
|
|
||||||
func (c *ContractReader) Hash256(h util.Uint256) (util.Uint256, error) {
|
|
||||||
return unwrap.Uint256(c.invoker.Call(c.hash, "hash256", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash256s invokes `hash256s` method of contract.
|
|
||||||
func (c *ContractReader) Hash256s(h []util.Uint256) ([]util.Uint256, error) {
|
|
||||||
return unwrap.ArrayOfUint256(c.invoker.Call(c.hash, "hash256s", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int invokes `int` method of contract.
|
|
||||||
func (c *ContractReader) Int(i *big.Int) (*big.Int, error) {
|
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "int", i))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ints invokes `ints` method of contract.
|
|
||||||
func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
|
|
||||||
return unwrap.ArrayOfBigInts(c.invoker.Call(c.hash, "ints", i))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
v, 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
|
|
||||||
}(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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKey invokes `publicKey` method of contract.
|
|
||||||
func (c *ContractReader) PublicKey(k *keys.PublicKey) (*keys.PublicKey, error) {
|
|
||||||
return unwrap.PublicKey(c.invoker.Call(c.hash, "publicKey", k))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKeys invokes `publicKeys` method of contract.
|
|
||||||
func (c *ContractReader) PublicKeys(k keys.PublicKeys) (keys.PublicKeys, error) {
|
|
||||||
return unwrap.ArrayOfPublicKeys(c.invoker.Call(c.hash, "publicKeys", k))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signature invokes `signature` method of contract.
|
|
||||||
func (c *ContractReader) Signature(s []byte) ([]byte, error) {
|
|
||||||
return unwrap.Bytes(c.invoker.Call(c.hash, "signature", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signatures invokes `signatures` method of contract.
|
|
||||||
func (c *ContractReader) Signatures(s [][]byte) ([][]byte, error) {
|
|
||||||
return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "signatures", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String invokes `string` method of contract.
|
|
||||||
func (c *ContractReader) String(s string) (string, error) {
|
|
||||||
return unwrap.UTF8String(c.invoker.Call(c.hash, "string", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings invokes `strings` method of contract.
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,440 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"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/rpcclient/unwrap"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
"math/big"
|
|
||||||
"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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractReader implements safe contract methods.
|
|
||||||
type ContractReader struct {
|
|
||||||
invoker Invoker
|
|
||||||
hash util.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
|
|
||||||
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
|
|
||||||
return &ContractReader{invoker, hash}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AAAStrings invokes `aAAStrings` method of contract.
|
|
||||||
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
|
||||||
return func(item stackitem.Item, err error) ([][][]string, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any invokes `any` method of contract.
|
|
||||||
func (c *ContractReader) Any(a any) (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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
res := make(map[*big.Int]any)
|
|
||||||
for i := range m {
|
|
||||||
k, err := m[i].Key.TryInteger()
|
|
||||||
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
|
|
||||||
}(item)
|
|
||||||
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool invokes `bool` method of contract.
|
|
||||||
func (c *ContractReader) Bool(b bool) (bool, error) {
|
|
||||||
return unwrap.Bool(c.invoker.Call(c.hash, "bool", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bools invokes `bools` method of contract.
|
|
||||||
func (c *ContractReader) Bools(b []bool) ([]bool, error) {
|
|
||||||
return unwrap.ArrayOfBools(c.invoker.Call(c.hash, "bools", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes invokes `bytes` method of contract.
|
|
||||||
func (c *ContractReader) Bytes(b []byte) ([]byte, error) {
|
|
||||||
return unwrap.Bytes(c.invoker.Call(c.hash, "bytes", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytess invokes `bytess` method of contract.
|
|
||||||
func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
|
|
||||||
return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "bytess", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
res := make(map[*big.Int][]map[string][]util.Uint160)
|
|
||||||
for i := range m {
|
|
||||||
k, err := m[i].Key.TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
|
||||||
}
|
|
||||||
res[k] = v
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}(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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash160 invokes `hash160` method of contract.
|
|
||||||
func (c *ContractReader) Hash160(h util.Uint160) (util.Uint160, error) {
|
|
||||||
return unwrap.Uint160(c.invoker.Call(c.hash, "hash160", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash160s invokes `hash160s` method of contract.
|
|
||||||
func (c *ContractReader) Hash160s(h []util.Uint160) ([]util.Uint160, error) {
|
|
||||||
return unwrap.ArrayOfUint160(c.invoker.Call(c.hash, "hash160s", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash256 invokes `hash256` method of contract.
|
|
||||||
func (c *ContractReader) Hash256(h util.Uint256) (util.Uint256, error) {
|
|
||||||
return unwrap.Uint256(c.invoker.Call(c.hash, "hash256", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash256s invokes `hash256s` method of contract.
|
|
||||||
func (c *ContractReader) Hash256s(h []util.Uint256) ([]util.Uint256, error) {
|
|
||||||
return unwrap.ArrayOfUint256(c.invoker.Call(c.hash, "hash256s", h))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int invokes `int` method of contract.
|
|
||||||
func (c *ContractReader) Int(i *big.Int) (*big.Int, error) {
|
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "int", i))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ints invokes `ints` method of contract.
|
|
||||||
func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
|
|
||||||
return unwrap.ArrayOfBigInts(c.invoker.Call(c.hash, "ints", i))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
}(m[i].Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
|
||||||
}
|
|
||||||
v, 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
|
|
||||||
}(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)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKey invokes `publicKey` method of contract.
|
|
||||||
func (c *ContractReader) PublicKey(k *keys.PublicKey) (*keys.PublicKey, error) {
|
|
||||||
return unwrap.PublicKey(c.invoker.Call(c.hash, "publicKey", k))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKeys invokes `publicKeys` method of contract.
|
|
||||||
func (c *ContractReader) PublicKeys(k keys.PublicKeys) (keys.PublicKeys, error) {
|
|
||||||
return unwrap.ArrayOfPublicKeys(c.invoker.Call(c.hash, "publicKeys", k))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signature invokes `signature` method of contract.
|
|
||||||
func (c *ContractReader) Signature(s []byte) ([]byte, error) {
|
|
||||||
return unwrap.Bytes(c.invoker.Call(c.hash, "signature", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signatures invokes `signatures` method of contract.
|
|
||||||
func (c *ContractReader) Signatures(s [][]byte) ([][]byte, error) {
|
|
||||||
return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "signatures", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String invokes `string` method of contract.
|
|
||||||
func (c *ContractReader) String(s string) (string, error) {
|
|
||||||
return unwrap.UTF8String(c.invoker.Call(c.hash, "string", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings invokes `strings` method of contract.
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Bool(b bool) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func Int(i int) int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func Bytes(b []byte) []byte {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func String(s string) string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func Any(a any) any {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Hash160(h interop.Hash160) interop.Hash160 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Hash256(h interop.Hash256) interop.Hash256 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PublicKey(k interop.PublicKey) interop.PublicKey {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Signature(s interop.Signature) interop.Signature {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Bools(b []bool) []bool {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Ints(i []int) []int {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Bytess(b [][]byte) [][]byte {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Strings(s []string) []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Hash160s(h []interop.Hash160) []interop.Hash160 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Hash256s(h []interop.Hash256) []interop.Hash256 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PublicKeys(k []interop.PublicKey) []interop.PublicKey {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Signatures(s []interop.Signature) []interop.Signature {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func AAAStrings(s [][][]string) [][][]string {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func Maps(m map[string]string) map[string]string {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func CrazyMaps(m map[int][]map[string][]interop.Hash160) map[int][]map[string][]interop.Hash160 {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
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}
|
|
||||||
}
|
|
297
cli/smartcontract/testdata/verify.bindings.yml
vendored
297
cli/smartcontract/testdata/verify.bindings.yml
vendored
|
@ -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
|
|
147
cli/smartcontract/testdata/verifyrpc/verify.go
vendored
147
cli/smartcontract/testdata/verifyrpc/verify.go
vendored
|
@ -1,147 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
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/smartcontract"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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}
|
|
||||||
|
|
||||||
// HelloWorldEvent represents "Hello world!" event emitted by the contract.
|
|
||||||
type HelloWorldEvent struct {
|
|
||||||
Args []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}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Contract) scriptForVerify() ([]byte, error) {
|
|
||||||
return smartcontract.CreateCallWithAssertScript(c.hash, "verify")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify creates a transaction invoking `verify` 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) Verify() (util.Uint256, uint32, error) {
|
|
||||||
script, err := c.scriptForVerify()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, 0, err
|
|
||||||
}
|
|
||||||
return c.actor.SendRun(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyTransaction creates a transaction invoking `verify` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) VerifyTransaction() (*transaction.Transaction, error) {
|
|
||||||
script, err := c.scriptForVerify()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.actor.MakeRun(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyUnsigned creates a transaction invoking `verify` 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) VerifyUnsigned() (*transaction.Transaction, error) {
|
|
||||||
script, err := c.scriptForVerify()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.actor.MakeUnsignedRun(script, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HelloWorldEventsFromApplicationLog retrieves a set of all emitted events
|
|
||||||
// with "Hello world!" name from the provided [result.ApplicationLog].
|
|
||||||
func HelloWorldEventsFromApplicationLog(log *result.ApplicationLog) ([]*HelloWorldEvent, error) {
|
|
||||||
if log == nil {
|
|
||||||
return nil, errors.New("nil application log")
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*HelloWorldEvent
|
|
||||||
for i, ex := range log.Executions {
|
|
||||||
for j, e := range ex.Events {
|
|
||||||
if e.Name != "Hello world!" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
event := new(HelloWorldEvent)
|
|
||||||
err := event.FromStackItem(e.Item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to deserialize HelloWorldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
|
||||||
}
|
|
||||||
res = append(res, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem converts provided [stackitem.Array] to HelloWorldEvent or
|
|
||||||
// returns an error if it's not possible to do to so.
|
|
||||||
func (e *HelloWorldEvent) 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.Args, 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 Args: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
{
|
|
||||||
"groups" : [],
|
|
||||||
"extra" : null,
|
|
||||||
"supportedstandards" : [],
|
|
||||||
"name" : "verify",
|
|
||||||
"trusts" : [],
|
|
||||||
"permissions" : [
|
|
||||||
{
|
|
||||||
"methods" : "*",
|
|
||||||
"contract" : "*"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"abi" : {
|
|
||||||
"methods" : [
|
|
||||||
{
|
|
||||||
"safe" : false,
|
|
||||||
"offset" : 0,
|
|
||||||
"parameters" : [],
|
|
||||||
"name" : "verify",
|
|
||||||
"returntype" : "Boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"returntype" : "Void",
|
|
||||||
"safe" : false,
|
|
||||||
"offset" : 5,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "from"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "amount"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Any",
|
|
||||||
"name" : "data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "onNEP17Payment"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"returntype" : "Void",
|
|
||||||
"safe" : false,
|
|
||||||
"offset" : 5,
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Hash160",
|
|
||||||
"name" : "from"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Integer",
|
|
||||||
"name" : "amount"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "ByteArray",
|
|
||||||
"name" : "tokenid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type" : "Any",
|
|
||||||
"name" : "data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "onNEP11Payment"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"events" : [
|
|
||||||
{
|
|
||||||
"parameters" : [
|
|
||||||
{
|
|
||||||
"type" : "Array",
|
|
||||||
"name" : "args"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name" : "Hello world!"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
package deploy
|
package deploy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/smartcontract/testdata/deploy/sub"
|
"github.com/nspcc-dev/neo-go/cli/testdata/deploy/sub"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
"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/contract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||||
|
@ -13,7 +13,7 @@ var key = "key"
|
||||||
|
|
||||||
const mgmtKey = "mgmt"
|
const mgmtKey = "mgmt"
|
||||||
|
|
||||||
func _deploy(data any, isUpdate bool) {
|
func _deploy(data interface{}, isUpdate bool) {
|
||||||
var value string
|
var value string
|
||||||
|
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
@ -25,7 +25,7 @@ func _deploy(data any, isUpdate bool) {
|
||||||
storage.Put(ctx, mgmtKey, sh)
|
storage.Put(ctx, mgmtKey, sh)
|
||||||
|
|
||||||
if data != nil {
|
if data != nil {
|
||||||
arr := data.([]any)
|
arr := data.([]interface{})
|
||||||
for i := 0; i < len(arr)-1; i += 2 {
|
for i := 0; i < len(arr)-1; i += 2 {
|
||||||
storage.Put(ctx, arr[i], arr[i+1])
|
storage.Put(ctx, arr[i], arr[i+1])
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,12 @@ func GetValueWithKey(key string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFind finds items with the specified prefix.
|
// TestFind finds items with the specified prefix.
|
||||||
func TestFind(f storage.FindFlags) []any {
|
func TestFind(f storage.FindFlags) []interface{} {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
storage.Put(ctx, "findkey1", "value1")
|
storage.Put(ctx, "findkey1", "value1")
|
||||||
storage.Put(ctx, "findkey2", "value2")
|
storage.Put(ctx, "findkey2", "value2")
|
||||||
|
|
||||||
var result []any
|
var result []interface{}
|
||||||
iter := storage.Find(ctx, "findkey", f)
|
iter := storage.Find(ctx, "findkey", f)
|
||||||
for iterator.Next(iter) {
|
for iterator.Next(iter) {
|
||||||
result = append(result, iterator.Value(iter))
|
result = append(result, iterator.Value(iter))
|
|
@ -4,7 +4,7 @@ import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||||
|
|
||||||
var Key = "sub"
|
var Key = "sub"
|
||||||
|
|
||||||
func _deploy(data any, isUpdate bool) {
|
func _deploy(data interface{}, isUpdate bool) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
value := "sub create"
|
value := "sub create"
|
||||||
if isUpdate {
|
if isUpdate {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue