diff --git a/.forgejo/workflows/codegen.yml b/.forgejo/workflows/codegen.yml deleted file mode 100644 index 3aa9594..0000000 --- a/.forgejo/workflows/codegen.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Code generation -on: [pull_request] - -jobs: - wrappers: - name: Generate wrappers - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: '1.23' - - name: Generate wrappers - run: make generate-wrappers - # The command seems to be non-deterministic. - # However, with >20 runs I haven't been able to reproduce the issue. - # This `git diff` is here to print diff in case we catch the behaviour again. - - name: Print diff - run: git diff HEAD - - name: Check that nothing has changed - run: git diff-index --exit-code HEAD diff --git a/.forgejo/workflows/dco.yml b/.forgejo/workflows/dco.yml deleted file mode 100644 index 2374802..0000000 --- a/.forgejo/workflows/dco.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: DCO action -on: [pull_request] - -jobs: - dco: - name: DCO - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: '1.23' - - - name: Run commit format checker - uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3 - with: - from: 'origin/${{ github.event.pull_request.base.ref }}' diff --git a/.forgejo/workflows/tests.yml b/.forgejo/workflows/tests.yml deleted file mode 100644 index 5a5f1f2..0000000 --- a/.forgejo/workflows/tests.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Tests -on: [pull_request] - -jobs: - tests: - name: Tests - runs-on: ubuntu-latest - strategy: - matrix: - go_versions: [ '1.22', '1.23' ] - fail-fast: false - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: '${{ matrix.go_versions }}' - - - name: Run tests - run: make test diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..85fa6d9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @carpawell @fyrchik @cthulhu-rider diff --git a/.forgejo/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from .forgejo/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.forgejo/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .forgejo/ISSUE_TEMPLATE/config.yml rename to .github/ISSUE_TEMPLATE/config.yml diff --git a/.forgejo/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from .forgejo/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.forgejo/logo.svg b/.github/logo.svg similarity index 100% rename from .forgejo/logo.svg rename to .github/logo.svg diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml new file mode 100644 index 0000000..40ed8fc --- /dev/null +++ b/.github/workflows/dco.yml @@ -0,0 +1,21 @@ +name: DCO check + +on: + pull_request: + branches: + - master + +jobs: + commits_check_job: + runs-on: ubuntu-latest + name: Commits Check + steps: + - name: Get PR Commits + id: 'get-pr-commits' + uses: tim-actions/get-pr-commits@master + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: DCO Check + uses: tim-actions/dco@master + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..d1856c1 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,20 @@ +name: Go + +on: + pull_request: + branches: [ master ] + +jobs: + + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 + + - name: Test + run: go test -v ./... diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9b995..ef924ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,54 +1,13 @@ # Changelog Changelog for FrostFS Contract - ## [Unreleased] ### Added -- Field `state` to a namespace to indicate its' lifecycle stage (#154). -- Method `UpdateNamespace` to adjust namespace state (#154). -- Method `DeleteNamespace` to remove existing namespace (#168). - ### Changed ### Removed -### Updated -### Fixed - -## [0.21.0] - -### Added -- Mention domain name in error messages in the nns contract (#92) -- Emit DeleteRecord event on record deletion in the nns contract (#114) - -### Changed -- Allow to register TLD automatically (#114) -- Use frostfsid claims as a permission to create TLD (#115) -- Ensure subject keys are unique (#118, #129) - -### Fixed -- Terminate session in `ReadIteratorItems()` (#85) -- Declare `nns.getAllRecords` as safe (#131) - -## [0.20.0] - -### Added -- Add `ListFullSubjects` method to the frostfsid RPC client (#107) -- Add `ListChainNames` method to the policy contract (#105) -- Add `DeleteRecord` method to the nns contract (#114) -- Emit notification on record changes in nns contract (#109) - -### Updated -- neo-go to v0.106.3 - -## [0.18.0] - 2023-09-14 - Academy of Sciences Glacier - -### Added -- Documentation for contract storage schema (#21) -### Changed -- `container.Delete()` now accepts public key along with token (#27) -- Allow to check whether container was deleted with `container.DeletionInfo()` (#38) -### Removed - `subnet` contract (#20) + ### Updated ### Fixed ### Updating from v0.17.0 diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 2f44ab8..0000000 --- a/CODEOWNERS +++ /dev/null @@ -1,5 +0,0 @@ -.forgejo/.* @potyarkin -Makefile @potyarkin -frostfsid/client/.* @dkirillov -.* @TrueCloudLab/storage-core-developers @TrueCloudLab/storage-core-committers @TrueCloudLab/storage-service-developers @TrueCloudLab/storage-service-committers -tests/.* @fyrchik diff --git a/Makefile b/Makefile index e6e6a51..b80cddc 100644 --- a/Makefile +++ b/Makefile @@ -22,13 +22,12 @@ all: sidechain mainnet sidechain: alphabet morph nns alphabet_sc = alphabet -morph_sc = balance container frostfsid netmap proxy policy +morph_sc = audit balance container frostfsid netmap proxy reputation mainnet_sc = frostfs processing nns_sc = nns -all_sc = $(alphabet_sc) $(morph_sc) $(mainnet_sc) $(nns_sc) define sc_template -$(2)$(1)/$(1)_contract.nef: $(2)$(1)/$(1)_contract.go $(2)$(1)/config.yml +$(2)$(1)/$(1)_contract.nef: $(2)$(1)/$(1)_contract.go $(NEOGO) contract compile -i $(2)$(1) -c $(if $(2),$(2),$(1)/)config.yml -m $(2)$(1)/config.json -o $(2)$(1)/$(1)_contract.nef $(if $(2),$(2)$(1)/$(1)_contract.go: alphabet/alphabet.go alphabet/alphabet.tpl @@ -50,32 +49,9 @@ neo-go: @go list -f '{{.Path}}/...@{{.Version}}' -m github.com/nspcc-dev/neo-go \ | xargs go install -v -generate-wrapper.%: - @mkdir -p ./rpcclient/$* - @# Note, that bindings file is currently missing: is can be emitted by compiler, - @# but this leads to a large amount of code duplication. It can be written by hand, - @# in case we need to override the type of some variables. - @# --config $*/$*.bindings.yml - @# Unfortunately, primitive integer types are not yet supported. - $(NEOGO) contract generate-rpcwrapper --manifest=$*/config.json --out ./rpcclient/$*/client.go - -generate-wrappers: build $(foreach sc,$(all_sc),generate-wrapper.$(sc)) - test: @go test ./tests/... -# Run all code formatters -fmts: fumpt imports - -# Reformat imports -imports: - @echo "⇒ Processing goimports check" - @goimports -w $(all_sc) tests/ - -fumpt: - @echo "⇒ Processing gofumpt check" - @gofumpt -l -w $(all_sc) tests/ - clean: find . -name '*.nef' -exec rm -rf {} \; find . -name 'config.json' -exec rm -rf {} \; diff --git a/README.md b/README.md index d0bc70f..004861f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

-FrostFS +FrostFS

FrostFS related smart contracts. diff --git a/VERSION b/VERSION index e124b61..a86d3df 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.21.4 +v0.18.0 diff --git a/alphabet/alphabet_contract.go b/alphabet/alphabet_contract.go index af7540b..72aebe8 100644 --- a/alphabet/alphabet_contract.go +++ b/alphabet/alphabet_contract.go @@ -18,32 +18,38 @@ const ( indexKey = "index" totalKey = "threshold" nameKey = "name" + + notaryDisabledKey = "notary" ) // OnNEP17Payment is a callback for NEP-17 compatible native GAS and NEO // contracts. -func OnNEP17Payment(from interop.Hash160, amount int, data any) { +func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { caller := runtime.GetCallingScriptHash() if !common.BytesEqual(caller, []byte(gas.Hash)) && !common.BytesEqual(caller, []byte(neo.Hash)) { common.AbortWithMessage("alphabet contract accepts GAS and NEO only") } } -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } args := data.(struct { - addrNetmap interop.Hash160 - addrProxy interop.Hash160 - name string - index int - total int + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrNetmap interop.Hash160 + addrProxy interop.Hash160 + name string + index int + total int }) if len(args.addrNetmap) != interop.Hash160Len || len(args.addrProxy) != interop.Hash160Len { @@ -61,12 +67,13 @@ func _deploy(data any, isUpdate bool) { // Update method updates contract source code and manifest. It can be invoked // only by committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { if !common.HasUpdateAccess() { panic("only committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("alphabet contract updated") } diff --git a/alphabet/doc.go b/alphabet/doc.go index 9176aaf..2571e6b 100644 --- a/alphabet/doc.go +++ b/alphabet/doc.go @@ -17,15 +17,5 @@ for each alphabet contract. # Contract notifications Alphabet contract does not produce notifications to process. - -# Contract storage scheme - - | Key | Value | Description | - |--------------------|------------|-------------------------------------------------| - | `netmapScriptHash` | Hash160 | netmap contract hash | - | `proxyScriptHash` | Hash160 | proxy contract hash | - | `name` | string | assigned glagolitic letter | - | `index` | int | the index of deployed alphabet contract | - | `threshold` | int | the total number of deployed alphabet contracts | */ package alphabet diff --git a/audit/audit_contract.go b/audit/audit_contract.go new file mode 100644 index 0000000..638a76d --- /dev/null +++ b/audit/audit_contract.go @@ -0,0 +1,228 @@ +package audit + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-contract/common" + "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/crypto" + "github.com/nspcc-dev/neo-go/pkg/interop/native/management" + "github.com/nspcc-dev/neo-go/pkg/interop/runtime" + "github.com/nspcc-dev/neo-go/pkg/interop/storage" +) + +type ( + auditHeader struct { + epoch int + cid []byte + from interop.PublicKey + } +) + +// Audit key is a combination of the epoch, the container ID and the public key of the node that +// has executed the audit. Together, it shouldn't be more than 64 bytes. We can't shrink +// epoch and container ID since we iterate over these values. But we can shrink +// public key by using first bytes of the hashed value. + +// V2 format +const maxKeySize = 24 // 24 + 32 (container ID length) + 8 (epoch length) = 64 + +func (a auditHeader) ID() []byte { + var buf interface{} = a.epoch + + hashedKey := crypto.Sha256(a.from) + shortedKey := hashedKey[:maxKeySize] + + return append(buf.([]byte), append(a.cid, shortedKey...)...) +} + +const ( + netmapContractKey = "netmapScriptHash" + + notaryDisabledKey = "notary" +) + +func _deploy(data interface{}, isUpdate bool) { + ctx := storage.GetContext() + + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + + if isUpdate { + args := data.([]interface{}) + common.CheckVersion(args[len(args)-1].(int)) + return + } + + args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrNetmap interop.Hash160 + }) + + if len(args.addrNetmap) != interop.Hash160Len { + panic("incorrect length of contract script hash") + } + + storage.Put(ctx, netmapContractKey, args.addrNetmap) + + runtime.Log("audit contract initialized") +} + +// Update method updates contract source code and manifest. It can be invoked +// only by committee. +func Update(script []byte, manifest []byte, data interface{}) { + if !common.HasUpdateAccess() { + panic("only committee can update contract") + } + + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) + runtime.Log("audit contract updated") +} + +// Put method stores a stable marshalled `DataAuditResult` structure. It can be +// invoked only by Inner Ring nodes. +// +// Inner Ring nodes perform audit of containers and produce `DataAuditResult` +// structures. They are stored in audit contract and used for settlements +// in later epochs. +func Put(rawAuditResult []byte) { + ctx := storage.GetContext() + + innerRing := common.InnerRingNodes() + + hdr := newAuditHeader(rawAuditResult) + presented := false + + for i := range innerRing { + ir := innerRing[i] + if common.BytesEqual(ir, hdr.from) { + presented = true + + break + } + } + + if !runtime.CheckWitness(hdr.from) || !presented { + panic("put access denied") + } + + storage.Put(ctx, hdr.ID(), rawAuditResult) + + runtime.Log("audit: result has been saved") +} + +// Get method returns a stable marshaled DataAuditResult structure. +// +// The ID of the DataAuditResult can be obtained from listing methods. +func Get(id []byte) []byte { + ctx := storage.GetReadOnlyContext() + return storage.Get(ctx, id).([]byte) +} + +// List method returns a list of all available DataAuditResult IDs from +// the contract storage. +func List() [][]byte { + ctx := storage.GetReadOnlyContext() + it := storage.Find(ctx, []byte{}, storage.KeysOnly) + + return list(it) +} + +// ListByEpoch method returns a list of DataAuditResult IDs generated during +// the specified epoch. +func ListByEpoch(epoch int) [][]byte { + ctx := storage.GetReadOnlyContext() + var buf interface{} = epoch + it := storage.Find(ctx, buf.([]byte), storage.KeysOnly) + + return list(it) +} + +// ListByCID method returns a list of DataAuditResult IDs generated during +// the specified epoch for the specified container. +func ListByCID(epoch int, cid []byte) [][]byte { + ctx := storage.GetReadOnlyContext() + + var buf interface{} = epoch + + prefix := append(buf.([]byte), cid...) + it := storage.Find(ctx, prefix, storage.KeysOnly) + + return list(it) +} + +// ListByNode method returns a list of DataAuditResult IDs generated in +// the specified epoch for the specified container by the specified Inner Ring node. +func ListByNode(epoch int, cid []byte, key interop.PublicKey) [][]byte { + ctx := storage.GetReadOnlyContext() + hdr := auditHeader{ + epoch: epoch, + cid: cid, + from: key, + } + + it := storage.Find(ctx, hdr.ID(), storage.KeysOnly) + + return list(it) +} + +func list(it iterator.Iterator) [][]byte { + var result [][]byte + + ignore := [][]byte{ + []byte(netmapContractKey), + } + +loop: + for iterator.Next(it) { + key := iterator.Value(it).([]byte) // iterator MUST BE `storage.KeysOnly` + for _, ignoreKey := range ignore { + if common.BytesEqual(key, ignoreKey) { + continue loop + } + } + + result = append(result, key) + } + + return result +} + +// Version returns the version of the contract. +func Version() int { + return common.Version +} + +// readNext reads the length from the first byte, and then reads data (max 127 bytes). +func readNext(input []byte) ([]byte, int) { + var buf interface{} = input[0] + ln := buf.(int) + + return input[1 : 1+ln], 1 + ln +} + +func newAuditHeader(input []byte) auditHeader { + // V2 format + offset := int(input[1]) + offset = 2 + offset + 1 // version prefix + version len + epoch prefix + + var buf interface{} = input[offset : offset+8] // [ 8 integer bytes ] + epoch := buf.(int) + + offset = offset + 8 + + // cid is a nested structure with raw bytes + // [ cid struct prefix (wireType + len = 2 bytes), cid value wireType (1 byte), ... ] + cid, cidOffset := readNext(input[offset+2+1:]) + + // key is a raw byte + // [ public key wireType (1 byte), ... ] + key, _ := readNext(input[offset+2+1+cidOffset+1:]) + + return auditHeader{ + epoch, + cid, + key, + } +} diff --git a/audit/config.yml b/audit/config.yml new file mode 100644 index 0000000..5033360 --- /dev/null +++ b/audit/config.yml @@ -0,0 +1,4 @@ +name: "Audit" +safemethods: ["get", "list", "listByEpoch", "listByCID", "listByNode", "version"] +permissions: + - methods: ["update"] diff --git a/audit/doc.go b/audit/doc.go new file mode 100644 index 0000000..97acfee --- /dev/null +++ b/audit/doc.go @@ -0,0 +1,22 @@ +/* +Audit contract is a contract deployed in FrostFS sidechain. + +Inner Ring nodes perform audit of the registered containers during every epoch. +If a container contains StorageGroup objects, an Inner Ring node initializes +a series of audit checks. Based on the results of these checks, the Inner Ring +node creates a DataAuditResult structure for the container. The content of this +structure makes it possible to determine which storage nodes have been examined and +see the status of these checks. Regarding this information, the container owner is +charged for data storage. + +Audit contract is used as a reliable and verifiable storage for all +DataAuditResult structures. At the end of data audit routine, Inner Ring +nodes send a stable marshaled version of the DataAuditResult structure to the +contract. When Alphabet nodes of the Inner Ring perform settlement operations, +they make a list and get these AuditResultStructures from the audit contract. + +# Contract notifications + +Audit contract does not produce notifications to process. +*/ +package audit diff --git a/balance/balance_contract.go b/balance/balance_contract.go index 803c819..3859c6e 100644 --- a/balance/balance_contract.go +++ b/balance/balance_contract.go @@ -3,6 +3,7 @@ package balance import ( "git.frostfs.info/TrueCloudLab/frostfs-contract/common" "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/management" "github.com/nspcc-dev/neo-go/pkg/interop/native/std" @@ -31,13 +32,6 @@ type ( // account wasn't burnt. Parent []byte } - - // account is a stored view of Account with fixed int size - account struct { - Balance []byte - Until []byte - Parent []byte - } ) const ( @@ -47,6 +41,7 @@ const ( netmapContractKey = "netmapScriptHash" containerContractKey = "containerScriptHash" + notaryDisabledKey = "notary" ) var token Token @@ -63,18 +58,22 @@ func init() { token = createToken() } -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } args := data.(struct { - addrNetmap interop.Hash160 - addrContainer interop.Hash160 + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrNetmap interop.Hash160 + addrContainer interop.Hash160 }) if len(args.addrNetmap) != interop.Hash160Len || len(args.addrContainer) != interop.Hash160Len { @@ -89,12 +88,13 @@ func _deploy(data any, isUpdate bool) { // Update method updates contract source code and manifest. It can be invoked // only by committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { if !common.HasUpdateAccess() { panic("only committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("balance contract updated") } @@ -128,7 +128,7 @@ func BalanceOf(account interop.Hash160) int { // // It produces Transfer and TransferX notifications. TransferX notification // will have empty details field. -func Transfer(from, to interop.Hash160, amount int, data any) bool { +func Transfer(from, to interop.Hash160, amount int, data interface{}) bool { ctx := storage.GetContext() return token.transfer(ctx, from, to, amount, false, nil) } @@ -175,7 +175,7 @@ func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) { Parent: from, } - setAccount(ctx, to, lockAccount) + common.SetSerialized(ctx, to, lockAccount) result := token.transfer(ctx, from, to, amount, true, details) if !result { @@ -312,14 +312,14 @@ func (t Token) transfer(ctx storage.Context, from, to interop.Hash160, amount in storage.Delete(ctx, from) } else { amountFrom.Balance = amountFrom.Balance - amount // neo-go#953 - setAccount(ctx, from, amountFrom) + common.SetSerialized(ctx, from, amountFrom) } } if len(to) == 20 { amountTo := getAccount(ctx, to) amountTo.Balance = amountTo.Balance + amount // neo-go#953 - setAccount(ctx, to, amountTo) + common.SetSerialized(ctx, to, amountTo) } runtime.Notify("Transfer", from, to, amount) @@ -330,7 +330,9 @@ func (t Token) transfer(ctx storage.Context, from, to interop.Hash160, amount in // canTransfer returns the amount it can transfer. func (t Token) canTransfer(ctx storage.Context, from, to interop.Hash160, amount int, innerRing bool) (Account, bool) { - emptyAcc := Account{} + var ( + emptyAcc = Account{} + ) if !innerRing { if len(to) != interop.Hash160Len || !isUsableAddress(from) { @@ -368,24 +370,11 @@ func isUsableAddress(addr interop.Hash160) bool { return false } -func getAccount(ctx storage.Context, key any) Account { +func getAccount(ctx storage.Context, key interface{}) Account { data := storage.Get(ctx, key) if data != nil { - acc := std.Deserialize(data.([]byte)).(account) - return Account{ - Balance: common.FromFixedWidth64(acc.Balance), - Until: common.FromFixedWidth64(acc.Until), - Parent: acc.Parent, - } + return std.Deserialize(data.([]byte)).(Account) } return Account{} } - -func setAccount(ctx storage.Context, key any, acc Account) { - common.SetSerialized(ctx, key, account{ - Balance: common.ToFixedWidth64(acc.Balance), - Until: common.ToFixedWidth64(acc.Until), - Parent: acc.Parent, - }) -} diff --git a/balance/config.yml b/balance/config.yml index ba2a7a6..35fad6d 100644 --- a/balance/config.yml +++ b/balance/config.yml @@ -1,11 +1,6 @@ name: "Balance" supportedstandards: ["NEP-17"] -safemethods: - - "balanceOf" - - "decimals" - - "symbol" - - "totalSupply" - - "version" +safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "version"] permissions: - methods: ["update"] events: diff --git a/balance/doc.go b/balance/doc.go index 437d546..3879048 100644 --- a/balance/doc.go +++ b/balance/doc.go @@ -74,13 +74,5 @@ when FrostFS contract has transferred GAS assets back to the user. type: Hash160 - name: amount type: Integer - -# Contract storage scheme - - | Key | Value | Description | - |-----------------------|------------|----------------------------------| - | `netmapScriptHash` | Hash160 | netmap contract hash | - | `containerScriptHash` | Hash160 | container contract hash | - | circulationKey | int | the token circulation key value | */ package balance diff --git a/common/address.go b/common/address.go deleted file mode 100644 index a5a713a..0000000 --- a/common/address.go +++ /dev/null @@ -1,10 +0,0 @@ -package common - -import "github.com/nspcc-dev/neo-go/pkg/interop" - -const ( - NEO3PrefixLen = 1 - ChecksumLen = 4 - - AddressLen = NEO3PrefixLen + interop.Hash160Len + ChecksumLen -) diff --git a/common/common.go b/common/common.go index a52f749..a8cf9c2 100644 --- a/common/common.go +++ b/common/common.go @@ -1,11 +1,26 @@ package common import ( + "github.com/nspcc-dev/neo-go/pkg/interop/storage" "github.com/nspcc-dev/neo-go/pkg/interop/util" ) +const ( + panicMsgForNotaryDisabledEnv = "contract not applicable for notary-disabled environment" +) + // BytesEqual compares two slices of bytes by wrapping them into strings, // which is necessary with new util.Equals interop behaviour, see neo-go#1176. func BytesEqual(a []byte, b []byte) bool { return util.Equals(string(a), string(b)) } + +// RmAndCheckNotaryDisabledKey remove notary disabled key from storage and +// panic in notary disabled environment +func RmAndCheckNotaryDisabledKey(data interface{}, key interface{}) { + //TODO(@acid-ant): #9 remove notaryDisabled from args in future version + storage.Delete(storage.GetContext(), key) + if data.([]interface{})[0].(bool) { + panic(panicMsgForNotaryDisabledEnv) + } +} diff --git a/common/ir.go b/common/ir.go index a639bf1..fbc813a 100644 --- a/common/ir.go +++ b/common/ir.go @@ -25,20 +25,20 @@ func AlphabetNodes() []interop.PublicKey { } // AlphabetAddress returns multi address of alphabet public keys. -func AlphabetAddress() interop.Hash160 { +func AlphabetAddress() []byte { alphabet := neo.GetCommittee() return Multiaddress(alphabet, false) } // CommitteeAddress returns multi address of committee. -func CommitteeAddress() interop.Hash160 { +func CommitteeAddress() []byte { committee := neo.GetCommittee() return Multiaddress(committee, true) } // Multiaddress returns default multisignature account address for N keys. // If committee set to true, it is `M = N/2+1` committee account. -func Multiaddress(n []interop.PublicKey, committee bool) interop.Hash160 { +func Multiaddress(n []interop.PublicKey, committee bool) []byte { threshold := len(n)*2/3 + 1 if committee { threshold = len(n)/2 + 1 diff --git a/common/storage.go b/common/storage.go index 8a184f3..3b9e494 100644 --- a/common/storage.go +++ b/common/storage.go @@ -1,28 +1,12 @@ package common import ( - "github.com/nspcc-dev/neo-go/pkg/interop/convert" "github.com/nspcc-dev/neo-go/pkg/interop/native/std" "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) // SetSerialized serializes data and puts it into contract storage. -func SetSerialized(ctx storage.Context, key any, value interface{}) { +func SetSerialized(ctx storage.Context, key interface{}, value interface{}) { data := std.Serialize(value) storage.Put(ctx, key, data) } - -// ToFixedWidth64 converts x to bytes such that numbers <= math.MaxUint64 -// have constant with of 9. -func ToFixedWidth64(x int) []byte { - data := convert.ToBytes(x) - if x < 0 || len(data) >= 9 { - return data - } - return append(data, make([]byte, 9-len(data))...) -} - -// FromFixedWidth64 is a reverse function for ToFixedWidth64. -func FromFixedWidth64(x []byte) int { - return convert.ToInteger(x) -} diff --git a/common/transfer.go b/common/transfer.go index 14a0129..b3eebdc 100644 --- a/common/transfer.go +++ b/common/transfer.go @@ -31,7 +31,7 @@ func LockTransferDetails(txDetails []byte) []byte { } func UnlockTransferDetails(epoch int) []byte { - var buf any = epoch + var buf interface{} = epoch return append(unlockPrefix, buf.([]byte)...) } diff --git a/common/version.go b/common/version.go index b72ea06..09dd6c9 100644 --- a/common/version.go +++ b/common/version.go @@ -4,15 +4,15 @@ import "github.com/nspcc-dev/neo-go/pkg/interop/native/std" const ( major = 0 - minor = 21 - patch = 4 + minor = 18 + patch = 0 // Versions from which an update should be performed. // These should be used in a group (so prevMinor can be equal to minor if there are // any migration routines. prevMajor = 0 - prevMinor = 19 - prevPatch = 4 + prevMinor = 16 + prevPatch = 0 Version = major*1_000_000 + minor*1_000 + patch @@ -32,20 +32,15 @@ func CheckVersion(from int) { if from < PrevVersion { panic(ErrVersionMismatch + ": expected >=" + std.Itoa(PrevVersion, 10)) } - if Version <= from { + if from == Version { panic(ErrAlreadyUpdated + ": " + std.Itoa(Version, 10)) } } // AppendVersion appends current contract version to the list of deploy arguments. -func AppendVersion(data any) []interface{} { +func AppendVersion(data interface{}) []interface{} { if data == nil { - return []any{Version} + return []interface{}{Version} } - return append(data.([]any), Version) -} - -// GetVersion returns version as int by major, minor, patch. -func GetVersion(major, minor, patch int) int { - return major*1_000_000 + minor*1_000 + patch + return append(data.([]interface{}), Version) } diff --git a/commonclient/invoker.go b/commonclient/invoker.go deleted file mode 100644 index 5b3d392..0000000 --- a/commonclient/invoker.go +++ /dev/null @@ -1,21 +0,0 @@ -package commonclient - -import ( - "github.com/google/uuid" - "github.com/nspcc-dev/neo-go/pkg/neorpc/result" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" -) - -// Invoker is a subset of methods provided by struct invoker.Invoker. The subset contains only those -// methods that are used by ActorWrapper and clients of the contracts. -type Invoker interface { - Run([]byte) (*result.Invoke, error) - Call(contract util.Uint160, method string, params ...any) (*result.Invoke, error) - TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error) - TerminateSession(sessionID uuid.UUID) error -} - -// Ensure the interface is compatible with the invoker.Invoker struct. -var _ Invoker = (*invoker.Invoker)(nil) diff --git a/commonclient/iterator.go b/commonclient/iterator.go deleted file mode 100644 index a46eab8..0000000 --- a/commonclient/iterator.go +++ /dev/null @@ -1,49 +0,0 @@ -package commonclient - -import ( - "fmt" - - "github.com/google/uuid" - "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" -) - -// ReadIteratorItems calls method that returns iterator and traverses the iterator until all items are read into array. -func ReadIteratorItems(inv Invoker, batchSize int, contract util.Uint160, method string, params ...any) ([]stackitem.Item, error) { - if batchSize <= 0 { - panic("batch size must be positive") - } - - script, err := smartcontract.CreateCallAndPrefetchIteratorScript(contract, method, batchSize, params...) - if err != nil { - return nil, fmt.Errorf("couldn't create unwrap script: %w", err) - } - - arr, sessionID, iter, err := unwrap.ArrayAndSessionIterator(inv.Run(script)) - if err != nil { - return nil, fmt.Errorf("unwrap session iterator: %w", err) - } - if (sessionID == uuid.UUID{}) { - return arr, nil - } - - defer func() { - _ = inv.TerminateSession(sessionID) - }() - - var shouldStop bool - res := arr - for !shouldStop { - items, err := inv.TraverseIterator(sessionID, &iter, batchSize) - if err != nil { - return nil, err - } - - res = append(res, items...) - shouldStop = len(items) < batchSize - } - - return res, nil -} diff --git a/commonclient/transaction.go b/commonclient/transaction.go deleted file mode 100644 index 15a33aa..0000000 --- a/commonclient/transaction.go +++ /dev/null @@ -1,63 +0,0 @@ -package commonclient - -import ( - "errors" - - "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/emit" -) - -// Transaction allows to invoke several contract method at once. -type Transaction struct { - writer *io.BufBinWriter - buffer *io.BufBinWriter - contract util.Uint160 -} - -var ErrTransactionTooLarge = errors.New("transaction/script size limit exceeded") - -// NewTransaction creates new transaction to accumulate contract invocations. -func NewTransaction(contractHash util.Uint160) *Transaction { - return &Transaction{ - writer: io.NewBufBinWriter(), - buffer: io.NewBufBinWriter(), - contract: contractHash, - } -} - -// WrapCall accept methods and arguments to invoke. -// Should be used with method on clients like Client.MethodNameCall. -func (t Transaction) WrapCall(method string, args []any) error { - t.buffer.Reset() - emit.AppCall(t.buffer.BinWriter, t.contract, method, callflag.All, args...) - - if t.writer.Len()+t.buffer.Len() > transaction.MaxScriptLength { - return ErrTransactionTooLarge - } - - t.writer.WriteBytes(t.buffer.Bytes()) - - return t.writer.Err -} - -// WrapCallErr accept methods, arguments and error to handle and invoke. -// Should be used with method on clients like *CallErr. -func (t Transaction) WrapCallErr(method string, args []any, err error) error { - if err != nil { - return err - } - - return t.WrapCall(method, args) -} - -// Bytes returns the resulting buffer and makes future writes return an error. -func (t Transaction) Bytes() ([]byte, error) { - if t.writer.Len() > transaction.MaxScriptLength { - return nil, ErrTransactionTooLarge - } - - return t.writer.Bytes(), nil -} diff --git a/commonclient/waiter.go b/commonclient/waiter.go deleted file mode 100644 index 2a86043..0000000 --- a/commonclient/waiter.go +++ /dev/null @@ -1,103 +0,0 @@ -package commonclient - -import ( - "context" - "fmt" - "strings" - - "github.com/nspcc-dev/neo-go/pkg/core/state" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" -) - -const alreadyExistsError = "already exists" - -// ContextWaiter is an interface that supports transaction awaiting with a context limit. -type ContextWaiter interface { - waiter.Waiter - WaitCtx(ctx context.Context, h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) -} - -type WaiterOptions struct { - // IgnoreAlreadyExistsError controls behavior for "already exists" error: - // - If set to true, it indicates that "already exists" error is not a problem, we should - // wait for transaction as usual (this is the behavior of neo-go [waiter.PollingBased]). - // - If set to false, it indicates that "already exists" should be reported as an error. - IgnoreAlreadyExistsError bool - - // VerifyExecResults controls whether waiter should ensure that transaction successfully - // enters blockchain block. - VerifyExecResults bool -} - -// Waiter is a decorator on top of the standard [waiter.Waiter]. -// It provides additional behavior (controlled by [WaiterOptions]) on top of the standard -// functionality of awaiting transactions. -type Waiter struct { - waiter waiter.Waiter - options WaiterOptions -} - -var _ waiter.Waiter = (*Waiter)(nil) - -// NewWaiter decorates the specified waiter in a new [Waiter] instance. -func NewWaiter(waiter waiter.Waiter, options WaiterOptions) *Waiter { - return &Waiter{ - waiter: waiter, - options: options, - } -} - -// Wait allows to wait until transaction will be accepted to the chain. -func (w *Waiter) Wait(h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) { - if !w.options.IgnoreAlreadyExistsError && errIsAlreadyExists(err) { - return nil, err - } - result, err := w.waiter.Wait(h, vub, err) - return w.examineExecResult(result, err) -} - -// WaitCtx allows to wait until transaction is accepted to the chain. -// Waiting is limited by the specified context. -func (w *Waiter) WaitCtx(ctx context.Context, h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) { - if err != nil { - shouldIgnore := errIsAlreadyExists(err) && w.options.IgnoreAlreadyExistsError - if !shouldIgnore { - return nil, err - } - } - result, err := w.waiter.WaitAny(ctx, vub, h) - return w.examineExecResult(result, err) -} - -// WaitAny waits until at least one of the specified transactions will be accepted -// to the chain. -func (w *Waiter) WaitAny(ctx context.Context, vub uint32, hashes ...util.Uint256) (*state.AppExecResult, error) { - result, err := w.waiter.WaitAny(ctx, vub, hashes...) - return w.examineExecResult(result, err) -} - -func (w *Waiter) examineExecResult(result *state.AppExecResult, err error) (*state.AppExecResult, error) { - if !w.options.VerifyExecResults || err != nil { - return result, err - } - - if result.Execution.VMState != vmstate.Fault { - // Transaction didn't fail, so we just return result "as is" - return result, nil - } - - // Transaction failed, we extract VM exception from it and report as an error - if result.FaultException != "" { - return result, fmt.Errorf("%s", result.FaultException) - } - return result, fmt.Errorf("transaction failed, stack=%v", result.Stack) -} - -func errIsAlreadyExists(err error) bool { - if err == nil { - return false - } - return strings.Contains(strings.ToLower(err.Error()), alreadyExistsError) -} diff --git a/commonclient/waiter_test.go b/commonclient/waiter_test.go deleted file mode 100644 index a614900..0000000 --- a/commonclient/waiter_test.go +++ /dev/null @@ -1,209 +0,0 @@ -package commonclient - -import ( - "context" - "fmt" - "testing" - - "github.com/nspcc-dev/neo-go/pkg/core/state" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" -) - -type mockWaiter struct { - mock.Mock -} - -func (w *mockWaiter) successfulResult(txHash util.Uint256) *state.AppExecResult { - return &state.AppExecResult{ - Container: txHash, - Execution: state.Execution{ - Trigger: trigger.Application, - VMState: vmstate.Halt, - GasConsumed: 100500, - Stack: nil, - Events: nil, - FaultException: "", - }, - } -} - -func (w *mockWaiter) failedResult(txHash util.Uint256, exception string) *state.AppExecResult { - return &state.AppExecResult{ - Container: txHash, - Execution: state.Execution{ - Trigger: trigger.Application, - VMState: vmstate.Fault, - GasConsumed: 100500, - Stack: nil, - Events: nil, - FaultException: exception, - }, - } -} - -func (m *mockWaiter) Wait(h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) { - args := m.Called(h, vub, err) - result := args.Get(0) - if result == nil { - return nil, args.Error(1) - } - return result.(*state.AppExecResult), args.Error(1) -} - -func (m *mockWaiter) WaitAny(ctx context.Context, vub uint32, hashes ...util.Uint256) (*state.AppExecResult, error) { - args := m.Called(ctx, vub, hashes) - result := args.Get(0) - if result == nil { - return nil, args.Error(1) - } - return result.(*state.AppExecResult), args.Error(1) -} - -func TestWaiter(t *testing.T) { - txHash := util.Uint256{} - txHashes := []util.Uint256{txHash} - - vub := uint32(100) - - t.Run("wait ignores already exists error", func(t *testing.T) { - sendErr := fmt.Errorf("transaction already exists") - mw := &mockWaiter{} - mw.On("Wait", txHash, vub, mock.Anything).Return(mw.successfulResult(txHash), nil) - - waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: true}) - _, err := waiter.Wait(txHash, vub, sendErr) - - require.NoError(t, err) - }) - - t.Run("wait reports already exists error", func(t *testing.T) { - sendErr := fmt.Errorf("transaction already exists") - mw := &mockWaiter{} - mw.On("Wait", txHash, vub, mock.Anything).Return(mw.successfulResult(txHash), nil) - - waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: false}) - _, err := waiter.Wait(txHash, vub, sendErr) - - require.Error(t, err) - }) - - t.Run("wait reports wait error when transaction error is ignored", func(t *testing.T) { - waitErr := fmt.Errorf("mock error") - mw := &mockWaiter{} - mw.On("Wait", txHash, vub, nil).Return(nil, waitErr) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false}) - _, err := waiter.Wait(txHash, vub, nil) - - require.ErrorIs(t, err, waitErr) - }) - - t.Run("wait reports wait error when transaction error is verified", func(t *testing.T) { - waitErr := fmt.Errorf("mock error") - mw := &mockWaiter{} - mw.On("Wait", txHash, vub, nil).Return(nil, waitErr) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true}) - _, err := waiter.Wait(txHash, vub, nil) - - require.ErrorIs(t, err, waitErr) - }) - - t.Run("wait ignores error from transaction", func(t *testing.T) { - txError := "mock error" - mw := &mockWaiter{} - mw.On("Wait", txHash, vub, nil).Return(mw.failedResult(txHash, txError), nil) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false}) - _, err := waiter.Wait(txHash, vub, nil) - - require.NoError(t, err) - }) - - t.Run("wait examines error from transaction", func(t *testing.T) { - txError := "mock error" - mw := &mockWaiter{} - mw.On("Wait", txHash, vub, nil).Return(mw.failedResult(txHash, txError), nil) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true}) - _, err := waiter.Wait(txHash, vub, nil) - - require.ErrorContains(t, err, txError) - }) - - t.Run("waitctx ignores already exists error", func(t *testing.T) { - sendErr := fmt.Errorf("transaction already exists") - mw := &mockWaiter{} - mw.On("WaitAny", mock.Anything, vub, txHashes).Return(mw.successfulResult(txHash), nil) - - waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: true}) - _, err := waiter.WaitCtx(context.Background(), txHash, vub, sendErr) - - require.NoError(t, err) - mw.AssertNotCalled(t, "Wait", mock.Anything, mock.Anything, mock.Anything) - }) - - t.Run("waitctx reports already exists error", func(t *testing.T) { - sendErr := fmt.Errorf("transaction already exists") - mw := &mockWaiter{} - mw.On("WaitAny", mock.Anything, vub, txHashes).Return(mw.successfulResult(txHash), nil) - - waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: false}) - _, err := waiter.WaitCtx(context.Background(), txHash, vub, sendErr) - - require.Error(t, err) - mw.AssertNotCalled(t, "Wait", mock.Anything, mock.Anything, mock.Anything) - }) - - t.Run("waitctx reports wait error when transaction error is ignored", func(t *testing.T) { - waitErr := fmt.Errorf("mock error") - mw := &mockWaiter{} - mw.On("WaitAny", mock.Anything, vub, txHashes).Return(nil, waitErr) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false}) - _, err := waiter.WaitCtx(context.Background(), txHash, vub, nil) - - require.ErrorIs(t, err, waitErr) - mw.AssertNotCalled(t, "Wait", mock.Anything, mock.Anything, mock.Anything) - }) - - t.Run("waitctx reports wait error when transaction error is verified", func(t *testing.T) { - waitErr := fmt.Errorf("mock error") - mw := &mockWaiter{} - mw.On("WaitAny", mock.Anything, vub, txHashes).Return(nil, waitErr) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true}) - _, err := waiter.WaitCtx(context.Background(), txHash, vub, nil) - - require.ErrorIs(t, err, waitErr) - mw.AssertNotCalled(t, "Wait", mock.Anything, mock.Anything, mock.Anything) - }) - - t.Run("waitctx ignores error from transaction", func(t *testing.T) { - txError := "mock error" - mw := &mockWaiter{} - mw.On("WaitAny", mock.Anything, vub, txHashes).Return(mw.failedResult(txHash, txError), nil) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false}) - _, err := waiter.WaitCtx(context.Background(), txHash, vub, nil) - - require.NoError(t, err) - mw.AssertNotCalled(t, "Wait", mock.Anything, mock.Anything, mock.Anything) - }) - - t.Run("waitctx examines error from transaction", func(t *testing.T) { - txError := "mock error" - mw := &mockWaiter{} - mw.On("WaitAny", mock.Anything, vub, txHashes).Return(mw.failedResult(txHash, txError), nil) - - waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true}) - _, err := waiter.WaitCtx(context.Background(), txHash, vub, nil) - - require.ErrorContains(t, err, txError) - mw.AssertNotCalled(t, "Wait", mock.Anything, mock.Anything, mock.Anything) - }) -} diff --git a/container/config.yml b/container/config.yml index df98605..2bf9d97 100644 --- a/container/config.yml +++ b/container/config.yml @@ -1,36 +1,47 @@ name: "Container" -safemethods: - - "count" - - "containersOf" - - "deletionInfo" - - "eACL" - - "get" - - "getContainerSize" - - "iterateContainerSizes" - - "list" - - "listContainerSizes" - - "owner" - - "version" +safemethods: ["count", "containersOf", "get", "owner", "list", "eACL", "getContainerSize", "listContainerSizes", "iterateContainerSizes", "version"] permissions: - - methods: - - "addRecord" - - "deleteRecords" - - "register" - - "transferX" - - "update" - - "setAdmin" - + - methods: ["update", "addKey", "transferX", + "register", "addRecord", "deleteRecords"] events: + - name: containerPut + parameters: + - name: container + type: ByteArray + - name: signature + type: Signature + - name: publicKey + type: PublicKey + - name: token + type: ByteArray - name: PutSuccess parameters: - name: containerID type: Hash256 - name: publicKey type: PublicKey + - name: containerDelete + parameters: + - name: containerID + type: ByteArray + - name: signature + type: Signature + - name: token + type: ByteArray - name: DeleteSuccess parameters: - name: containerID - type: Hash256 + type: ByteArray + - name: setEACL + parameters: + - name: eACL + type: ByteArray + - name: signature + type: Signature + - name: publicKey + type: PublicKey + - name: token + type: ByteArray - name: SetEACLSuccess parameters: - name: containerID diff --git a/container/container_contract.go b/container/container_contract.go index a4f0ebf..9a600d1 100644 --- a/container/container_contract.go +++ b/container/container_contract.go @@ -50,6 +50,7 @@ const ( nnsContractKey = "nnsScriptHash" nnsRootKey = "nnsRoot" nnsHasAliasKey = "nnsHasAlias" + notaryDisabledKey = "notary" // RegistrationFeeKey is a key in netmap config which contains fee for container registration. RegistrationFeeKey = "ContainerFee" @@ -63,7 +64,6 @@ const ( estimateKeyPrefix = "cnr" containerKeyPrefix = 'x' ownerKeyPrefix = 'o' - graveKeyPrefix = 'g' estimatePostfixSize = 10 // CleanupDelta contains the number of the last epochs for which container estimations are present. CleanupDelta = 3 @@ -82,27 +82,53 @@ const ( defaultTTL = 3600 // 1 hour ) -var eACLPrefix = []byte("eACL") +var ( + eACLPrefix = []byte("eACL") +) // OnNEP11Payment is needed for registration with contract as the owner to work. -func OnNEP11Payment(a interop.Hash160, b int, c []byte, d any) { +func OnNEP11Payment(a interop.Hash160, b int, c []byte, d interface{}) { } -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) + + it := storage.Find(ctx, []byte{}, storage.None) + for iterator.Next(it) { + item := iterator.Value(it).(struct { + key []byte + value []byte + }) + + // Migrate container. + if len(item.key) == containerIDSize { + storage.Delete(ctx, item.key) + storage.Put(ctx, append([]byte{containerKeyPrefix}, item.key...), item.value) + } + + // Migrate owner-cid map. + if len(item.key) == 25 /* owner id size */ +containerIDSize { + storage.Delete(ctx, item.key) + storage.Put(ctx, append([]byte{ownerKeyPrefix}, item.key...), item.value) + } + } return } args := data.(struct { - addrNetmap interop.Hash160 - addrBalance interop.Hash160 - addrID interop.Hash160 - addrNNS interop.Hash160 - nnsRoot string + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrNetmap interop.Hash160 + addrBalance interop.Hash160 + addrID interop.Hash160 + addrNNS interop.Hash160 + nnsRoot string }) if len(args.addrNetmap) != interop.Hash160Len || @@ -131,7 +157,7 @@ func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) { } res := contract.Call(addrNNS, "register", contract.All, - nnsRoot, runtime.GetExecutingScriptHash(), "ops@frostfs.info", + nnsRoot, runtime.GetExecutingScriptHash(), "ops@nspcc.ru", defaultRefresh, defaultRetry, defaultExpire, defaultTTL).(bool) if !res { panic("can't register NNS TLD") @@ -140,17 +166,18 @@ func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) { // Update method updates contract source code and manifest. It can be invoked // by committee only. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { if !common.HasUpdateAccess() { panic("only committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("container contract updated") } // Put method creates a new container if it has been invoked by Alphabet nodes -// of the Inner Ring. +// of the Inner Ring. Otherwise, it produces containerPut notification. // // Container should be a stable marshaled Container structure from API. // Signature is a RFC6979 signature of the Container. @@ -165,12 +192,12 @@ func Put(container []byte, signature interop.Signature, publicKey interop.Public // Note that zone must exist. func PutNamed(container []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte, - name, zone string, -) { + name, zone string) { ctx := storage.GetContext() ownerID := ownerFromBinaryContainer(container) containerID := crypto.Sha256(container) + frostfsIDContractAddr := storage.Get(ctx, frostfsIDContractKey).(interop.Hash160) cnr := Container{ value: container, sig: signature, @@ -230,7 +257,7 @@ func PutNamed(container []byte, signature interop.Signature, if name != "" { if needRegister { res := contract.Call(nnsContractAddr, "register", contract.All, - domain, runtime.GetExecutingScriptHash(), "ops@frostfs.info", + domain, runtime.GetExecutingScriptHash(), "ops@nspcc.ru", defaultRefresh, defaultRetry, defaultExpire, defaultTTL).(bool) if !res { panic("can't register the domain " + domain) @@ -243,6 +270,10 @@ func PutNamed(container []byte, signature interop.Signature, storage.Put(ctx, key, domain) } + if len(token) == 0 { // if container created directly without session + contract.Call(frostfsIDContractAddr, "addKey", contract.All, ownerID, [][]byte{publicKey}) + } + runtime.Log("added new container") runtime.Notify("PutSuccess", containerID, publicKey) } @@ -272,14 +303,15 @@ func checkNiceNameAvailable(nnsContractAddr interop.Hash160, domain string) bool } // Delete method removes a container from the contract storage if it has been -// invoked by Alphabet nodes of the Inner Ring. +// invoked by Alphabet nodes of the Inner Ring. Otherwise, it produces +// containerDelete notification. // // Signature is a RFC6979 signature of the container ID. // Token is optional and should be a stable marshaled SessionToken structure from // API. // // If the container doesn't exist, it panics with NotFoundError. -func Delete(containerID interop.Hash256, signature interop.Signature, publicKey interop.PublicKey, token []byte) { +func Delete(containerID []byte, signature interop.Signature, token []byte) { ctx := storage.GetContext() ownerID := getOwnerByID(ctx, containerID) @@ -298,7 +330,7 @@ func Delete(containerID interop.Hash256, signature interop.Signature, publicKey // and inability to delete a container. We should also check if we own the record in case. nnsContractAddr := storage.Get(ctx, nnsContractKey).(interop.Hash160) res := contract.Call(nnsContractAddr, "getRecords", contract.ReadStates|contract.AllowCall, domain, 16 /* TXT */) - if res != nil && std.Base58Encode(containerID) == string(res.([]any)[0].(string)) { + if res != nil && std.Base58Encode(containerID) == string(res.([]interface{})[0].(string)) { contract.Call(nnsContractAddr, "deleteRecords", contract.All, domain, 16 /* TXT */) } } @@ -307,35 +339,6 @@ func Delete(containerID interop.Hash256, signature interop.Signature, publicKey runtime.Notify("DeleteSuccess", containerID) } -type DelInfo struct { - Owner []byte - Epoch int -} - -type delInfo struct { - Owner []byte - Epoch []byte -} - -// DeletionInfo method returns container deletion info. -// If the container had never existed, NotFoundError is throwed. -// It can be used to check whether non-existing container was indeed deleted -// or does not yet exist at some height. -func DeletionInfo(containerID []byte) DelInfo { - ctx := storage.GetReadOnlyContext() - graveKey := append([]byte{graveKeyPrefix}, containerID...) - data := storage.Get(ctx, graveKey).([]byte) - if data == nil { - panic(NotFoundError) - } - - d := std.Deserialize(data).(delInfo) - return DelInfo{ - Owner: d.Owner, - Epoch: common.FromFixedWidth64(d.Epoch), - } -} - // Get method returns a structure that contains a stable marshaled Container structure, // the signature, the public key of the container creator and a stable marshaled SessionToken // structure if it was provided. @@ -404,7 +407,8 @@ func List(owner []byte) [][]byte { } // SetEACL method sets a new extended ACL table related to the contract -// if it was invoked by Alphabet nodes of the Inner Ring. +// if it was invoked by Alphabet nodes of the Inner Ring. Otherwise, it produces +// setEACL notification. // // EACL should be a stable marshaled EACLTable structure from API. // Signature is a RFC6979 signature of the Container. @@ -515,7 +519,7 @@ func GetContainerSize(id []byte) containerSizes { func ListContainerSizes(epoch int) [][]byte { ctx := storage.GetReadOnlyContext() - var buf any = epoch + var buf interface{} = epoch key := []byte(estimateKeyPrefix) key = append(key, buf.([]byte)...) @@ -547,7 +551,7 @@ func ListContainerSizes(epoch int) [][]byte { func IterateContainerSizes(epoch int) iterator.Iterator { ctx := storage.GetReadOnlyContext() - var buf any = epoch + var buf interface{} = epoch key := []byte(estimateKeyPrefix) key = append(key, buf.([]byte)...) @@ -565,21 +569,6 @@ func NewEpoch(epochNum int) { cleanupContainers(ctx, epochNum) } -// SetAdmin sets admin for root container domain. -func SetAdmin(admin interop.Hash160) { - ctx := storage.GetReadOnlyContext() - - if !runtime.CheckWitness(common.CommitteeAddress()) { - panic("only committee can set admin") - } - - addrNNS := storage.Get(ctx, nnsContractKey).(interop.Hash160) - rootContainerDomain := storage.Get(ctx, nnsRootKey).(string) - - contract.Call(addrNNS, "setAdmin", contract.All, - rootContainerDomain, admin) -} - // StartContainerEstimation method produces StartEstimation notification. // It can be invoked only by Alphabet nodes of the Inner Ring. func StartContainerEstimation(epoch int) { @@ -610,9 +599,6 @@ func addContainer(ctx storage.Context, id, owner []byte, container Container) { idKey := append([]byte{containerKeyPrefix}, id...) common.SetSerialized(ctx, idKey, container) - - graveKey := append([]byte{graveKeyPrefix}, id...) - storage.Delete(ctx, graveKey) } func removeContainer(ctx storage.Context, id []byte, owner []byte) { @@ -621,14 +607,6 @@ func removeContainer(ctx storage.Context, id []byte, owner []byte) { storage.Delete(ctx, containerListKey) storage.Delete(ctx, append([]byte{containerKeyPrefix}, id...)) - - graveKey := append([]byte{graveKeyPrefix}, id...) - netmapContractAddr := storage.Get(ctx, netmapContractKey).(interop.Hash160) - epoch := contract.Call(netmapContractAddr, "epoch", contract.ReadOnly).(int) - common.SetSerialized(ctx, graveKey, delInfo{ - Owner: owner, - Epoch: common.ToFixedWidth64(epoch), - }) } func getAllContainers(ctx storage.Context) [][]byte { @@ -680,7 +658,7 @@ func ownerFromBinaryContainer(container []byte) []byte { } func estimationKey(epoch int, cid []byte, key interop.PublicKey) []byte { - var buf any = epoch + var buf interface{} = epoch hash := crypto.Ripemd160(key) @@ -758,7 +736,7 @@ func cleanupContainers(ctx storage.Context, epoch int) { // V2 format nbytes := k[len(estimateKeyPrefix) : len(k)-containerIDSize-estimatePostfixSize] - var n any = nbytes + var n interface{} = nbytes if epoch-n.(int) > TotalCleanupDelta { storage.Delete(ctx, k) diff --git a/container/doc.go b/container/doc.go index 20dcb6e..0636b0f 100644 --- a/container/doc.go +++ b/container/doc.go @@ -9,6 +9,47 @@ the same arguments. # Contract notifications +containerPut notification. This notification is produced when a user wants to +create a new container. Alphabet nodes of the Inner Ring catch the notification and +validate container data, signature and token if present. + + containerPut: + - name: container + type: ByteArray + - name: signature + type: Signature + - name: publicKey + type: PublicKey + - name: token + type: ByteArray + +containerDelete notification. This notification is produced when a container owner +wants to delete a container. Alphabet nodes of the Inner Ring catch the notification +and validate container ownership, signature and token if present. + + containerDelete: + - name: containerID + type: ByteArray + - name: signature + type: Signature + - name: token + type: ByteArray + +setEACL notification. This notification is produced when a container owner wants +to update an extended ACL of a container. Alphabet nodes of the Inner Ring catch +the notification and validate container ownership, signature and token if +present. + + setEACL: + - name: eACL + type: ByteArray + - name: signature + type: Signature + - name: publicKey + type: PublicKey + - name: token + type: ByteArray + StartEstimation notification. This notification is produced when Storage nodes should exchange estimation values of container sizes among other Storage nodes. @@ -23,20 +64,5 @@ it in Container contract. StopEstimation: - name: epoch type: Integer - -# Contract storage scheme - - | Key | Value | Description | - |-----------------------------------------------------------------------------------------------------| - | `netmapScriptHash` | Hash160 | netmap contract hash | - | `balanceScriptHash` | Hash160 | balance contract hash | - | `identityScriptHash` | Hash160 | frostfsID contract hash | - | `nnsContractKey` | Hash160 | nns contract hash | - | `nnsRoot` | string | default value for domain zone | - | `cnr` + epoch + containerID + publicKeyHash[:10] | ByteArray | estimated container size | - | `est` + containerID + publicKeyHash | ByteArray | serialized epochs array | - | `o` + ownerID + containerID | ByteArray | container ID | - | `x` + containerID | ByteArray | serialized container struct | - | `nnsHasAlias` + containerID | string | domain name | */ package container diff --git a/docs/globally-unique-domain-zone.md b/docs/globally-unique-domain-zone.md deleted file mode 100644 index 25872cc..0000000 --- a/docs/globally-unique-domain-zone.md +++ /dev/null @@ -1,160 +0,0 @@ -# Globally unique domain zone - -**Make sure you understand the [basic concepts](../nns/README.md) of `NNS`.** - -`Globally Unique Domains Zone` (`GUDZ`) is an extension of `NNS` that ensures unique names across multiple domain zones. When this option is enabled, all newly created domains will automatically receive a corresponding alias in the designated global zone. Deleting a domain will also remove its alias from the global zone. - -It's important to note that this feature is not retroactive: domains created before this option is enabled will not receive a global alias. Likewise, if the option is later disabled, domains that already have a `GUDZ` alias will retain their records. To fully disable `GUDZ`, all domains must be recreated with the option turned off. - -To enable `GUDZ`, add a `cnametgt=$(global domain)` `TXT` record that specifies the global zone. - -**Example:** - -Domains: -- `poland` -- `sweden` -- `animals.org` - -It is necessary to associate the domain zones `.poland` and `.sweden` into the global zone `.animals`. - -![](img/GUDZ.png) - -Create domains: - -``` -frostfs-adm morph nns register --name="poland" --email="email@email.email" -frostfs-adm morph nns register --name="sweden" --email="email@email.email" -frostfs-adm morph nns register --name="org" --email="email@email.email" -frostfs-adm morph nns register --name="animals.org" --email="email@email.email" -``` - -Add the `cnametgt` records: - -``` -frostfs-adm morph nns add-record --name="poland" --data="cnametgt=animals.org" --type="txt" -frostfs-adm morph nns add-record --name="sweden" --data="cnametgt=animals.org" --type="txt" -``` - -Create a domain with mapping to the global zone: - -``` -frostfs-adm morph nns register --name="bober.poland" --email="email@email.email" -``` - -Add any `TXT` record - -``` -frostfs-adm morph nns add-record --name="bober.poland" --data="CID" --type="txt" -``` - -Verify that the created domain has alias in the global zone - -``` -frostfs-adm morph nns tokens -v - -balance.frostfs -animals.org -group.frostfs -container -org -container.frostfs -proxy.frostfs -policy.frostfs -alphabet0.frostfs -sweden -frostfsid.frostfs -bober.animals.org (CNAME: bober.poland) -netmap.frostfs -frostfs -poland -bober.poland -``` - -Create of a conflicting domain -``` -frostfs-adm morph nns register --name="bober.sweden" --email="email@email.email" - -unable to register domain: script failed (FAULT state) due to an error: at instruction 1263 (THROW): unhandled exception: "global domain is already taken: bober.animals.org. Domain: bober.poland -``` - -**Disable GUDZ** -Delete `cnametgt` records - -``` -frostfs-adm morph nns delete-records --type=txt --name=poland -``` -Create `hamster.poland` and `hamster.sweden` -``` -frostfs-adm morph nns register --name="hamster.poland" --email="email@email.email" -frostfs-adm morph nns register --name="hamster.sweden" --email="email@email.email" -``` -`hamster.poland` and `hamster.sweden` does not have alias -``` -frostfs-adm morph nns tokens -v -balance.frostfs -animals.org -group.frostfs -container -org -container.frostfs -proxy.frostfs -policy.frostfs -alphabet0.frostfs -sweden -frostfsid.frostfs -bober.animals.org (CNAME: bober.poland) -netmap.frostfs -frostfs -poland -bober.poland -hamster.poland -``` -Delete global alias of `bober.poland` - -``` - frostfs-adm morph nns delete-records --name="bober.poland" --type="txt" -``` - - -``` -frostfs-adm morph nns tokens -v -balance.frostfs -animals.org -group.frostfs -container -org -container.frostfs -proxy.frostfs -policy.frostfs -alphabet0.frostfs -sweden -frostfsid.frostfs -netmap.frostfs -frostfs -poland -bober.poland -hamster.poland -``` -Delete `bober.poland` -``` - frostfs-adm morph nns delete --name="bober.poland" -``` - -``` -frostfs-adm morph nns tokens -v -balance.frostfs -animals.org -group.frostfs -container -org -container.frostfs -proxy.frostfs -policy.frostfs -alphabet0.frostfs -sweden -frostfsid.frostfs -netmap.frostfs -frostfs -poland -hamster.poland -``` \ No newline at end of file diff --git a/docs/img/GUDZ.drawio b/docs/img/GUDZ.drawio deleted file mode 100644 index 13ddf92..0000000 --- a/docs/img/GUDZ.drawio +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/img/GUDZ.png b/docs/img/GUDZ.png deleted file mode 100644 index 6d1057d..0000000 Binary files a/docs/img/GUDZ.png and /dev/null differ diff --git a/frostfs/config.yml b/frostfs/config.yml index b7220bb..4718ca9 100644 --- a/frostfs/config.yml +++ b/frostfs/config.yml @@ -1,9 +1,5 @@ name: "FrostFS" -safemethods: - - "config" - - "innerRingCandidates" - - "listConfig" - - "version" +safemethods: ["alphabetAddress", "innerRingCandidates", "config", "listConfig", "version"] permissions: - methods: ["update", "transfer"] events: @@ -47,6 +43,12 @@ events: type: ByteArray - name: keys type: Array + - name: AlphabetUpdate + parameters: + - name: id + type: ByteArray + - name: alphabet + type: Array - name: SetConfig parameters: - name: id diff --git a/frostfs/doc.go b/frostfs/doc.go index ec22bd8..8a312be 100644 --- a/frostfs/doc.go +++ b/frostfs/doc.go @@ -80,13 +80,5 @@ FrostFS network configuration value. type: ByteArray - name: value type: ByteArray - -# Contract storage scheme - - | Key | Value | Description | - |-----------------------------------------------------------------------------| - | `processingScriptHash` | Hash160 | processing contract hash | - | `candidates` + candidateKey | ByteArray | it flags inner ring candidate | - | `config` + postfix | ByteArray | serialized config data | */ package frostfs diff --git a/frostfs/frostfs_contract.go b/frostfs/frostfs_contract.go index f43e4bf..f902d30 100644 --- a/frostfs/frostfs_contract.go +++ b/frostfs/frostfs_contract.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" "github.com/nspcc-dev/neo-go/pkg/interop/native/roles" + "github.com/nspcc-dev/neo-go/pkg/interop/native/std" "github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) @@ -25,7 +26,9 @@ const ( CandidateFeeConfigKey = "InnerRingCandidateFee" withdrawFeeConfigKey = "WithdrawFee" - candidatesKey = "candidates" + alphabetKey = "alphabet" + candidatesKey = "candidates" + notaryDisabledKey = "notary" processingContractKey = "processingScriptHash" @@ -36,22 +39,28 @@ const ( ignoreDepositNotification = "\x57\x0b" ) -var configPrefix = []byte("config") +var ( + configPrefix = []byte("config") +) // _deploy sets up initial alphabet node keys. -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } args := data.(struct { - addrProc interop.Hash160 - keys []interop.PublicKey - config [][]byte + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrProc interop.Hash160 + keys []interop.PublicKey + config [][]byte }) if len(args.keys) == 0 { @@ -69,6 +78,9 @@ func _deploy(data any, isUpdate bool) { } } + // initialize all storage slices + common.SetSerialized(ctx, alphabetKey, args.keys) + storage.Put(ctx, processingContractKey, args.addrProc) ln := len(args.config) @@ -88,7 +100,7 @@ func _deploy(data any, isUpdate bool) { // Update method updates contract source code and manifest. It can be invoked // only by sidechain committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { blockHeight := ledger.CurrentIndex() alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1)) alphabetCommittee := common.Multiaddress(alphabetKeys, true) @@ -97,10 +109,18 @@ func Update(script []byte, manifest []byte, data any) { panic(common.ErrAlphabetWitnessFailed) } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("frostfs contract updated") } +// AlphabetAddress returns 2\3n+1 multisignature address of alphabet nodes. +// It is used in sidechain notary disabled environment. +func AlphabetAddress() interop.Hash160 { + ctx := storage.GetReadOnlyContext() + return multiaddress(getAlphabetNodes(ctx)) +} + // InnerRingCandidates returns an array of structures that contain an Inner Ring // candidate node key. func InnerRingCandidates() []common.IRNode { @@ -125,7 +145,8 @@ func InnerRingCandidateRemove(key interop.PublicKey) { keyOwner := runtime.CheckWitness(key) if !keyOwner { - if !runtime.CheckWitness(common.AlphabetAddress()) { + multiaddr := AlphabetAddress() + if !runtime.CheckWitness(multiaddr) { panic("this method must be invoked by candidate or alphabet") } } @@ -170,7 +191,7 @@ func InnerRingCandidateAdd(key interop.PublicKey) { // It takes no more than 9000.0 GAS. Native GAS has precision 8, and // FrostFS balance contract has precision 12. Values bigger than 9000.0 can // break JSON limits for integers when precision is converted. -func OnNEP17Payment(from interop.Hash160, amount int, data any) { +func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { rcv := data.(interop.Hash160) if common.BytesEqual(rcv, []byte(ignoreDepositNotification)) { return @@ -301,7 +322,7 @@ func Unbind(user []byte, keys []interop.PublicKey) { // Config returns configuration value of FrostFS configuration. If the key does // not exists, returns nil. -func Config(key []byte) any { +func Config(key []byte) interface{} { ctx := storage.GetReadOnlyContext() return getConfig(ctx, key) } @@ -345,8 +366,18 @@ func Version() int { return common.Version } +// getAlphabetNodes returns a deserialized slice of nodes from storage. +func getAlphabetNodes(ctx storage.Context) []interop.PublicKey { + data := storage.Get(ctx, alphabetKey) + if data != nil { + return std.Deserialize(data.([]byte)).([]interop.PublicKey) + } + + return []interop.PublicKey{} +} + // getConfig returns the installed frostfs configuration value or nil if it is not set. -func getConfig(ctx storage.Context, key any) interface{} { +func getConfig(ctx storage.Context, key interface{}) interface{} { postfix := key.([]byte) storageKey := append(configPrefix, postfix...) @@ -354,7 +385,7 @@ func getConfig(ctx storage.Context, key any) interface{} { } // setConfig sets a frostfs configuration value in the contract storage. -func setConfig(ctx storage.Context, key, val any) { +func setConfig(ctx storage.Context, key, val interface{}) { postfix := key.([]byte) storageKey := append(configPrefix, postfix...) diff --git a/frostfsid/client/client.go b/frostfsid/client/client.go deleted file mode 100644 index 8f95b00..0000000 --- a/frostfsid/client/client.go +++ /dev/null @@ -1,693 +0,0 @@ -package client - -import ( - "context" - "fmt" - - "git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient" - "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/crypto/keys" - "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/notary" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/emit" - "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/wallet" -) - -type ( - Client struct { - act *actor.Actor - waiter commonclient.ContextWaiter - contract util.Uint160 - } - - Options struct { - ProxyContract util.Uint160 - Waiter commonclient.WaiterOptions - } -) - -type ( - Subject struct { - PrimaryKey *keys.PublicKey - AdditionalKeys keys.PublicKeys - Namespace string - Name string - KV map[string]string - } - - SubjectExtended struct { - PrimaryKey *keys.PublicKey - AdditionalKeys keys.PublicKeys - Namespace string - Name string - KV map[string]string - Groups []*Group - } - - Namespace struct { - Name string - State NamespaceState - } - - NamespaceExtended struct { - Name string - State NamespaceState - GroupsCount int64 - SubjectsCount int64 - } - - Group struct { - ID int64 - Name string - Namespace string - KV map[string]string - } - - GroupExtended struct { - ID int64 - Name string - Namespace string - KV map[string]string - SubjectsCount int64 - } - - NamespaceState string -) - -const ( - IAMPathKey = "iam-path" - IAMARNKey = "iam-arn" - IAMCreatedTimeKey = "ctime" - IAMModifiedTimeKey = "mtime" -) - -const iteratorBatchSize = 100 - -const ( - getAdminMethod = "getAdmin" - setAdminMethod = "setAdmin" - clearAdminMethod = "clearAdmin" - - versionMethod = "version" - - createSubjectMethod = "createSubject" - getSubjectMethod = "getSubject" - getSubjectExtendedMethod = "getSubjectExtended" - getSubjectKVMethod = "getSubjectKV" - listSubjectsMethod = "listSubjects" - addSubjectKeyMethod = "addSubjectKey" - removeSubjectKeyMethod = "removeSubjectKey" - getSubjectByKeyMethod = "getSubjectByKey" - getSubjectByNameMethod = "getSubjectByName" - getSubjectKeyByNameMethod = "getSubjectKeyByName" - setSubjectKVMethod = "setSubjectKV" - setSubjectNameMethod = "setSubjectName" - deleteSubjectKVMethod = "deleteSubjectKV" - deleteSubjectMethod = "deleteSubject" - - createNamespaceMethod = "createNamespace" - updateNamespaceMethod = "updateNamespace" - deleteNamespaceMethod = "deleteNamespace" - getNamespaceMethod = "getNamespace" - getNamespaceExtendedMethod = "getNamespaceExtended" - listNamespacesMethod = "listNamespaces" - listNamespaceSubjectsMethod = "listNamespaceSubjects" - - createGroupMethod = "createGroup" - getGroupMethod = "getGroup" - getGroupExtendedMethod = "getGroupExtended" - getGroupIDByNameMethod = "getGroupIDByName" - getGroupByNameMethod = "getGroupByName" - setGroupNameMethod = "setGroupName" - setGroupKVMethod = "setGroupKV" - deleteGroupKVMethod = "deleteGroupKV" - listGroupsMethod = "listGroups" - addSubjectToGroupMethod = "addSubjectToGroup" - removeSubjectFromGroupMethod = "removeSubjectFromGroup" - listGroupSubjectsMethod = "listGroupSubjects" - deleteGroupMethod = "deleteGroup" -) - -const ( - Active NamespaceState = "active" - Frozen NamespaceState = "frozen" - Purge NamespaceState = "purge" -) - -// New creates a new Client. Options can be empty. -func New(ra actor.RPCActor, acc *wallet.Account, contract util.Uint160, opt Options) (*Client, error) { - signers := []actor.SignerAccount{{ - Signer: transaction.Signer{ - Account: acc.Contract.ScriptHash(), - Scopes: transaction.CalledByEntry, - }, - Account: acc, - }} - - if !opt.ProxyContract.Equals(util.Uint160{}) { - signers = append([]actor.SignerAccount{{ - Signer: transaction.Signer{ - Account: opt.ProxyContract, - Scopes: transaction.CustomContracts, - AllowedContracts: []util.Uint160{contract}, - }, - Account: notary.FakeContractAccount(opt.ProxyContract), - }}, signers...) - } - - act, err := actor.New(ra, signers) - if err != nil { - return nil, fmt.Errorf("init actor: %w", err) - } - wtr := commonclient.NewWaiter(act, opt.Waiter) - - return &Client{ - act: act, - waiter: wtr, - contract: contract, - }, nil -} - -// NewSimple creates a new Client using existing actor.Actor and default waiter options. -func NewSimple(act *actor.Actor, contract util.Uint160) *Client { - wtr := commonclient.NewWaiter(act, commonclient.WaiterOptions{}) - return &Client{ - act: act, - waiter: wtr, - contract: contract, - } -} - -// StartTx inits transaction. -func (c Client) StartTx() *commonclient.Transaction { - return commonclient.NewTransaction(c.contract) -} - -// SendTx sends provided transaction to blockchain. -func (c Client) SendTx(txn *commonclient.Transaction) (tx util.Uint256, vub uint32, err error) { - txBytes, err := txn.Bytes() - if err != nil { - return util.Uint256{}, 0, err - } - - return c.act.SendRun(txBytes) -} - -// Version returns version of contract. -func (c Client) Version() (int64, error) { - return unwrap.Int64(c.act.Call(c.contract, versionMethod)) -} - -// SetAdmin sets address that can perform write operations on contract. -// Must be invoked by committee. -func (c Client) SetAdmin(owner util.Uint160) (tx util.Uint256, vub uint32, err error) { - method, args := c.SetAdminCall(owner) - return c.act.SendCall(c.contract, method, args...) -} - -// SetAdminCall provides args for SetAdmin to use in commonclient.Transaction. -func (c Client) SetAdminCall(owner util.Uint160) (method string, args []any) { - return setAdminMethod, []any{owner} -} - -// ClearAdmin removes address that can perform write operations on contract. -// Must be invoked by committee. -func (c Client) ClearAdmin() (tx util.Uint256, vub uint32, err error) { - method, args := c.ClearAdminCall() - return c.act.SendCall(c.contract, method, args...) -} - -// ClearAdminCall provides args for ClearAdmin to use in commonclient.Transaction. -func (c Client) ClearAdminCall() (method string, args []any) { - return clearAdminMethod, nil -} - -// GetAdmin returns address that can perform write operations on contract. -// Second return values is true iff admin is set. -func (c Client) GetAdmin() (util.Uint160, bool, error) { - item, err := unwrap.Item(c.act.Call(c.contract, getAdminMethod)) - if err != nil { - return util.Uint160{}, false, err - } - if item.Value() == nil { - return util.Uint160{}, false, nil - } - bs, err := item.TryBytes() - if err != nil { - return util.Uint160{}, true, err - } - u, err := util.Uint160DecodeBytesBE(bs) - return u, true, err -} - -// CreateSubject creates new subject using public key and namespace. -// Must be invoked by contract owner. -func (c Client) CreateSubject(ns string, key *keys.PublicKey) (tx util.Uint256, vub uint32, err error) { - method, args := c.CreateSubjectCall(ns, key) - return c.act.SendCall(c.contract, method, args...) -} - -// CreateSubjectCall provides args for CreateSubject to use in commonclient.Transaction. -func (c Client) CreateSubjectCall(ns string, key *keys.PublicKey) (method string, args []any) { - return createSubjectMethod, []any{ns, key.Bytes()} -} - -// GetSubject gets subject by address. -func (c Client) GetSubject(addr util.Uint160) (*Subject, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getSubjectMethod, addr)) - if err != nil { - return nil, err - } - - return ParseSubject(items) -} - -// GetSubjectExtended gets extended subject by address. -func (c Client) GetSubjectExtended(addr util.Uint160) (*SubjectExtended, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getSubjectExtendedMethod, addr)) - if err != nil { - return nil, err - } - - return ParseSubjectExtended(items) -} - -// GetSubjectKV invokes `getSubjectKV` method of contract. -func (c Client) GetSubjectKV(addr util.Uint160, name string) (string, error) { - return unwrap.UTF8String(c.act.Call(c.contract, getSubjectKVMethod, addr, name)) -} - -// ListSubjects gets all subjects. -func (c Client) ListSubjects() ([]util.Uint160, error) { - return UnwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listSubjectsMethod)) -} - -// ListFullSubjects gets list of subjects. -func (c Client) ListFullSubjects(hashes []util.Uint160) ([]*Subject, error) { - w := io.NewBufBinWriter() - - for _, hash := range hashes { - emit.AppCall(w.BinWriter, c.contract, getSubjectMethod, callflag.All, hash) - } - - invoker, err := c.act.Run(w.Bytes()) - if err != nil { - return nil, err - } - if invoker.State != vmstate.Halt.String() { - return nil, fmt.Errorf("invocation failed: %s", invoker.FaultException) - } - subjects := make([]*Subject, 0, len(invoker.Stack)) - - for _, item := range invoker.Stack { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, fmt.Errorf("invalid subject") - } - - subject, err := ParseSubject(arr) - if err != nil { - return nil, err - } - subjects = append(subjects, subject) - } - - return subjects, nil -} - -// AddSubjectKey adds extra public key to subject. -// Must be invoked by contract owner. -func (c Client) AddSubjectKey(addr util.Uint160, key *keys.PublicKey) (tx util.Uint256, vub uint32, err error) { - method, args := c.AddSubjectKeyCall(addr, key) - return c.act.SendCall(c.contract, method, args...) -} - -// AddSubjectKeyCall provides args for AddSubjectKey to use in commonclient.Transaction. -func (c Client) AddSubjectKeyCall(addr util.Uint160, key *keys.PublicKey) (method string, args []any) { - return addSubjectKeyMethod, []any{addr, key.Bytes()} -} - -// RemoveSubjectKey removes extra public key from subject. -// Must be invoked by contract owner. -func (c Client) RemoveSubjectKey(addr util.Uint160, key *keys.PublicKey) (tx util.Uint256, vub uint32, err error) { - method, args := c.RemoveSubjectKeyCall(addr, key) - return c.act.SendCall(c.contract, method, args...) -} - -// RemoveSubjectKeyCall provides args for RemoveSubjectKey to use in commonclient.Transaction. -func (c Client) RemoveSubjectKeyCall(addr util.Uint160, key *keys.PublicKey) (method string, args []any) { - return removeSubjectKeyMethod, []any{addr, key.Bytes()} -} - -// SetSubjectKV updates subject kv map. -// Must be invoked by contract owner. -// You can use some predefined key constants: IAMPathKey, IAMARNKey, IAMCreatedTimeKey, IAMModifiedTimeKey. -func (c Client) SetSubjectKV(addr util.Uint160, key, val string) (tx util.Uint256, vub uint32, err error) { - method, args := c.SetSubjectKVCall(addr, key, val) - return c.act.SendCall(c.contract, method, args...) -} - -// SetSubjectKVCall provides args for SetSubjectKV to use in commonclient.Transaction. -func (c Client) SetSubjectKVCall(addr util.Uint160, key, val string) (method string, args []any) { - return setSubjectKVMethod, []any{addr, key, val} -} - -// SetSubjectName updates subject name. -// Must be invoked by contract owner. -func (c Client) SetSubjectName(addr util.Uint160, name string) (tx util.Uint256, vub uint32, err error) { - method, args := c.SetSubjectNameCall(addr, name) - return c.act.SendCall(c.contract, method, args...) -} - -// SetSubjectNameCall provides args for SetSubjectName to use in commonclient.Transaction. -func (c Client) SetSubjectNameCall(addr util.Uint160, name string) (method string, args []any) { - return setSubjectNameMethod, []any{addr, name} -} - -// DeleteSubjectKV removes subject kv map. -// Must be invoked by contract owner. -func (c Client) DeleteSubjectKV(addr util.Uint160, key string) (tx util.Uint256, vub uint32, err error) { - method, args := c.DeleteSubjectKVCall(addr, key) - return c.act.SendCall(c.contract, method, args...) -} - -// DeleteSubjectKVCall provides args for DeleteSubjectKV to use in commonclient.Transaction. -func (c Client) DeleteSubjectKVCall(addr util.Uint160, key string) (method string, args []any) { - return deleteSubjectKVMethod, []any{addr, key} -} - -// GetSubjectByKey gets subject by its primary or additional keys. -func (c Client) GetSubjectByKey(key *keys.PublicKey) (*Subject, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getSubjectByKeyMethod, key.Bytes())) - if err != nil { - return nil, err - } - - return ParseSubject(items) -} - -// GetSubjectByName gets subject by its name (namespace scope). -func (c Client) GetSubjectByName(namespace, subjectName string) (*Subject, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getSubjectByNameMethod, namespace, subjectName)) - if err != nil { - return nil, err - } - - return ParseSubject(items) -} - -// GetSubjectKeyByName gets subject public key by its name (namespace scope). -func (c Client) GetSubjectKeyByName(namespace, subjectName string) (*keys.PublicKey, error) { - return unwrap.PublicKey(c.act.Call(c.contract, getSubjectKeyByNameMethod, namespace, subjectName)) -} - -// DeleteSubject delete subject and removes it from related namespaces and groups. -// Must be invoked by contract owner. -func (c Client) DeleteSubject(addr util.Uint160) (tx util.Uint256, vub uint32, err error) { - method, args := c.DeleteSubjectCall(addr) - return c.act.SendCall(c.contract, method, args...) -} - -// DeleteSubjectCall provides args for DeleteSubject to use in commonclient.Transaction. -func (c Client) DeleteSubjectCall(addr util.Uint160) (method string, args []any) { - return deleteSubjectMethod, []any{addr} -} - -// CreateNamespace create new namespace. -// Must be invoked by contract owner. -func (c Client) CreateNamespace(namespace string) (tx util.Uint256, vub uint32, err error) { - method, args := c.CreateNamespaceCall(namespace) - return c.act.SendCall(c.contract, method, args...) -} - -// CreateNamespaceCall provides args for CreateNamespace to use in commonclient.Transaction. -func (c Client) CreateNamespaceCall(namespace string) (method string, args []any) { - return createNamespaceMethod, []any{namespace} -} - -// GetNamespace gets namespace. -func (c Client) GetNamespace(namespace string) (*Namespace, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getNamespaceMethod, namespace)) - if err != nil { - return nil, err - } - - return ParseNamespace(items) -} - -// GetNamespaceExtended gets extended namespace. -func (c Client) GetNamespaceExtended(namespace string) (*NamespaceExtended, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getNamespaceExtendedMethod, namespace)) - if err != nil { - return nil, err - } - - return ParseNamespaceExtended(items) -} - -// UpdateNamespace updates namespace. -// Must be invoked by contract owner. -func (c Client) UpdateNamespace(namespace string, state NamespaceState) (tx util.Uint256, vub uint32, err error) { - method, args := c.UpdateNamespaceCall(namespace, string(state)) - return c.act.SendCall(c.contract, method, args...) -} - -// UpdateNamespaceCall provides args for UpdateNamespace to use in commonclient.Transaction. -func (c Client) UpdateNamespaceCall(namespace string, state string) (method string, args []any) { - return updateNamespaceMethod, []any{namespace, state} -} - -// DeleteNamespace idempotently removes the namespace. -// Must be invoked by contract owner. -func (c Client) DeleteNamespace(namespace string) (tx util.Uint256, vub uint32, err error) { - method, args := c.DeleteNamespaceCall(namespace) - return c.act.SendCall(c.contract, method, args...) -} - -// DeleteNamespaceCall provides args for DeleteNamespace to use in commonclient.Transaction. -func (c Client) DeleteNamespaceCall(namespace string) (method string, args []any) { - return deleteNamespaceMethod, []any{namespace} -} - -// ListNamespaces gets all namespaces. -func (c Client) ListNamespaces() ([]*Namespace, error) { - items, err := commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listNamespacesMethod) - if err != nil { - return nil, err - } - - return ParseNamespaces(items) -} - -// ListNamespaceSubjects gets all subjects from namespace. -func (c Client) ListNamespaceSubjects(namespace string) ([]util.Uint160, error) { - return UnwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listNamespaceSubjectsMethod, namespace)) -} - -// CreateGroup creates a new group in specific namespace. -// Must be invoked by contract owner. -func (c Client) CreateGroup(namespace, group string) (tx util.Uint256, vub uint32, err error) { - method, args := c.CreateGroupCall(namespace, group) - return c.act.SendCall(c.contract, method, args...) -} - -// CreateGroupCall provides args for CreateGroup to use in commonclient.Transaction. -func (c Client) CreateGroupCall(namespace, group string) (method string, args []any) { - return createGroupMethod, []any{namespace, group} -} - -// GetGroup gets group. -func (c Client) GetGroup(namespace string, groupID int64) (*Group, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getGroupMethod, namespace, groupID)) - if err != nil { - return nil, err - } - - return ParseGroup(items) -} - -// GetGroupExtended gets extended group. -func (c Client) GetGroupExtended(namespace string, groupID int64) (*GroupExtended, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getGroupExtendedMethod, namespace, groupID)) - if err != nil { - return nil, err - } - - return ParseGroupExtended(items) -} - -// SetGroupName updates subject name. -// Must be invoked by contract owner. -func (c Client) SetGroupName(namespace string, groupID int64, name string) (tx util.Uint256, vub uint32, err error) { - method, args := c.SetGroupNameCall(namespace, groupID, name) - return c.act.SendCall(c.contract, method, args...) -} - -// SetGroupNameCall provides args for SetGroupName to use in commonclient.Transaction. -func (c Client) SetGroupNameCall(namespace string, groupID int64, name string) (method string, args []any) { - return setGroupNameMethod, []any{namespace, groupID, name} -} - -// SetGroupKV updates group kv map. -// Must be invoked by contract owner. -// You can use some predefined key constants: IAMPathKey, IAMARNKey, IAMCreatedTimeKey, IAMModifiedTimeKey. -func (c Client) SetGroupKV(namespace string, groupID int64, key, val string) (tx util.Uint256, vub uint32, err error) { - method, args := c.SetGroupKVCall(namespace, groupID, key, val) - return c.act.SendCall(c.contract, method, args...) -} - -// SetGroupKVCall provides args for SetGroupKV to use in commonclient.Transaction. -func (c Client) SetGroupKVCall(namespace string, groupID int64, key, val string) (method string, args []any) { - return setGroupKVMethod, []any{namespace, groupID, key, val} -} - -// DeleteGroupKV removes group kv map. -// Must be invoked by contract owner. -func (c Client) DeleteGroupKV(namespace string, groupID int64, key string) (tx util.Uint256, vub uint32, err error) { - method, args := c.DeleteGroupKVCall(namespace, groupID, key) - return c.act.SendCall(c.contract, method, args...) -} - -// DeleteGroupKVCall provides args for DeleteGroupKV to use in commonclient.Transaction. -func (c Client) DeleteGroupKVCall(namespace string, groupID int64, key string) (method string, args []any) { - return deleteGroupKVMethod, []any{namespace, groupID, key} -} - -// GetGroupIDByName gets group id its name (namespace scope). -func (c Client) GetGroupIDByName(namespace, groupName string) (int64, error) { - return unwrap.Int64(c.act.Call(c.contract, getGroupIDByNameMethod, namespace, groupName)) -} - -// GetGroupByName gets group by its name (namespace scope). -func (c Client) GetGroupByName(namespace, groupName string) (*Group, error) { - items, err := unwrap.Array(c.act.Call(c.contract, getGroupByNameMethod, namespace, groupName)) - if err != nil { - return nil, err - } - - return ParseGroup(items) -} - -// ListGroups gets all groups in specific namespace. -func (c Client) ListGroups(namespace string) ([]*Group, error) { - items, err := commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listGroupsMethod, namespace) - if err != nil { - return nil, err - } - - return ParseGroups(items) -} - -// AddSubjectToGroup adds a new subject to group. -// Must be invoked by contract owner. -func (c Client) AddSubjectToGroup(addr util.Uint160, groupID int64) (tx util.Uint256, vub uint32, err error) { - method, args := c.AddSubjectToGroupCall(addr, groupID) - return c.act.SendCall(c.contract, method, args...) -} - -// AddSubjectToGroupCall provides args for AddSubjectToGroup to use in commonclient.Transaction. -func (c Client) AddSubjectToGroupCall(addr util.Uint160, groupID int64) (method string, args []any) { - return addSubjectToGroupMethod, []any{addr, groupID} -} - -// RemoveSubjectFromGroup removes subject from group. -// Must be invoked by contract owner. -func (c Client) RemoveSubjectFromGroup(addr util.Uint160, groupID int64) (tx util.Uint256, vub uint32, err error) { - method, args := c.RemoveSubjectFromGroupCall(addr, groupID) - return c.act.SendCall(c.contract, method, args...) -} - -// RemoveSubjectFromGroupCall provides args for RemoveSubjectFromGroup to use in commonclient.Transaction. -func (c Client) RemoveSubjectFromGroupCall(addr util.Uint160, groupID int64) (method string, args []any) { - return removeSubjectFromGroupMethod, []any{addr, groupID} -} - -// ListGroupSubjects gets all subjects in specific group. -func (c Client) ListGroupSubjects(namespace string, groupID int64) ([]util.Uint160, error) { - return UnwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listGroupSubjectsMethod, namespace, groupID)) -} - -// DeleteGroup deletes group. -// Must be invoked by contract owner. -func (c Client) DeleteGroup(namespace string, groupID int64) (tx util.Uint256, vub uint32, err error) { - method, args := c.DeleteGroupCall(namespace, groupID) - return c.act.SendCall(c.contract, method, args...) -} - -// DeleteGroupCall provides args for DeleteGroup to use in commonclient.Transaction. -func (c Client) DeleteGroupCall(namespace string, groupID int64) (method string, args []any) { - return deleteGroupMethod, []any{namespace, groupID} -} - -// ListNonEmptyNamespaces gets namespaces that contain at least one subject. -func (c Client) ListNonEmptyNamespaces() ([]string, error) { - namespaces, err := c.ListNamespaces() - if err != nil { - return nil, err - } - - var res []string - - for _, namespace := range namespaces { - nsExt, err := c.GetNamespaceExtended(namespace.Name) - if err != nil { - return nil, err - } - - if nsExt.SubjectsCount > 0 { - res = append(res, nsExt.Name) - } - } - - return res, nil -} - -// Wait waits until the specified transaction is accepted to the chain. -// Deprecated: use [Waiter] method instead. -func (c Client) Wait(tx util.Uint256, vub uint32, err error) (*state.AppExecResult, error) { - return c.Waiter().WaitCtx(context.TODO(), tx, vub, err) -} - -// Waiter returns underlying waiter. -func (c Client) Waiter() commonclient.ContextWaiter { - return c.waiter -} - -// ParseGroupID fetch groupID from stack after creating group method invocation. -func (c Client) ParseGroupID(res *state.AppExecResult, err error) (int64, error) { - if err != nil { - return 0, err - } - - return unwrap.Int64(makeResFromAppExec(res)) -} - -// ListNonEmptyGroups gets groups that contain at least one subject. -func (c Client) ListNonEmptyGroups(namespace string) ([]string, error) { - groups, err := c.ListGroups(namespace) - if err != nil { - return nil, err - } - - var res []string - - for _, group := range groups { - groupExt, err := c.GetGroupExtended(namespace, group.ID) - if err != nil { - return nil, err - } - - if groupExt.SubjectsCount > 0 { - res = append(res, groupExt.Name) - } - } - - return res, nil -} diff --git a/frostfsid/client/utils.go b/frostfsid/client/utils.go deleted file mode 100644 index 4dc0c70..0000000 --- a/frostfsid/client/utils.go +++ /dev/null @@ -1,332 +0,0 @@ -package client - -import ( - "errors" - "fmt" - - "github.com/nspcc-dev/neo-go/pkg/core/state" - "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" - "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" -) - -func UnwrapArrayOfUint160(items []stackitem.Item, err error) ([]util.Uint160, error) { - if err != nil { - return nil, err - } - - return unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(items))) -} - -func ParseSubject(structArr []stackitem.Item) (*Subject, error) { - if len(structArr) < 5 { - return nil, errors.New("invalid response subject struct") - } - - var ( - err error - subj Subject - ) - - subj.PrimaryKey, err = unwrap.PublicKey(makeValidRes(structArr[0])) - if err != nil { - return nil, err - } - - if !structArr[1].Equals(stackitem.Null{}) { - subj.AdditionalKeys, err = unwrap.ArrayOfPublicKeys(makeValidRes(structArr[1])) - if err != nil { - return nil, err - } - } - - if !structArr[2].Equals(stackitem.Null{}) { - subj.Namespace, err = unwrap.UTF8String(makeValidRes(structArr[2])) - if err != nil { - return nil, err - } - } - - if !structArr[2].Equals(stackitem.Null{}) { - subj.Name, err = unwrap.UTF8String(makeValidRes(structArr[3])) - if err != nil { - return nil, err - } - } - - subj.KV, err = ParseMap(structArr[4]) - if err != nil { - return nil, err - } - - return &subj, nil -} - -func ParseSubjectExtended(structArr []stackitem.Item) (*SubjectExtended, error) { - if len(structArr) < 6 { - return nil, errors.New("invalid response subject extended struct") - } - - var ( - err error - subj SubjectExtended - ) - - subj.PrimaryKey, err = unwrap.PublicKey(makeValidRes(structArr[0])) - if err != nil { - return nil, err - } - - if !structArr[1].Equals(stackitem.Null{}) { - subj.AdditionalKeys, err = unwrap.ArrayOfPublicKeys(makeValidRes(structArr[1])) - if err != nil { - return nil, err - } - } - - nsBytes, err := structArr[2].TryBytes() - if err != nil { - return nil, err - } - subj.Namespace = string(nsBytes) - - nameBytes, err := structArr[3].TryBytes() - if err != nil { - return nil, err - } - subj.Name = string(nameBytes) - - subj.KV, err = ParseMap(structArr[4]) - if err != nil { - return nil, err - } - - if !structArr[5].Equals(stackitem.Null{}) { - groupItems, ok := structArr[5].Value().([]stackitem.Item) - if !ok { - return nil, fmt.Errorf("invalid groups field") - } - - subj.Groups, err = ParseGroups(groupItems) - if err != nil { - return nil, err - } - } - - return &subj, nil -} - -func ParseMap(item stackitem.Item) (map[string]string, error) { - if item.Equals(stackitem.Null{}) { - return nil, nil - } - - metaMap, err := unwrap.Map(makeValidRes(item)) - if err != nil { - return nil, err - } - - meta, ok := metaMap.Value().([]stackitem.MapElement) - if !ok { - return nil, errors.New("invalid map type") - } - - res := make(map[string]string, len(meta)) - for _, element := range meta { - key, err := element.Key.TryBytes() - if err != nil { - return nil, err - } - val, err := element.Value.TryBytes() - if err != nil { - return nil, err - } - res[string(key)] = string(val) - } - - return res, nil -} - -func ParseNamespace(structArr []stackitem.Item) (*Namespace, error) { - if len(structArr) < 1 { - return nil, errors.New("invalid response namespace struct") - } - - return parseNamespace(structArr, 1) -} - -func ParseNamespaceExtended(structArr []stackitem.Item) (*NamespaceExtended, error) { - if len(structArr) < 3 { - return nil, errors.New("invalid response namespace extended struct") - } - - ns, err := parseNamespace(structArr, 3) - if err != nil { - return nil, err - } - - groupCount, err := structArr[1].TryInteger() - if err != nil { - return nil, err - } - - subjectCount, err := structArr[2].TryInteger() - if err != nil { - return nil, err - } - - return &NamespaceExtended{ - Name: ns.Name, - State: ns.State, - GroupsCount: groupCount.Int64(), - SubjectsCount: subjectCount.Int64(), - }, nil -} - -func parseNamespace(structArr []stackitem.Item, stateIndex int) (*Namespace, error) { - name, err := structArr[0].TryBytes() - if err != nil { - return nil, err - } - - nsState := Active - if len(structArr) >= stateIndex+1 { - nsStateBytes, err := structArr[stateIndex].TryBytes() - if err != nil { - return nil, err - } - - if len(nsStateBytes) > 0 { - nsState = NamespaceState(nsStateBytes) - } - } - - return &Namespace{ - Name: string(name), - State: nsState, - }, nil -} - -func ParseNamespaces(items []stackitem.Item) ([]*Namespace, error) { - var err error - res := make([]*Namespace, len(items)) - - for i := 0; i < len(items); i++ { - arr, ok := items[i].Value().([]stackitem.Item) - if !ok { - return nil, fmt.Errorf("invalid namespace type") - } - res[i], err = ParseNamespace(arr) - if err != nil { - return nil, err - } - } - - return res, nil -} - -func ParseGroup(structArr []stackitem.Item) (*Group, error) { - if len(structArr) < 4 { - return nil, errors.New("invalid response group struct") - } - - groupID, err := structArr[0].TryInteger() - if err != nil { - return nil, err - } - - name, err := structArr[1].TryBytes() - if err != nil { - return nil, err - } - - namespace, err := structArr[2].TryBytes() - if err != nil { - return nil, err - } - - kvs, err := ParseMap(structArr[3]) - if err != nil { - return nil, err - } - - return &Group{ - ID: groupID.Int64(), - Name: string(name), - Namespace: string(namespace), - KV: kvs, - }, nil -} - -func ParseGroupExtended(structArr []stackitem.Item) (*GroupExtended, error) { - if len(structArr) < 5 { - return nil, errors.New("invalid response group extended struct") - } - - groupID, err := structArr[0].TryInteger() - if err != nil { - return nil, err - } - - name, err := structArr[1].TryBytes() - if err != nil { - return nil, err - } - - namespace, err := structArr[2].TryBytes() - if err != nil { - return nil, err - } - - kvs, err := ParseMap(structArr[3]) - if err != nil { - return nil, err - } - - subjectCount, err := structArr[4].TryInteger() - if err != nil { - return nil, err - } - - return &GroupExtended{ - ID: groupID.Int64(), - Name: string(name), - Namespace: string(namespace), - KV: kvs, - SubjectsCount: subjectCount.Int64(), - }, nil -} - -func ParseGroups(items []stackitem.Item) ([]*Group, error) { - var err error - res := make([]*Group, len(items)) - - for i := 0; i < len(items); i++ { - arr, ok := items[i].Value().([]stackitem.Item) - if !ok { - return nil, fmt.Errorf("invalid group type") - } - res[i], err = ParseGroup(arr) - if err != nil { - return nil, err - } - } - - return res, nil -} - -func makeValidRes(item stackitem.Item) (*result.Invoke, error) { - return &result.Invoke{ - Stack: []stackitem.Item{item}, - State: vmstate.Halt.String(), - }, nil -} - -func makeResFromAppExec(res *state.AppExecResult) (*result.Invoke, error) { - return &result.Invoke{ - Stack: res.Stack, - State: res.VMState.String(), - }, nil -} diff --git a/frostfsid/config.yml b/frostfsid/config.yml index be3cfb3..a8daad2 100644 --- a/frostfsid/config.yml +++ b/frostfsid/config.yml @@ -1,144 +1,4 @@ name: "Identity" -safemethods: - - "getAdmin" - - "getGroup" - - "getGroupExtended" - - "getGroupIDByName" - - "getGroupByName" - - "getNamespace" - - "getNamespaceExtended" - - "getSubjectKV" - - "getSubject" - - "getSubjectExtended" - - "getSubjectByKey" - - "getSubjectByName" - - "getSubjectKeyByName" - - "listGroups" - - "listGroupSubjects" - - "listNamespaces" - - "listNamespaceSubjects" - - "listSubjects" - - "version" +safemethods: ["key", "version"] permissions: - methods: ["update"] -events: - - name: CreateSubject - parameters: - - name: subjectAddress - type: Hash160 - - name: AddSubjectKey - parameters: - - name: subjectAddress - type: Hash160 - - name: subjectKey - type: PublicKey - - name: RemoveSubjectKey - parameters: - - name: subjectAddress - type: Hash160 - - name: subjectKey - type: PublicKey - - name: SetSubjectName - parameters: - - name: subjectAddress - type: Hash160 - - name: name - type: String - - name: SetSubjectKV - parameters: - - name: subjectAddress - type: Hash160 - - name: key - type: String - - name: value - type: String - - name: DeleteSubjectKV - parameters: - - name: subjectAddress - type: Hash160 - - name: key - type: String - - name: DeleteSubject - parameters: - - name: subjectAddress - type: Hash160 - - name: CreateNamespace - parameters: - - name: namespace - type: String - - name: UpdateNamespace - parameters: - - name: namespace - type: String - - name: state - type: String - - name: DeleteNamespace - parameters: - - name: namespace - type: String - - name: AddSubjectToNamespace - parameters: - - name: subjectAddress - type: Hash160 - - name: namespace - type: String - - name: RemoveSubjectFromNamespace - parameters: - - name: subjectAddress - type: Hash160 - - name: namespace - type: String - - name: CreateGroup - parameters: - - name: namespace - type: String - - name: group - type: String - - name: SetGroupName - parameters: - - name: namespace - type: String - - name: groupID - type: Integer - - name: name - type: String - - name: SetGroupKV - parameters: - - name: namespace - type: String - - name: groupID - type: Integer - - name: key - type: String - - name: value - type: String - - name: DeleteGroupKV - parameters: - - name: namespace - type: String - - name: groupID - type: Integer - - name: key - type: String - - name: AddSubjectToGroup - parameters: - - name: subjectAddress - type: Hash160 - - name: namespace - type: String - - name: groupID - type: Integer - - name: RemoveSubjectFromGroup - parameters: - - name: subjectAddress - type: Hash160 - - name: namespace - type: String - - name: groupID - type: Integer - - name: DeleteGroup - parameters: - - name: namespace - type: String - - name: groupID - type: Integer diff --git a/frostfsid/doc.go b/frostfsid/doc.go index a887f42..e15832d 100644 --- a/frostfsid/doc.go +++ b/frostfsid/doc.go @@ -1,28 +1,20 @@ -// Package frostfsid /* FrostFSID contract is a contract deployed in FrostFS sidechain. +FrostFSID contract is used to store connection between an OwnerID and its public keys. +OwnerID is a 25-byte N3 wallet address that can be produced from a public key. +It is one-way conversion. In simple cases, FrostFS verifies ownership by checking +signature and relation between a public key and an OwnerID. + +In more complex cases, a user can use public keys unrelated to the OwnerID to maintain +secure access to the data. FrostFSID contract stores relation between an OwnerID and +arbitrary public keys. Data owner can bind a public key with its account or unbind it +by invoking Bind or Unbind methods of FrostFS contract in the mainchain. After that, +Alphabet nodes produce multisigned AddKey and RemoveKey invocations of FrostFSID +contract. + # Contract notifications FrostFSID contract does not produce notifications to process. - -# Contract storage scheme - - | Key | Value | Description | - |------------------------------------------------------------------------------|--------------------------------|-----------------------------------------------| - | `o` + [ owner address ] | []byte{1} | contract owners that can invoke write methods | - | `s` + [ subject address ] | Serialized Subject structure | subject into | - | `a` + [ pk address ] + [ subject address ] | []byte{1} | link extra public keys for subject | - | `n` + [ RIPEMD160 of namespace ] | Serialized Namespace structure | namespace info | - | `N` + [ RIPEMD160 of namespace ] + [ subject address ] | []byte{1} | subject that belongs to the namespace | - | `l` + [ RIPEMD160 of namespace ] + [ RIPEMD160 of subject name ] | Subject public key | subject name to public key index | - | `g` + [ RIPEMD160 of namespace ] + [ 8 byte group id ] | Serialized Group structure | group into | - | `G` + [ RIPEMD160 of namespace ] + [ 8 byte group id ] + [ subject address ] | []byte{1} | subject that belongs to the group | - | `c` | Int | group id counter | - | `m` + [ RIPEMD160 of namespace ] + [ RIPEMD160 of subject name ] | Serialized group id int | group name to group id index | - | `A` + [ subject address ] | bool | means that the wallet has been used | - | `d` + [ subject address ] + [ pk address ] | []byte{1} | link subject to extra public keys | - - */ package frostfsid diff --git a/frostfsid/frostfsid_contract.go b/frostfsid/frostfsid_contract.go index 1167041..58d6fbc 100644 --- a/frostfsid/frostfsid_contract.go +++ b/frostfsid/frostfsid_contract.go @@ -4,1242 +4,159 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-contract/common" "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/convert" "github.com/nspcc-dev/neo-go/pkg/interop/iterator" - "github.com/nspcc-dev/neo-go/pkg/interop/native/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" - "github.com/nspcc-dev/neo-go/pkg/interop/native/std" "github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) type ( - // Subject represents a subject entity. - // - // Fields: - // - Namespace: a string representing the namespace of the subject. - // - Name: a string representing the name of the subject. - // The name must match the following regex pattern: ^[\w+=,.@-]{1,64}$ - // The Subject is stored in the storage as a hash(namespace) + hash(name). - // AdditionalKeys are stored in records with subject's address prefix. - Subject struct { - PrimaryKey interop.PublicKey - AdditionalKeys []interop.PublicKey - Namespace string - Name string - KV map[string]string - } - - SubjectExtended struct { - PrimaryKey interop.PublicKey - AdditionalKeys []interop.PublicKey - Namespace string - Name string - KV map[string]string - Groups []Group - } - - // Namespace represents a namespace. - // - // Fields: - // - Name: a string representing the name of the namespace. - // The custom name must match the following regex pattern: - // (^$)|(^[a-z0-9]{1,2}$)|(^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$) - // An empty Name is considered the namespace. - // - // The Namespace is stored in the storage as a hash(name). - Namespace struct { - Name string - State string - } - - NamespaceExtended struct { - Name string - GroupsCount int - SubjectsCount int - State string - } - - // Group represents a group entity. - // - // Fields: - // - ID: an integer representing the unique identifier of the group. - // The ID is generated upon creation and is the sequential number of the group within the namespace. - // It cannot be changed once set. - // - Name: a string representing the name of the group. - // The name must match the following regex pattern: [\w+=,.@-]{1,128}$ - // - Namespace: a string representing the namespace of the group. - // A group exists only within one namespace. - // - // The group is stored in the storage as a hash(namespace) + hash(name). - Group struct { - ID int - Name string - Namespace string - KV map[string]string - } - - GroupExtended struct { - ID int - Name string - Namespace string - KV map[string]string - SubjectsCount int + UserInfo struct { + Keys [][]byte } ) const ( - adminKey = 'o' - subjectKeysPrefix = 's' - additionalKeysPrefix = 'a' - namespaceKeysPrefix = 'n' - namespaceSubjectsKeysPrefix = 'N' - namespaceSubjectsNamesPrefix = 'l' - groupKeysPrefix = 'g' - groupSubjectsKeysPrefix = 'G' - groupCounterKey = 'c' - namespaceGroupsNamesPrefix = 'm' - addressPrefix = 'A' - subjectToAddKeyPrefix = 'd' - - nsActiveState = "active" - nsFrozenState = "frozen" - nsPurgeState = "purge" + ownerSize = 1 + interop.Hash160Len + 4 ) -var dummyValue = []byte{1} +const ( + netmapContractKey = "netmapScriptHash" + containerContractKey = "containerScriptHash" + notaryDisabledKey = "notary" + ownerKeysPrefix = 'o' +) -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() - args := data.(struct { - admin interop.Hash160 - version int - }) - - if args.admin != nil { - if len(args.admin) != interop.Hash160Len { - panic("incorrect length of owner address") - } - storage.Put(ctx, adminKey, args.admin) - } + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) if isUpdate { - common.CheckVersion(args.version) - if args.version < common.GetVersion(0, 21, 1) { - it := storage.Find(ctx, subjectKeysPrefix, storage.ValuesOnly) - for iterator.Next(it) { - subjectRaw := iterator.Value(it) - subject := std.Deserialize(subjectRaw.([]byte)).(Subject) - address := addressKey(contract.CreateStandardAccount(subject.PrimaryKey)) - if storage.Get(ctx, address) != nil { - panic("frostfsid contract contains duplicate keys") - } - storage.Put(ctx, address, true) - - for i := 0; i < len(subject.AdditionalKeys); i++ { - address = addressKey(contract.CreateStandardAccount(subject.AdditionalKeys[i])) - if storage.Get(ctx, address) != nil { - panic("frostfsid contract contains duplicate keys") - } - storage.Put(ctx, address, true) - } - } - } - if args.version < common.GetVersion(0, 21, 2) { - maxGroupID := 0 - it := storage.Find(ctx, groupKeysPrefix, storage.ValuesOnly) - for iterator.Next(it) { - groupRaw := iterator.Value(it) - group := std.Deserialize(groupRaw.([]byte)).(Group) - if group.ID > maxGroupID { - maxGroupID = group.ID - } - } - - storage.Put(ctx, groupCounterKey, maxGroupID) - } - - if args.version < common.GetVersion(0, 21, 3) { - migrateNamespacesState(ctx) - } - - if args.version < common.GetVersion(0, 21, 4) { - it := storage.Find(ctx, subjectKeysPrefix, storage.ValuesOnly) - for iterator.Next(it) { - subject := std.Deserialize(iterator.Value(it).([]byte)).(Subject) - subjAddr := contract.CreateStandardAccount(subject.PrimaryKey) - for i := 0; i < len(subject.AdditionalKeys); i++ { - storage.Put(ctx, subjectToAdditionalKeyKey(subjAddr, subject.AdditionalKeys[i]), dummyValue) - } - subject.AdditionalKeys = nil - storage.Put(ctx, subjectKeyFromAddr(subjAddr), std.Serialize(subject)) - } - } - + args := data.([]interface{}) + common.CheckVersion(args[len(args)-1].(int)) return } - storage.Put(ctx, groupCounterKey, 0) - storage.Put(ctx, namespaceKey(""), std.Serialize(Namespace{State: nsActiveState})) + args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrNetmap interop.Hash160 + addrContainer interop.Hash160 + }) + + if len(args.addrNetmap) != interop.Hash160Len || len(args.addrContainer) != interop.Hash160Len { + panic("incorrect length of contract script hash") + } + + storage.Put(ctx, netmapContractKey, args.addrNetmap) + storage.Put(ctx, containerContractKey, args.addrContainer) runtime.Log("frostfsid contract initialized") } -// SetAdmin sets the admin address for the contract. -func SetAdmin(addr interop.Hash160) { - ctx := storage.GetContext() - if !common.HasUpdateAccess() { - panic("not witnessed") - } - - storage.Put(ctx, adminKey, addr) -} - -// ClearAdmin removes the admin address from the contract storage. -func ClearAdmin() { - ctx := storage.GetContext() - if !common.HasUpdateAccess() { - panic("not witnessed") - } - - storage.Delete(ctx, adminKey) -} - -// GetAdmin retrieves the admin address from the contract storage. -func GetAdmin() interop.Hash160 { - ctx := storage.GetReadOnlyContext() - return storage.Get(ctx, adminKey).(interop.Hash160) -} - // Update method updates contract source code and manifest. It can be invoked // only by committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { if !common.HasUpdateAccess() { panic("only committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("frostfsid contract updated") } +// AddKey binds a list of the provided public keys to the OwnerID. It can be invoked only by +// Alphabet nodes. +// +// This method panics if the OwnerID is not an ownerSize byte or the public key is not 33 byte long. +// If the key is already bound, the method ignores it. +func AddKey(owner []byte, keys []interop.PublicKey) { + // V2 format + if len(owner) != ownerSize { + panic("incorrect owner") + } + + for i := range keys { + if len(keys[i]) != interop.PublicKeyCompressedLen { + panic("incorrect public key") + } + } + + ctx := storage.GetContext() + + common.CheckAlphabetWitness() + + ownerKey := append([]byte{ownerKeysPrefix}, owner...) + for i := range keys { + stKey := append(ownerKey, keys[i]...) + storage.Put(ctx, stKey, []byte{1}) + } + + runtime.Log("key bound to the owner") +} + +// RemoveKey unbinds the provided public keys from the OwnerID. It can be invoked only by +// Alphabet nodes. +// +// This method panics if the OwnerID is not an ownerSize byte or the public key is not 33 byte long. +// If the key is already unbound, the method ignores it. +func RemoveKey(owner []byte, keys []interop.PublicKey) { + // V2 format + if len(owner) != ownerSize { + panic("incorrect owner") + } + + for i := range keys { + if len(keys[i]) != interop.PublicKeyCompressedLen { + panic("incorrect public key") + } + } + + ctx := storage.GetContext() + + multiaddr := common.AlphabetAddress() + if !runtime.CheckWitness(multiaddr) { + panic("invocation from non inner ring node") + } + + ownerKey := append([]byte{ownerKeysPrefix}, owner...) + for i := range keys { + stKey := append(ownerKey, keys[i]...) + storage.Delete(ctx, stKey) + } +} + +// Key method returns a list of 33-byte public keys bound with the OwnerID. +// +// This method panics if the owner is not ownerSize byte long. +func Key(owner []byte) [][]byte { + // V2 format + if len(owner) != ownerSize { + panic("incorrect owner") + } + + ctx := storage.GetReadOnlyContext() + + ownerKey := append([]byte{ownerKeysPrefix}, owner...) + info := getUserInfo(ctx, ownerKey) + + return info.Keys +} + // Version returns the version of the contract. func Version() int { return common.Version } -// CreateSubject creates a new subject in the specified namespace with the provided public key. -func CreateSubject(ns string, key interop.PublicKey) { - ctx := storage.GetContext() - checkNamespaceState(ns) - checkContractOwner(ctx) - - if len(key) != interop.PublicKeyCompressedLen { - panic("incorrect public key length") - } - - addr := contract.CreateStandardAccount(key) - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data != nil { - panic("subject already exists") - } - - saPrefix := additionalKeyToSubjectPrefix(key) - it := storage.Find(ctx, saPrefix, storage.KeysOnly) +func getUserInfo(ctx storage.Context, key interface{}) UserInfo { + it := storage.Find(ctx, key, storage.KeysOnly|storage.RemovePrefix) + pubs := [][]byte{} for iterator.Next(it) { - panic("key is occupied") + pub := iterator.Value(it).([]byte) + pubs = append(pubs, pub) } - allAddressKey := addressKey(addr) - if storage.Get(ctx, allAddressKey) != nil { - panic("key is occupied by another additional key") - } - - nsKey := namespaceKey(ns) - data = storage.Get(ctx, nsKey).([]byte) - if data == nil { - panic("namespace not found") - } - - subj := Subject{ - PrimaryKey: key, - Namespace: ns, - } - - storage.Put(ctx, sKey, std.Serialize(subj)) - - nsSubjKey := namespaceSubjectKey(ns, addr) - storage.Put(ctx, nsSubjKey, dummyValue) - storage.Put(ctx, allAddressKey, true) - - runtime.Notify("CreateSubject", interop.Hash160(addr)) -} - -// AddSubjectKey adds an additional public key to a subject with the specified address. -func AddSubjectKey(addr interop.Hash160, key interop.PublicKey) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - if len(key) != interop.PublicKeyCompressedLen { - panic("incorrect public key length") - } - - addressKey := addressKey(contract.CreateStandardAccount(key)) - if storage.Get(ctx, addressKey) != nil { - panic("key is occupied") - } - - saKey := additionalKeyToSubjectKey(key, addr) - data := storage.Get(ctx, saKey).([]byte) - if data != nil { - panic("key already added") - } - - storage.Put(ctx, saKey, dummyValue) - - sKey := subjectKeyFromAddr(addr) - data = storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("address not found") - } - subject := std.Deserialize(data).(Subject) - checkNamespaceState(subject.Namespace) - - storage.Put(ctx, subjectToAdditionalKeyKey(addr, key), dummyValue) - storage.Put(ctx, addressKey, true) - runtime.Notify("AddSubjectKey", addr, key) -} - -// RemoveSubjectKey removes an additional public key from the subject with the specified address. -func RemoveSubjectKey(addr interop.Hash160, key interop.PublicKey) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - if len(key) != interop.PublicKeyCompressedLen { - panic("incorrect public key length") - } - - saKey := additionalKeyToSubjectKey(key, addr) - data := storage.Get(ctx, saKey).([]byte) - if data == nil { - panic("key already removed") - } - - storage.Delete(ctx, saKey) - - sKey := subjectKeyFromAddr(addr) - data = storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("address not found") - } - - subjToAddKey := subjectToAdditionalKeyKey(addr, key) - data = storage.Get(ctx, subjToAddKey).([]byte) - if data == nil { - panic("key already removed") - } - storage.Delete(ctx, subjToAddKey) - - storage.Delete(ctx, addressKey(contract.CreateStandardAccount(key))) - runtime.Notify("RemoveSubjectKey", addr, key) -} - -// SetSubjectName sets a new name for the subject with the specified address. -func SetSubjectName(addr interop.Hash160, name string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("subject not found") - } - - subject := std.Deserialize(data).(Subject) - checkNamespaceState(subject.Namespace) - oldName := subject.Name - subject.Name = name - storage.Put(ctx, sKey, std.Serialize(subject)) - - updateNamespaceSubjectName(ctx, subject, oldName) - - runtime.Notify("SetSubjectName", addr, name) -} - -// SetSubjectKV sets a key-value pair for the subject with the specified address. -func SetSubjectKV(addr interop.Hash160, key, val string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("subject not found") - } - - subject := std.Deserialize(data).(Subject) - checkNamespaceState(subject.Namespace) - if subject.KV == nil { - subject.KV = map[string]string{} - } - subject.KV[key] = val - - storage.Put(ctx, sKey, std.Serialize(subject)) - runtime.Notify("SetSubjectKV", addr, key, val) -} - -// DeleteSubjectKV deletes a key-value pair from the subject with the specified address. -func DeleteSubjectKV(addr interop.Hash160, key string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("subject not found") - } - - subject := std.Deserialize(data).(Subject) - delete(subject.KV, key) - - storage.Put(ctx, sKey, std.Serialize(subject)) - runtime.Notify("DeleteSubjectKV", addr, key) -} - -// DeleteSubject deletes the subject with the specified address. -func DeleteSubject(addr interop.Hash160) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - return - } - subj := std.Deserialize(data).(Subject) - - subj.AdditionalKeys = getSubjectAdditionalKeys(ctx, addr) - for i := 0; i < len(subj.AdditionalKeys); i++ { - storage.Delete(ctx, additionalKeyToSubjectKey(subj.AdditionalKeys[i], addr)) - storage.Delete(ctx, subjectToAdditionalKeyKey(addr, subj.AdditionalKeys[i])) - storage.Delete(ctx, addressKey(contract.CreateStandardAccount(subj.AdditionalKeys[i]))) - } - storage.Delete(ctx, addressKey(addr)) - storage.Delete(ctx, sKey) - - removeSubjectFromNamespace(ctx, subj.Namespace, addr) - deleteNamespaceSubjectName(ctx, subj.Namespace, subj.Name) - - runtime.Notify("DeleteSubject", addr) -} - -// GetSubject retrieves the subject with the specified address. -func GetSubject(addr interop.Hash160) Subject { - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - - ctx := storage.GetReadOnlyContext() - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - addr = getPrimaryAddr(ctx, addr) - sKey = subjectKeyFromAddr(addr) - data = storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("subject not found") - } - } - - subj := std.Deserialize(data).(Subject) - subj.AdditionalKeys = getSubjectAdditionalKeys(ctx, addr) - return subj -} - -// GetSubjectExtended retrieves the extended information of the subject with the specified address. -func GetSubjectExtended(addr interop.Hash160) SubjectExtended { - subj := GetSubject(addr) - ctx := storage.GetReadOnlyContext() - - var groups []Group - nsHash := ripemd160Hash(subj.Namespace) - it := storage.Find(ctx, groupPrefixFromHash(nsHash), storage.KeysOnly|storage.RemovePrefix) - for iterator.Next(it) { - groupHash := iterator.Value(it).([]byte) - data := storage.Get(ctx, groupSubjectKeyFromHashes(nsHash, groupHash, addr)).([]byte) - if data != nil { - data = storage.Get(ctx, groupKeyFromHashes(nsHash, groupHash)).([]byte) - if data == nil { - panic("group not found") - } - groups = append(groups, std.Deserialize(data).(Group)) - } - } - - subjExt := SubjectExtended{ - PrimaryKey: subj.PrimaryKey, - AdditionalKeys: subj.AdditionalKeys, - Namespace: subj.Namespace, - Name: subj.Name, - KV: subj.KV, - Groups: groups, - } - - return subjExt -} - -// GetSubjectByKey retrieves the subject associated with the provided public key. -func GetSubjectByKey(key interop.PublicKey) Subject { - if len(key) != interop.PublicKeyCompressedLen { - panic("incorrect key length") - } - - ctx := storage.GetReadOnlyContext() - - sKey := subjectKey(key) - data := storage.Get(ctx, sKey).([]byte) - if data != nil { - subj := std.Deserialize(data).(Subject) - subj.AdditionalKeys = getSubjectAdditionalKeys(ctx, contract.CreateStandardAccount(key)) - return subj - } - - addr := getPrimaryAddr(ctx, contract.CreateStandardAccount(key)) - sKey = subjectKeyFromAddr(addr) - data = storage.Get(ctx, sKey).([]byte) - if data != nil { - subj := std.Deserialize(data).(Subject) - subj.AdditionalKeys = getSubjectAdditionalKeys(ctx, addr) - return subj - } - - panic("subject not found") -} - -func getPrimaryAddr(ctx storage.Context, addr interop.Hash160) interop.Hash160 { - saPrefix := append([]byte{additionalKeysPrefix}, addr...) - it := storage.Find(ctx, saPrefix, storage.KeysOnly|storage.RemovePrefix) - if iterator.Next(it) { - return iterator.Value(it).([]byte) - } - panic("subject not found") -} - -func getSubjectAdditionalKeys(ctx storage.Context, addr interop.Hash160) []interop.PublicKey { - var result []interop.PublicKey - subjToAddKeyPrefix := subjectToAdditionalKeyPrefix(addr) - it := storage.Find(ctx, subjToAddKeyPrefix, storage.KeysOnly|storage.RemovePrefix) - if iterator.Next(it) { - key := iterator.Value(it).([]byte) - if len(key) < interop.PublicKeyCompressedLen { - panic("invalid subject additional key") - } - result = append(result, interop.PublicKey(key[:interop.PublicKeyCompressedLen])) - } - return result -} - -// GetSubjectByName retrieves the subject with the specified name within the given namespace. -func GetSubjectByName(ns, name string) Subject { - key := GetSubjectKeyByName(ns, name) - addr := contract.CreateStandardAccount(key) - return GetSubject(addr) -} - -// GetSubjectKeyByName retrieves the public key of the subject with the specified namespace and name. -func GetSubjectKeyByName(ns, name string) interop.PublicKey { - if name == "" { - panic("invalid or name") - } - - ctx := storage.GetReadOnlyContext() - - nsSubjNameKey := namespaceSubjectNameKey(ns, name) - subjKey := storage.Get(ctx, nsSubjNameKey).(interop.PublicKey) - if subjKey == nil { - panic("subject not found") - } - - return subjKey -} - -// GetSubjectKV GetSubjectKey returns the value associated with the key for the subject. -func GetSubjectKV(addr interop.Hash160, name string) string { - if len(addr) != interop.Hash160Len { - panic("incorrect address length") - } - - ctx := storage.GetReadOnlyContext() - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - return "" - } - - sbj := std.Deserialize(data).(Subject) - - if sbj.KV == nil { - return "" - } - - for k, v := range sbj.KV { - if k == name { - return v - } - } - - return "" -} - -func ListSubjects() iterator.Iterator { - ctx := storage.GetReadOnlyContext() - return storage.Find(ctx, []byte{subjectKeysPrefix}, storage.KeysOnly|storage.RemovePrefix) -} - -// CreateNamespace creates a new namespace with the specified name. -func CreateNamespace(ns string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - nsKey := namespaceKey(ns) - data := storage.Get(ctx, nsKey).([]byte) - if data != nil { - panic("namespace already exists") - } - - namespace := Namespace{ - Name: ns, - State: nsActiveState, - } - - storage.Put(ctx, nsKey, std.Serialize(namespace)) - runtime.Notify("CreateNamespace", ns) -} - -// DeleteNamespace idempotently removes a namespace with the specified name. -func DeleteNamespace(ns string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - nsKey := namespaceKey(ns) - data := storage.Get(ctx, nsKey).([]byte) - if data == nil { - return - } - - namespace := std.Deserialize(data).(Namespace) - if namespace.State != nsPurgeState { - panic("namespace should be in 'purge' state for deletion") - } - - it := storage.Find(ctx, groupPrefix(ns), storage.KeysOnly) - if iterator.Next(it) { - panic("can't delete non-empty namespace: groups still present") - } - - it = storage.Find(ctx, namespaceSubjectPrefix(ns), storage.KeysOnly) - if iterator.Next(it) { - panic("can't delete non-empty namespace: users still present") - } - - storage.Delete(ctx, nsKey) - runtime.Notify("DeleteNamespace", ns) -} - -// UpdateNamespace updates existing namespace. -func UpdateNamespace(ns string, state string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - nsKey := namespaceKey(ns) - data := storage.Get(ctx, nsKey).([]byte) - if data == nil { - panic("namespace not found") - } - - namespace := Namespace{ - Name: ns, - State: state, - } - - storage.Put(ctx, nsKey, std.Serialize(namespace)) - runtime.Notify("UpdateNamespace", ns, state) -} - -// GetNamespace retrieves the namespace with the specified name. -func GetNamespace(ns string) Namespace { - ctx := storage.GetReadOnlyContext() - nsKey := namespaceKey(ns) - data := storage.Get(ctx, nsKey).([]byte) - if data == nil { - panic("namespace not found") - } - - return std.Deserialize(data).(Namespace) -} - -// GetNamespaceExtended retrieves extended information about the namespace. -func GetNamespaceExtended(ns string) NamespaceExtended { - ctx := storage.GetReadOnlyContext() - nsKey := namespaceKey(ns) - data := storage.Get(ctx, nsKey).([]byte) - if data == nil { - panic("namespace not found") - } - namespace := std.Deserialize(data).(Namespace) - - nsExtended := NamespaceExtended{ - Name: namespace.Name, - State: namespace.State, - } - - it := storage.Find(ctx, groupPrefix(ns), storage.KeysOnly) - for iterator.Next(it) { - nsExtended.GroupsCount += 1 - } - - it = storage.Find(ctx, namespaceSubjectPrefix(ns), storage.KeysOnly) - for iterator.Next(it) { - nsExtended.SubjectsCount += 1 - } - - return nsExtended -} - -func ListNamespaces() iterator.Iterator { - ctx := storage.GetReadOnlyContext() - return storage.Find(ctx, []byte{namespaceKeysPrefix}, storage.ValuesOnly|storage.DeserializeValues) -} - -func ListNamespaceSubjects(ns string) iterator.Iterator { - ctx := storage.GetReadOnlyContext() - return storage.Find(ctx, namespaceSubjectPrefix(ns), storage.KeysOnly|storage.RemovePrefix) -} - -// CreateGroup creates a new group within the specified namespace. -func CreateGroup(ns, group string) int { - ctx := storage.GetContext() - checkNamespaceState(ns) - checkContractOwner(ctx) - - if group == "" { - panic("invalid group name") - } - - nsKey := namespaceKey(ns) - data := storage.Get(ctx, nsKey).([]byte) - if data == nil { - panic("namespace not found") - } - - groupCountID := storage.Get(ctx, groupCounterKey).(int) - groupCountID++ - storage.Put(ctx, groupCounterKey, groupCountID) - - gr := Group{ - ID: groupCountID, - Name: group, - Namespace: ns, - } - - setNamespaceGroupName(ctx, gr) - - gKey := groupKey(ns, groupCountID) - storage.Put(ctx, gKey, std.Serialize(gr)) - - runtime.Notify("CreateGroup", ns, group) - - return groupCountID -} - -// GetGroup retrieves the group with the specified ID within the given namespace. -func GetGroup(ns string, groupID int) Group { - ctx := storage.GetReadOnlyContext() - gKey := groupKey(ns, groupID) - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - - return std.Deserialize(data).(Group) -} - -// GetGroupExtended retrieves extended information about the group, including the count of subjects in the group. -func GetGroupExtended(ns string, groupID int) GroupExtended { - ctx := storage.GetReadOnlyContext() - gKey := groupKey(ns, groupID) - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - - gr := std.Deserialize(data).(Group) - - grExtended := GroupExtended{ - ID: gr.ID, - Name: gr.Name, - Namespace: gr.Namespace, - KV: gr.KV, - } - - it := storage.Find(ctx, groupSubjectPrefix(ns, groupID), storage.KeysOnly) - for iterator.Next(it) { - grExtended.SubjectsCount += 1 - } - - return grExtended -} - -// GetGroupIDByName retrieves the ID of the group with the specified name within the given namespace. -func GetGroupIDByName(ns, name string) int { - if name == "" { - panic("invalid name") - } - - ctx := storage.GetReadOnlyContext() - - nsGroupNameKey := namespaceGroupNameKey(ns, name) - groupIDRaw := storage.Get(ctx, nsGroupNameKey).([]byte) - if groupIDRaw == nil { - panic("group not found") - } - - return std.Deserialize(groupIDRaw).(int) -} - -// GetGroupByName retrieves the group with the specified name within the given namespace. -func GetGroupByName(ns, name string) Group { - groupID := GetGroupIDByName(ns, name) - gKey := groupKey(ns, groupID) - - ctx := storage.GetReadOnlyContext() - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - - return std.Deserialize(data).(Group) -} - -// SetGroupName sets a new name for the group with the specified ID within the given namespace. -func SetGroupName(ns string, groupID int, name string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - gKey := groupKey(ns, groupID) - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - - gr := std.Deserialize(data).(Group) - checkNamespaceState(gr.Namespace) - oldName := gr.Name - gr.Name = name - storage.Put(ctx, gKey, std.Serialize(gr)) - - updateNamespaceGroupName(ctx, gr, oldName) - - runtime.Notify("SetGroupName", ns, groupID, name) -} - -// SetGroupKV sets a key-value pair for the group with the specified ID within the given namespace. -func SetGroupKV(ns string, groupID int, key, val string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - gKey := groupKey(ns, groupID) - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - - gr := std.Deserialize(data).(Group) - checkNamespaceState(gr.Namespace) - if gr.KV == nil { - gr.KV = map[string]string{} - } - gr.KV[key] = val - - storage.Put(ctx, gKey, std.Serialize(gr)) - runtime.Notify("SetGroupKV", ns, groupID, key, val) -} - -// DeleteGroupKV deletes a key-value pair from the group with the specified ID within the given namespace. -func DeleteGroupKV(ns string, groupID int, key string) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - gKey := groupKey(ns, groupID) - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - - gr := std.Deserialize(data).(Group) - delete(gr.KV, key) - - storage.Put(ctx, gKey, std.Serialize(gr)) - runtime.Notify("DeleteGroupKV", ns, groupID, key) -} - -func ListGroups(ns string) iterator.Iterator { - ctx := storage.GetReadOnlyContext() - return storage.Find(ctx, groupPrefix(ns), storage.ValuesOnly|storage.DeserializeValues) -} - -// AddSubjectToGroup adds a subject to a group with the specified ID. -func AddSubjectToGroup(addr interop.Hash160, groupID int) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("invalid address length") - } - - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("subject not found") - } - subject := std.Deserialize(data).(Subject) - checkNamespaceState(subject.Namespace) - - gKey := groupKey(subject.Namespace, groupID) - data = storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - group := std.Deserialize(data).(Group) - - if group.Namespace != subject.Namespace { - panic("subject and group must be in the same namespace") - } - - gsKey := groupSubjectKey(subject.Namespace, groupID, addr) - storage.Put(ctx, gsKey, dummyValue) - - runtime.Notify("AddSubjectToGroup", addr, subject.Namespace, groupID) -} - -// RemoveSubjectFromGroup removes a subject from a group with the specified ID. -func RemoveSubjectFromGroup(addr interop.Hash160, groupID int) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - if len(addr) != interop.Hash160Len { - panic("invalid address length") - } - - sKey := subjectKeyFromAddr(addr) - data := storage.Get(ctx, sKey).([]byte) - if data == nil { - panic("subject not found") - } - - subject := std.Deserialize(data).(Subject) - - gKey := groupKey(subject.Namespace, groupID) - data = storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - group := std.Deserialize(data).(Group) - - if group.Namespace != subject.Namespace { - panic("subject and group must be in the same namespace") - } - - gsKey := groupSubjectKey(subject.Namespace, groupID, addr) - storage.Delete(ctx, gsKey) - - runtime.Notify("RemoveSubjectFromGroup", addr, subject.Namespace, groupID) -} - -func ListGroupSubjects(ns string, groupID int) iterator.Iterator { - ctx := storage.GetReadOnlyContext() - return storage.Find(ctx, groupSubjectPrefix(ns, groupID), storage.KeysOnly|storage.RemovePrefix) -} - -// DeleteGroup deletes the group with the specified ID within the given namespace. -func DeleteGroup(ns string, groupID int) { - ctx := storage.GetContext() - checkContractOwner(ctx) - - gKey := groupKey(ns, groupID) - data := storage.Get(ctx, gKey).([]byte) - if data == nil { - panic("group not found") - } - gr := std.Deserialize(data).(Group) - - storage.Delete(ctx, gKey) - - it := storage.Find(ctx, groupSubjectPrefix(ns, groupID), storage.KeysOnly) - for iterator.Next(it) { - gsKey := iterator.Value(it).([]byte) - storage.Delete(ctx, gsKey) - } - - deleteNamespaceGroupName(ctx, ns, gr.Name) - - runtime.Notify("DeleteGroup", ns, groupID) -} - -func checkContractOwner(ctx storage.Context) { - addr := storage.Get(ctx, adminKey) - if addr != nil && runtime.CheckWitness(addr.(interop.Hash160)) { - return - } - if common.HasUpdateAccess() { - return - } - panic("not witnessed") -} - -func removeSubjectFromNamespace(ctx storage.Context, ns string, addr interop.Hash160) { - nsSubjKey := namespaceSubjectKey(ns, addr) - storage.Delete(ctx, nsSubjKey) - - nsHash := ripemd160Hash(ns) - it := storage.Find(ctx, groupPrefixFromHash(nsHash), storage.KeysOnly|storage.RemovePrefix) - for iterator.Next(it) { - groupHash := iterator.Value(it).([]byte) - storage.Delete(ctx, groupSubjectKeyFromHashes(nsHash, groupHash, addr)) - } -} - -func setNamespaceSubjectName(ctx storage.Context, subj Subject) { - if subj.Name == "" { - return - } - - nsSubjNameKey := namespaceSubjectNameKey(subj.Namespace, subj.Name) - subjKey := storage.Get(ctx, nsSubjNameKey).(interop.PublicKey) - if subjKey == nil { - storage.Put(ctx, nsSubjNameKey, subj.PrimaryKey) - } else if !common.BytesEqual(subjKey, subj.PrimaryKey) { - panic("subject name is not available in the current namespace") - } -} - -func deleteNamespaceSubjectName(ctx storage.Context, ns, subjName string) { - if subjName == "" { - return - } - - nsSubjNameKey := namespaceSubjectNameKey(ns, subjName) - storage.Delete(ctx, nsSubjNameKey) -} - -func updateNamespaceSubjectName(ctx storage.Context, subj Subject, oldName string) { - if subj.Name == oldName { - return - } - - deleteNamespaceSubjectName(ctx, subj.Namespace, oldName) - setNamespaceSubjectName(ctx, subj) -} - -func updateNamespaceGroupName(ctx storage.Context, gr Group, oldName string) { - if gr.Name == oldName { - return - } - - deleteNamespaceGroupName(ctx, gr.Namespace, oldName) - setNamespaceGroupName(ctx, gr) -} - -func deleteNamespaceGroupName(ctx storage.Context, ns, grName string) { - if grName == "" { - return - } - - nsGroupNameKey := namespaceGroupNameKey(ns, grName) - storage.Delete(ctx, nsGroupNameKey) -} - -func setNamespaceGroupName(ctx storage.Context, gr Group) { - if gr.Name == "" { - return - } - - nsGroupNameKey := namespaceGroupNameKey(gr.Namespace, gr.Name) - groupIDRaw := storage.Get(ctx, nsGroupNameKey).([]byte) - if groupIDRaw == nil { - storage.Put(ctx, nsGroupNameKey, std.Serialize(gr.ID)) - return - } - - groupID := std.Deserialize(groupIDRaw).(int) - if groupID != gr.ID { - panic("group name is not available in the current namespace") - } -} - -func subjectKey(key interop.PublicKey) []byte { - addr := contract.CreateStandardAccount(key) - return subjectKeyFromAddr(addr) -} - -func subjectKeyFromAddr(addr interop.Hash160) []byte { - return append([]byte{subjectKeysPrefix}, addr...) -} - -func additionalKeyToSubjectKey(additionalKey interop.PublicKey, primeAddr interop.Hash160) []byte { - return append(additionalKeyToSubjectPrefix(additionalKey), primeAddr...) -} - -func additionalKeyToSubjectPrefix(additionalKey interop.PublicKey) []byte { - addr := contract.CreateStandardAccount(additionalKey) - return append([]byte{additionalKeysPrefix}, addr...) -} - -// subjectToAdditionalKeyKey returns 'd' + [20]byte subjectAddr + [33]byte additionalKey. -func subjectToAdditionalKeyKey(subjectAddr interop.Hash160, additionalKey interop.PublicKey) []byte { - return append(subjectToAdditionalKeyPrefix(subjectAddr), additionalKey...) -} - -// subjectToAdditionalKeyPrefix returns 'd' + [20]byte subjectAddr. -func subjectToAdditionalKeyPrefix(subjectAddr interop.Hash160) []byte { - return append([]byte{subjectToAddKeyPrefix}, subjectAddr...) -} - -func namespaceKey(ns string) []byte { - return namespaceKeyFromHash(ripemd160Hash(ns)) -} - -func namespaceKeyFromHash(ns []byte) []byte { - return append([]byte{namespaceKeysPrefix}, ns...) -} - -func groupKey(ns string, groupID int) []byte { - prefix := groupPrefix(ns) - return append(prefix, idToBytes(groupID)...) -} - -func groupKeyFromHashes(nsHash []byte, groupIDBytes []byte) []byte { - prefix := groupPrefixFromHash(nsHash) - return append(prefix, groupIDBytes...) -} - -func groupPrefix(ns string) []byte { - return groupPrefixFromHash(ripemd160Hash(ns)) -} - -func groupPrefixFromHash(nsHash []byte) []byte { - return append([]byte{groupKeysPrefix}, nsHash...) -} - -func ripemd160Hash(data string) []byte { - return crypto.Ripemd160([]byte(data)) -} - -func namespaceSubjectKey(ns string, addr interop.Hash160) []byte { - prefix := namespaceSubjectPrefix(ns) - return append(prefix, addr...) -} - -func namespaceSubjectPrefix(ns string) []byte { - nsHash := ripemd160Hash(ns) - return append([]byte{namespaceSubjectsKeysPrefix}, nsHash...) -} - -func namespaceSubjectNameKey(ns, subjName string) []byte { - nsHash := ripemd160Hash(ns) - nameHash := ripemd160Hash(subjName) - return append([]byte{namespaceSubjectsNamesPrefix}, append(nsHash, nameHash...)...) -} - -func namespaceGroupNameKey(ns, groupName string) []byte { - nsHash := ripemd160Hash(ns) - nameHash := ripemd160Hash(groupName) - return append([]byte{namespaceGroupsNamesPrefix}, append(nsHash, nameHash...)...) -} - -func groupSubjectKey(ns string, groupID int, addr interop.Hash160) []byte { - prefix := groupSubjectPrefix(ns, groupID) - return append(prefix, addr...) -} - -func groupSubjectKeyFromHashes(nsHash, groupHash []byte, addr interop.Hash160) []byte { - prefix := groupSubjectPrefixFromHashes(nsHash, groupHash) - return append(prefix, addr...) -} - -func groupSubjectPrefix(ns string, groupID int) []byte { - nsHash := ripemd160Hash(ns) - return groupSubjectPrefixFromHashes(nsHash, idToBytes(groupID)) -} - -func groupSubjectPrefixFromHashes(nsHash, groupIDBytes []byte) []byte { - return append([]byte{groupSubjectsKeysPrefix}, append(nsHash, groupIDBytes...)...) -} - -// idToBytes converts i64 value to BE bytes. Panics if value is bigger than i64. -func idToBytes(itemID int) []byte { - b := convert.ToBytes(itemID) - ln := len(b) - if ln > 8 { - panic("item ID exceeds 8 byte limit") - } - zeros := make([]byte, 8-ln) - return append(b, zeros...) -} - -func addressKey(address []byte) []byte { - return append([]byte{addressPrefix}, address...) -} - -func migrateNamespacesState(ctx storage.Context) { - it := storage.Find(ctx, []byte{namespaceKeysPrefix}, storage.None) - - for iterator.Next(it) { - kv := iterator.Value(it).(struct { - Key []byte - Value []byte - }) - - oldNs := std.Deserialize(kv.Value).(struct { - Name string - }) - - newNs := Namespace{ - Name: oldNs.Name, - State: nsActiveState, - } - - namespaceData := std.Serialize(newNs) - storage.Put(ctx, string(kv.Key), namespaceData) - } -} - -func checkNamespaceState(name string) { - ns := GetNamespace(name) - if ns.State == nsFrozenState || ns.State == nsPurgeState { - panic("namespace is non-active") - } + return UserInfo{Keys: pubs} } diff --git a/go.mod b/go.mod index d144617..56e08fe 100644 --- a/go.mod +++ b/go.mod @@ -1,56 +1,10 @@ module git.frostfs.info/TrueCloudLab/frostfs-contract -go 1.22 +go 1.14 require ( - github.com/google/uuid v1.6.0 github.com/mr-tron/base58 v1.2.0 - github.com/nspcc-dev/neo-go v0.106.3 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec - github.com/stretchr/testify v1.9.0 - go.uber.org/zap v1.27.0 -) - -require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.8.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/golang/snappy v0.0.1 // indirect - github.com/gorilla/websocket v1.5.1 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/holiman/uint256 v1.2.4 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect - github.com/nspcc-dev/dbft v0.2.0 // indirect - github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 // indirect - github.com/nspcc-dev/rfc6979 v0.2.1 // indirect - github.com/pierrec/lz4 v2.6.1+incompatible // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.19.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/stretchr/objx v0.5.2 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect - github.com/twmb/murmur3 v1.1.8 // indirect - github.com/urfave/cli/v2 v2.27.2 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect - go.etcd.io/bbolt v1.3.9 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.19.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - rsc.io/tmplfunc v0.0.3 // indirect + github.com/nspcc-dev/neo-go v0.99.4 + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 + github.com/stretchr/testify v1.7.0 ) diff --git a/go.sum b/go.sum index 57d2589..9df8735 100644 --- a/go.sum +++ b/go.sum @@ -1,194 +1,730 @@ -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CityOfZion/neo-go v0.62.1-pre.0.20191114145240-e740fbe708f8/go.mod h1:MJCkWUBhi9pn/CrYO1Q3P687y2KeahrOPS9BD9LDGb0= +github.com/CityOfZion/neo-go v0.70.1-pre.0.20191209120015-fccb0085941e/go.mod h1:0enZl0az8xA6PVkwzEOwPWVJGqlt/GO4hA4kmQ5Xzig= +github.com/CityOfZion/neo-go v0.70.1-pre.0.20191212173117-32ac01130d4c/go.mod h1:JtlHfeqLywZLswKIKFnAp+yzezY4Dji9qlfQKB2OD/I= +github.com/CityOfZion/neo-go v0.71.1-pre.0.20200129171427-f773ec69fb84/go.mod h1:FLI526IrRWHmcsO+mHsCbj64pJZhwQFTLJZu+A4PGOA= +github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg= +github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs= +github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= -github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc= -github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= +github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-redis/redis v6.10.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= +github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/nspcc-dev/dbft v0.2.0 h1:sDwsQES600OSIMncV176t2SX5OvB14lzeOAyKFOkbMI= -github.com/nspcc-dev/dbft v0.2.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3YMoz49o= -github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk= -github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc= -github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU= -github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA= -github.com/nspcc-dev/neo-go v0.106.3 h1:HEyhgkjQY+HfBzotMJ12xx2VuOUphkngZ4kEkjvXDtE= -github.com/nspcc-dev/neo-go v0.106.3/go.mod h1:3vEwJ2ld12N7HRGCaH/l/7EwopplC/+8XdIdPDNmD/M= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= -github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no= -github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ= -github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM= -github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc= -github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4= -github.com/nspcc-dev/tzhash v1.7.2/go.mod h1:oHiH0qwmTsZkeVs7pvCS5cVXUaLhXxSFvnmnZ++ijm4= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw= +github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY= +github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= +github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ= +github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac/go.mod h1:U8MSnEShH+o5hexfWJdze6uMFJteP0ko7J2frO7Yu1Y= +github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647 h1:handGBjqVzRx7HD6152zsP8ZRxw083zCMbN0IlUaPQk= +github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647/go.mod h1:g9xisXmX9NP9MjioaTe862n9SlZTrP+6PVUWLBYOr98= +github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= +github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg= +github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= +github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= +github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= +github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg= +github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM= +github.com/nspcc-dev/neo-go v0.99.4 h1:8Y+SdRxksC72a4PNkcGCh/aaQinh9Gu+c5LilbcsXOI= +github.com/nspcc-dev/neo-go v0.99.4/go.mod h1:mKTolfRUfKjFso5HPvGSQtUZc70n0VKBMs16eGuC5gA= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= +github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= +github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ= +github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= +github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= +github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= +github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= +github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= +github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs= +github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4= +github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 h1:rpMCoRa7expLc9gMiOP724gz6YSykZzmMALR/CmiwnU= +github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40= +github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= +github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= +github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= -github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= -go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +github.com/twmb/murmur3 v1.1.5 h1:i9OLS9fkuLzBXjt6dptlAEyk58fJsSTXbRg3SgVyqgk= +github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180318012157-96caea41033d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/abiosoft/ishell.v2 v2.0.0/go.mod h1:sFp+cGtH6o4s1FtpVPTMcHq2yue+c4DGOVohJCPUzwY= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/netmap/config.yml b/netmap/config.yml index ed88ebc..df985cd 100644 --- a/netmap/config.yml +++ b/netmap/config.yml @@ -1,13 +1,5 @@ name: "Netmap" -safemethods: - - "config" - - "epoch" - - "listConfig" - - "netmap" - - "netmapCandidates" - - "snapshot" - - "snapshotByEpoch" - - "version" +safemethods: ["epoch", "netmap", "netmapCandidates", "snapshot", "snapshotByEpoch", "config", "listConfig", "version"] permissions: - methods: ["update", "newEpoch"] events: diff --git a/netmap/doc.go b/netmap/doc.go index 9df6c3c..c352699 100644 --- a/netmap/doc.go +++ b/netmap/doc.go @@ -29,17 +29,5 @@ in the network by invoking NewEpoch method. NewEpoch - name: epoch type: Integer - -# Contract storage scheme - - | Key | Value | Description | - |-----------------------------|------------|-----------------------------------| - | `snapshotCount` | int | snapshot count | - | `snapshotEpoch` | int | snapshot epoch | - | `snapshotBlock` | int | snapshot block | - | `snapshot_` + snapshotNum | ByteArray | serialized '[]Node' array | - | `snapshotCurrent` | int | current snapshot | - | `balanceScriptHash` | Hash160 | balance contract hash | - | `containerScriptHash` | Hash160 | container contract hash | */ package netmap diff --git a/netmap/netmap_contract.go b/netmap/netmap_contract.go index 1af6974..150c461 100644 --- a/netmap/netmap_contract.go +++ b/netmap/netmap_contract.go @@ -43,7 +43,8 @@ type Node struct { } const ( - innerRingKey = "innerring" + notaryDisabledKey = "notary" + innerRingKey = "innerring" // DefaultSnapshotCount contains the number of previous snapshots stored by this contract. // Must be less than 255. @@ -66,15 +67,19 @@ var ( ) // _deploy function sets up initial list of inner ring public keys. -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() - args := data.(struct { - addrBalance interop.Hash160 - addrContainer interop.Hash160 - keys []interop.PublicKey - config [][]byte - version int + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + + var args = data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version + notaryDisabled bool + addrBalance interop.Hash160 + addrContainer interop.Hash160 + keys []interop.PublicKey + config [][]byte + version int }) ln := len(args.config) @@ -117,12 +122,13 @@ func _deploy(data any, isUpdate bool) { // Update method updates contract source code and manifest. It can be invoked // only by committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { if !common.HasUpdateAccess() { panic("only committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("netmap contract updated") } @@ -426,7 +432,7 @@ func SnapshotByEpoch(epoch int) []Node { // Config returns configuration value of FrostFS configuration. If key does // not exists, returns nil. -func Config(key []byte) any { +func Config(key []byte) interface{} { ctx := storage.GetReadOnlyContext() return getConfig(ctx, key) } @@ -538,14 +544,14 @@ func getSnapshot(ctx storage.Context, key string) []Node { return []Node{} } -func getConfig(ctx storage.Context, key any) interface{} { +func getConfig(ctx storage.Context, key interface{}) interface{} { postfix := key.([]byte) storageKey := append(configPrefix, postfix...) return storage.Get(ctx, storageKey) } -func setConfig(ctx storage.Context, key, val any) { +func setConfig(ctx storage.Context, key, val interface{}) { postfix := key.([]byte) storageKey := append(configPrefix, postfix...) diff --git a/nns/README.md b/nns/README.md deleted file mode 100644 index 32a72bf..0000000 --- a/nns/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# NNS -NNS - Neo Name Service is a service that allows manage a domain name as a digital asset (NFT). It has an interface similar to `DNS` but has significant differences in its internal structure. - -## Entities: - -- Domain -- Record -- Owner -- Committee - -### Domain - -Domain is string that satisfies the following requirements: -- Length from 2 to 255 characters. -- Root domain must start with a letter. -- All other fragments must start and end with a letter or digit. - -Domain has owner, a registration period, and may optionally have records. - -A fee established by the committee is charged upon domain registration. After registration, the owner can manage this asset (add/delete records, transfer ownership to another owner) until the end of the domain registration period. - -### Record - -A record is a pair of values ``. - -Supported record types: - -| Type | Description | -|-------|-------------------------------------------| -| A | Represents address record type | -| AAA | Represents IPv6 address record type | -| TXT | Represents text record type | -| CNAME | Represents canonical name record type | -| SOA | Represents start of authority record type | - -### Owner - -An owner is a wallet that has the right to manage this NFT (domain). - -### Committee - -The committee makes new tokens (domains), sets, and charges a fee for issuance. - -## Globally Unique Domain Zone - -For more information, see [here](../docs/globally-unique-domain-zone.md). - -## NNS and Frostfsid - -You can register a TLD domain without a committee signature using Frostfsid. To do this, create a new wallet -``` -neo-go wallet init -w newwallet/wallet.json -``` - -Get wallet address: -``` -neo-go wallet dump-keys -w newwallet/wallet.json -[subject-address] -[subject-key] -``` - -Create a subject in `FrostfsID`: -``` -frostfs-adm morph frostfsid create-subject --subject-key="[subject-key]" -``` - -Grant permissions to the wallet: -``` -frostfs-adm morph nns give-privilege --subject-address="[subject-address]" -``` - -Register domain: -``` -neo-go contract invokefunction [NNS-hash] register "subdomain.domain" hash160:[subject-address] "email@frostfs.info" 10000 1000 1000 1000 -- [subject-address]:Global -``` \ No newline at end of file diff --git a/nns/config.yml b/nns/config.yml index 54fc073..75a111d 100644 --- a/nns/config.yml +++ b/nns/config.yml @@ -2,35 +2,8 @@ name: "NameService" supportedstandards: ["NEP-11"] safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties", "roots", "getPrice", "isAvailable", "getRecords", - "getAllRecords", "resolve", "version"] events: - - name: RegisterDomain - parameters: - - name: name - type: String - - name: AddRecord - parameters: - - name: name - type: String - - name: type - type: Integer - - name: DeleteRecord - parameters: - - name: name - type: String - - name: type - type: Integer - - name: DeleteRecords - parameters: - - name: name - type: String - - name: type - type: Integer - - name: DeleteDomain - parameters: - - name: name - type: String - name: Transfer parameters: - name: from diff --git a/nns/doc.go b/nns/doc.go deleted file mode 100644 index 787cca4..0000000 --- a/nns/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* - -# Contract storage scheme - - | Key | Value | Description | - |--------------------------------------|------------|-----------------------------------| - | 0x0 | int | total supply of minted domains | - | 0x1 + accountAddr | int | account's balance | - | 0x2 + accountAddr + tokenKey | ByteArray | token ID | - | 0x10 | int | price for domain registration | - | 0x20 | int | set of roots | - | 0x21 + tokenKey | ByteArray | serialized NameState struct | - | 0x22 + tokenKey + Hash160(tokenName) | Hash160 | container contract hash | - | 0x23 + tokenKey + Hash160(tokenName) | string | global domain flag | - -*/ - -package nns diff --git a/nns/frostfsid.go b/nns/frostfsid.go deleted file mode 100644 index fcc2d87..0000000 --- a/nns/frostfsid.go +++ /dev/null @@ -1,39 +0,0 @@ -package nns - -import ( - "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/native/management" - "github.com/nspcc-dev/neo-go/pkg/interop/native/std" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" -) - -const FrostfsIDNNSName = "frostfsid.frostfs" - -const ( - FrostfsIDNNSTLDPermissionKey = "nns-allow-register-tld" - FrostfsIDTLDRegistrationAllowed = "allow" -) - -func checkFrostfsID(ctx storage.Context, addr interop.Hash160) bool { - if len(addr) == 0 { - return false - } - - frostfsIDAddress := getRecordsByType(ctx, []byte(tokenIDFromName(FrostfsIDNNSName)), FrostfsIDNNSName, TXT) - if len(frostfsIDAddress) < 2 { - return false - } - - decodedBytes := std.Base58Decode([]byte(frostfsIDAddress[1])) - - if len(decodedBytes) < 21 || management.GetContract(decodedBytes[1:21]) == nil { - return false - } - - if res := contract.Call(decodedBytes[1:21], "getSubjectKV", contract.ReadOnly, addr, FrostfsIDNNSTLDPermissionKey).(string); res == FrostfsIDTLDRegistrationAllowed { - return true - } - - return false -} diff --git a/nns/namestate.go b/nns/namestate.go index ea186c8..72bbf94 100644 --- a/nns/namestate.go +++ b/nns/namestate.go @@ -7,14 +7,19 @@ import ( // NameState represents domain name state. type NameState struct { - Owner interop.Hash160 - Name string - // Expiration field used to contain wall-clock time of a domain expiration. - // It is preserved for backwards compatibility, but is unused by the contract and should be ignored. + Owner interop.Hash160 + Name string Expiration int64 Admin interop.Hash160 } +// ensureNotExpired panics if domain name is expired. +func (n NameState) ensureNotExpired() { + if int64(runtime.GetTime()) >= n.Expiration { + panic("name has expired") + } +} + // checkAdmin panics if script container is not signed by the domain name admin. func (n NameState) checkAdmin() { if runtime.CheckWitness(n.Owner) { diff --git a/nns/nns.yml b/nns/nns.yml new file mode 100644 index 0000000..289793c --- /dev/null +++ b/nns/nns.yml @@ -0,0 +1,20 @@ +name: "NameService" +supportedstandards: ["NEP-11"] +safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", + "tokens", "properties", "roots", "getPrice", "isAvailable", "getRecord", + "resolve", "getAllRecords"] +events: + - name: Transfer + parameters: + - name: from + type: Hash160 + - name: to + type: Hash160 + - name: amount + type: Integer + - name: tokenId + type: ByteArray +permissions: + - hash: fffdc93764dbaddd97c48f252a53ea4643faa3fd + methods: ["update"] + - methods: ["onNEP11Payment"] diff --git a/nns/nns_contract.go b/nns/nns_contract.go index 9185e45..bf75fdf 100644 --- a/nns/nns_contract.go +++ b/nns/nns_contract.go @@ -41,14 +41,6 @@ const ( // prefixRecord contains map from (token key + hash160(token name) + record type) // to record. prefixRecord byte = 0x22 - // prefixGlobalDomain contains a flag indicating that this domain was created using GlobalDomain. - // This is necessary to distinguish it from regular CNAME records. - prefixGlobalDomain byte = 0x23 - // prefixCountSubDomains contains information about the number of domains in the zone. - // If it is nil, it will definitely be calculated on the first removal. - prefixCountSubDomains byte = 0x24 - // prefixAutoCreated contains a flag indicating whether the TLD domain was created automatically. - prefixAutoCreated = 0x25 ) // Values constraints. @@ -60,7 +52,7 @@ const ( // maxDomainNameFragmentLength is the maximum length of the domain name fragment. maxDomainNameFragmentLength = 63 // minDomainNameLength is minimum domain length. - minDomainNameLength = 2 + minDomainNameLength = 3 // maxDomainNameLength is maximum domain length. maxDomainNameLength = 255 // maxTXTRecordLength is the maximum length of the TXT domain record. @@ -73,14 +65,6 @@ const ( defaultRegisterPrice = 10_0000_0000 // millisecondsInYear is amount of milliseconds per year. millisecondsInYear = int64(365 * 24 * 3600 * 1000) - // errInvalidDomainName is an error message for invalid domain name format. - errInvalidDomainName = "invalid domain name format" -) - -const ( - // Cnametgt is a special TXT record ensuring all created subdomains point to the global domain - the value of this variable. - // It is guaranteed that two domains cannot point to the same global domain. - Cnametgt = "cnametgt" ) // RecordState is a type that registered entities are saved to. @@ -92,20 +76,21 @@ type RecordState struct { } // Update updates NameService contract. -func Update(nef []byte, manifest string, data any) { +func Update(nef []byte, manifest string, data interface{}) { checkCommittee() // Calculating keys and serializing requires calling // std and crypto contracts. This can be helpful on update // thus we provide `AllowCall` to management.Update. // management.Update(nef, []byte(manifest)) - management.UpdateWithData(nef, []byte(manifest), common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, nef, manifest, common.AppendVersion(data)) runtime.Log("nns contract updated") } // _deploy initializes defaults (total supply and registration price) on contract deploy. -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } @@ -144,11 +129,12 @@ func OwnerOf(tokenID []byte) interop.Hash160 { } // Properties returns a domain name and an expiration date of the specified domain. -func Properties(tokenID []byte) map[string]any { +func Properties(tokenID []byte) map[string]interface{} { ctx := storage.GetReadOnlyContext() ns := getNameState(ctx, tokenID) - return map[string]any{ - "name": ns.Name, + return map[string]interface{}{ + "name": ns.Name, + "expiration": ns.Expiration, } } @@ -181,7 +167,7 @@ func TokensOf(owner interop.Hash160) iterator.Iterator { } // Transfer transfers the domain with the specified name to a new owner. -func Transfer(to interop.Hash160, tokenID []byte, data any) bool { +func Transfer(to interop.Hash160, tokenID []byte, data interface{}) bool { if !isValid(to) { panic(`invalid receiver`) } @@ -234,129 +220,69 @@ func GetPrice() int { // IsAvailable checks whether the provided domain name is available. func IsAvailable(name string) bool { - fragments := splitAndCheck(name) + fragments := splitAndCheck(name, false) + if fragments == nil { + panic("invalid domain name format") + } ctx := storage.GetReadOnlyContext() l := len(fragments) if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[l-1])...)) == nil { + if l != 1 { + panic("TLD not found") + } return true } - - checkParent(ctx, fragments) - checkAvailableGlobalDomain(ctx, name) - return storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) == nil + return parentExpired(ctx, 0, fragments) } -// checkAvailableGlobalDomain - triggers a panic if the global domain name is occupied. -func checkAvailableGlobalDomain(ctx storage.Context, domain string) { - globalDomain := getGlobalDomain(ctx, domain) - if globalDomain == "" { - return - } - - nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(globalDomain))...)) - if nsBytes != nil { - panic("global domain is already taken: " + globalDomain + ". Domain: " + domain) - } -} - -// getGlobalDomain returns the global domain. -func getGlobalDomain(ctx storage.Context, domain string) string { - index := std.MemorySearch([]byte(domain), []byte(".")) - - if index == -1 { - return "" - } - - name := domain[index+1:] - if name == "" { - return "" - } - - return extractCnametgt(ctx, name, domain) -} - -// extractCnametgt returns the value of the Cnametgt TXT record. -func extractCnametgt(ctx storage.Context, name, domain string) string { - fragments := splitAndCheck(domain) - - tokenID := []byte(tokenIDFromName(name)) - records := getRecordsByType(ctx, tokenID, name, TXT) - - if records == nil { - return "" - } - - globalDomain := "" - for _, name := range records { - fragments := std.StringSplit(name, "=") - if len(fragments) != 2 { - continue - } - - if fragments[0] == Cnametgt { - globalDomain = fragments[1] - break - } - } - - if globalDomain == "" { - return "" - } - return fragments[0] + "." + globalDomain -} - -// checkParent returns parent domain or empty string if domain not found. -func checkParent(ctx storage.Context, fragments []string) string { +// parentExpired returns true if any domain from fragments doesn't exist or is expired. +// first denotes the deepest subdomain to check. +func parentExpired(ctx storage.Context, first int, fragments []string) bool { + now := int64(runtime.GetTime()) last := len(fragments) - 1 name := fragments[last] - parent := "" - for i := last; i > 0; i-- { + for i := last; i >= first; i-- { if i != last { name = fragments[i] + "." + name } nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) if nsBytes == nil { - continue + return true + } + ns := std.Deserialize(nsBytes.([]byte)).(NameState) + if now >= ns.Expiration { + return true } - parent = name } - return parent + return false } // Register registers a new domain with the specified owner and name if it's available. func Register(name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool { + fragments := splitAndCheck(name, true) + if fragments == nil { + panic("invalid domain name format") + } + + l := len(fragments) + tldKey := append([]byte{prefixRoot}, []byte(fragments[l-1])...) ctx := storage.GetContext() - return register(ctx, name, owner, email, refresh, retry, expire, ttl) -} - -// Register registers a new domain with the specified owner and name if it's available. -func register(ctx storage.Context, name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool { - fragments := splitAndCheck(name) - countZone := len(fragments) - rootZone := []byte(fragments[countZone-1]) - tldKey := append([]byte{prefixRoot}, rootZone...) - tldBytes := storage.Get(ctx, tldKey) - if countZone == 1 { - checkCommitteeAndFrostfsID(ctx, owner) + if l == 1 { + checkCommittee() if tldBytes != nil { panic("TLD already exists") } storage.Put(ctx, tldKey, 0) } else { - parent := checkParent(ctx, fragments) - if parent == "" { - parent = fragments[len(fragments)-1] - - storage.Put(ctx, append([]byte{prefixAutoCreated}, rootZone...), true) - register(ctx, parent, owner, email, refresh, retry, expire, ttl) + if tldBytes == nil { + panic("TLD not found") } - - parentKey := getTokenKey([]byte(parent)) + if parentExpired(ctx, 1, fragments) { + panic("one of the parent domains is not registered") + } + parentKey := getTokenKey([]byte(name[len(fragments[0])+1:])) nsBytes := storage.Get(ctx, append([]byte{prefixName}, parentKey...)) - if nsBytes == nil { - panic("parent does not exist:" + parent) - } ns := std.Deserialize(nsBytes.([]byte)).(NameState) ns.checkAdmin() @@ -384,30 +310,46 @@ func register(ctx storage.Context, name string, owner interop.Hash160, email str nsBytes := storage.Get(ctx, append([]byte{prefixName}, tokenKey...)) if nsBytes != nil { ns := std.Deserialize(nsBytes.([]byte)).(NameState) + if int64(runtime.GetTime()) < ns.Expiration { + return false + } oldOwner = ns.Owner updateBalance(ctx, []byte(name), oldOwner, -1) } else { updateTotalSupply(ctx, +1) } ns := NameState{ - Owner: owner, - Name: name, - Expiration: 0, + Owner: owner, + Name: name, + // NNS expiration is in milliseconds + Expiration: int64(runtime.GetTime() + expire*1000), } - checkAvailableGlobalDomain(ctx, name) - - updateSubdDomainCounter(ctx, rootZone, countZone) putNameStateWithKey(ctx, tokenKey, ns) putSoaRecord(ctx, name, email, refresh, retry, expire, ttl) updateBalance(ctx, []byte(name), owner, +1) postTransfer(oldOwner, owner, []byte(name), nil) - runtime.Notify("RegisterDomain", name) return true } +// Renew increases domain expiration date. +func Renew(name string) int64 { + if len(name) > maxDomainNameLength { + panic("invalid domain name format") + } + runtime.BurnGas(GetPrice()) + ctx := storage.GetContext() + ns := getNameState(ctx, []byte(name)) + ns.checkAdmin() + ns.Expiration += millisecondsInYear + putNameState(ctx, ns) + return ns.Expiration +} + // UpdateSOA updates soa record. func UpdateSOA(name, email string, refresh, retry, expire, ttl int) { - checkDomainNameLength(name) + if len(name) > maxDomainNameLength { + panic("invalid domain name format") + } ctx := storage.GetContext() ns := getNameState(ctx, []byte(name)) ns.checkAdmin() @@ -416,7 +358,9 @@ func UpdateSOA(name, email string, refresh, retry, expire, ttl int) { // SetAdmin updates domain admin. func SetAdmin(name string, admin interop.Hash160) { - checkDomainNameLength(name) + if len(name) > maxDomainNameLength { + panic("invalid domain name format") + } if admin != nil && !runtime.CheckWitness(admin) { panic("not witnessed by admin") } @@ -445,7 +389,7 @@ func checkBaseRecords(typ RecordType, data string) bool { case A: return checkIPv4(data) case CNAME: - return splitAndCheck(data) != nil + return splitAndCheck(data, true) != nil case TXT: return len(data) <= maxTXTRecordLength case AAAA: @@ -479,26 +423,13 @@ func GetRecords(name string, typ RecordType) []string { // DeleteRecords removes domain records with the specified type. func DeleteRecords(name string, typ RecordType) { - ctx := storage.GetContext() - deleteRecords(ctx, name, typ) -} - -// DeleteRecords removes domain records with the specified type. -func deleteRecords(ctx storage.Context, name string, typ RecordType) { if typ == SOA { panic("you cannot delete soa record") } tokenID := []byte(tokenIDFromName(name)) + ctx := storage.GetContext() ns := getNameState(ctx, tokenID) ns.checkAdmin() - - globalDomainStorage := append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...) - globalDomainRaw := storage.Get(ctx, globalDomainStorage) - globalDomain := globalDomainRaw.(string) - if globalDomainRaw != nil && globalDomain != "" { - deleteDomain(ctx, globalDomain) - } - recordsKey := getRecordsKeyByType(tokenID, name, typ) records := storage.Find(ctx, recordsKey, storage.KeysOnly) for iterator.Next(records) { @@ -506,126 +437,6 @@ func deleteRecords(ctx storage.Context, name string, typ RecordType) { storage.Delete(ctx, r) } updateSoaSerial(ctx, tokenID) - runtime.Notify("DeleteRecords", name, typ) -} - -// DeleteRecord delete a record of the specified type by data in the provided domain. -// Returns false if the record was not found. -func DeleteRecord(name string, typ RecordType, data string) bool { - tokenID := []byte(tokenIDFromName(name)) - if !checkBaseRecords(typ, data) { - panic("invalid record data") - } - ctx := storage.GetContext() - ns := getNameState(ctx, tokenID) - ns.checkAdmin() - return deleteRecord(ctx, tokenID, name, typ, data) -} - -func deleteRecord(ctx storage.Context, tokenId []byte, name string, typ RecordType, data string) bool { - recordsKey := getRecordsKeyByType(tokenId, name, typ) - - var previousKey any - it := storage.Find(ctx, recordsKey, storage.KeysOnly) - for iterator.Next(it) { - key := iterator.Value(it).([]byte) - ss := storage.Get(ctx, key).([]byte) - - ns := std.Deserialize(ss).(RecordState) - if ns.Name == name && ns.Type == typ && ns.Data == data { - previousKey = key - continue - } - - if previousKey != nil { - data := storage.Get(ctx, key) - storage.Put(ctx, previousKey, data) - previousKey = key - } - } - - if previousKey == nil { - return false - } - - storage.Delete(ctx, previousKey) - runtime.Notify("DeleteRecord", name, typ) - return true -} - -// DeleteDomain deletes the domain with the given name. -func DeleteDomain(name string) { - ctx := storage.GetContext() - deleteDomain(ctx, name) -} - -func countSubdomains(name string) int { - countSubDomains := 0 - it := Tokens() - for iterator.Next(it) { - domain := iterator.Value(it) - if std.MemorySearch([]byte(domain.(string)), []byte(name)) > 0 { - countSubDomains = countSubDomains + 1 - } - } - return countSubDomains -} - -func deleteDomain(ctx storage.Context, name string) { - fragments := splitAndCheck(name) - parent := []byte(fragments[len(fragments)-1]) - countSubDomainsKey := append([]byte{prefixCountSubDomains}, parent...) - autoCreatedPrefix := append([]byte{prefixAutoCreated}, parent...) - - nsKey := append([]byte{prefixName}, getTokenKey([]byte(name))...) - nsRaw := storage.Get(ctx, nsKey) - if nsRaw == nil { - panic("domain not found") - } - - ns := std.Deserialize(nsRaw.([]byte)).(NameState) - ns.checkAdmin() - - countSubDomain := 0 - countSubDomainRaw := storage.Get(ctx, countSubDomainsKey) - if countSubDomainRaw != nil { - countSubDomain = common.FromFixedWidth64(countSubDomainRaw.([]byte)) - } else { - countSubDomain = countSubdomains(fragments[len(fragments)-1]) - } - - if countSubDomain > 1 && len(fragments) == 1 { - panic("can't delete TLD domain that has subdomains") - } - - countSubDomain = countSubDomain - 1 - storage.Put(ctx, countSubDomainsKey, common.ToFixedWidth64(countSubDomain)) - - globalNSKey := append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...) - globalDomainRaw := storage.Get(ctx, globalNSKey) - globalDomain := globalDomainRaw.(string) - if globalDomainRaw != nil && globalDomain != "" { - deleteDomain(ctx, globalDomain) - } - - deleteRecords(ctx, name, CNAME) - deleteRecords(ctx, name, TXT) - deleteRecords(ctx, name, A) - deleteRecords(ctx, name, AAAA) - storage.Delete(ctx, nsKey) - storage.Delete(ctx, append([]byte{prefixRoot}, []byte(name)...)) - - isAutoCreated := storage.Get(ctx, autoCreatedPrefix) - if countSubDomain == 1 && isAutoCreated != nil && isAutoCreated.(bool) { - deleteDomain(ctx, fragments[len(fragments)-1]) - } - - if len(fragments) == 1 { - storage.Delete(ctx, countSubDomainsKey) - storage.Delete(ctx, autoCreatedPrefix) - } - - runtime.Notify("DeleteDomain", name) } // Resolve resolves given name (not more then three redirects are allowed). @@ -648,13 +459,13 @@ func updateBalance(ctx storage.Context, tokenId []byte, acc interop.Hash160, dif balanceKey := append([]byte{prefixBalance}, acc...) var balance int if b := storage.Get(ctx, balanceKey); b != nil { - balance = common.FromFixedWidth64(b.([]byte)) + balance = b.(int) } balance += diff if balance == 0 { storage.Delete(ctx, balanceKey) } else { - storage.Put(ctx, balanceKey, common.ToFixedWidth64(balance)) + storage.Put(ctx, balanceKey, balance) } tokenKey := getTokenKey(tokenId) @@ -668,7 +479,7 @@ func updateBalance(ctx storage.Context, tokenId []byte, acc interop.Hash160, dif // postTransfer sends Transfer notification to the network and calls onNEP11Payment // method. -func postTransfer(from, to interop.Hash160, tokenID []byte, data any) { +func postTransfer(from, to interop.Hash160, tokenID []byte, data interface{}) { runtime.Notify("Transfer", from, to, 1, tokenID) if management.GetContract(to) != nil { contract.Call(to, "onNEP11Payment", contract.All, from, 1, tokenID, data) @@ -678,14 +489,14 @@ func postTransfer(from, to interop.Hash160, tokenID []byte, data any) { // getTotalSupply returns total supply from storage. func getTotalSupply(ctx storage.Context) int { val := storage.Get(ctx, []byte{prefixTotalSupply}) - return common.FromFixedWidth64(val.([]byte)) + return val.(int) } // updateTotalSupply adds the specified diff to the total supply. func updateTotalSupply(ctx storage.Context, diff int) { tsKey := []byte{prefixTotalSupply} ts := getTotalSupply(ctx) - storage.Put(ctx, tsKey, common.ToFixedWidth64(ts+diff)) + storage.Put(ctx, tsKey, ts+diff) } // getTokenKey computes hash160 from the given tokenID. @@ -698,7 +509,9 @@ func getNameState(ctx storage.Context, tokenID []byte) NameState { tokenKey := getTokenKey(tokenID) ns := getNameStateWithKey(ctx, tokenKey) fragments := std.StringSplit(string(tokenID), ".") - checkParent(ctx, fragments) + if parentExpired(ctx, 1, fragments) { + panic("parent domain has expired") + } return ns } @@ -709,7 +522,9 @@ func getNameStateWithKey(ctx storage.Context, tokenKey []byte) NameState { if nsBytes == nil { panic("token not found") } - return std.Deserialize(nsBytes.([]byte)).(NameState) + ns := std.Deserialize(nsBytes.([]byte)).(NameState) + ns.ensureNotExpired() + return ns } // putNameState stores domain name state. @@ -766,33 +581,6 @@ func addRecord(ctx storage.Context, tokenId []byte, name string, typ RecordType, } } - globalDomainKey := append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...) - globalDomainStorage := storage.Get(ctx, globalDomainKey) - globalDomain := getGlobalDomain(ctx, name) - - if globalDomainStorage == nil && typ == TXT { - if globalDomain != "" { - checkAvailableGlobalDomain(ctx, name) - nsOriginal := getNameState(ctx, []byte(tokenIDFromName(name))) - ns := NameState{ - Name: globalDomain, - Owner: nsOriginal.Owner, - Expiration: 0, - Admin: nsOriginal.Admin, - } - - putNameStateWithKey(ctx, getTokenKey([]byte(globalDomain)), ns) - storage.Put(ctx, globalDomainKey, globalDomain) - - var oldOwner interop.Hash160 - updateBalance(ctx, []byte(name), nsOriginal.Owner, +1) - postTransfer(oldOwner, nsOriginal.Owner, []byte(name), nil) - putCnameRecord(ctx, globalDomain, name) - } else { - storage.Put(ctx, globalDomainKey, "") - } - } - if typ == CNAME && id != 0 { panic("you shouldn't have more than one CNAME record") } @@ -811,7 +599,6 @@ func storeRecord(ctx storage.Context, recordKey []byte, name string, typ RecordT } recBytes := std.Serialize(rs) storage.Put(ctx, recordKey, recBytes) - runtime.Notify("AddRecord", name, typ) } // putSoaRecord stores soa domain record. @@ -832,24 +619,6 @@ func putSoaRecord(ctx storage.Context, name, email string, refresh, retry, expir } recBytes := std.Serialize(rs) storage.Put(ctx, recordKey, recBytes) - runtime.Notify("AddRecord", name, SOA) -} - -// putCnameRecord stores CNAME domain record. -func putCnameRecord(ctx storage.Context, name, data string) { - var id byte - tokenId := []byte(tokenIDFromName(name)) - recordKey := getIdRecordKey(tokenId, name, CNAME, id) - - rs := RecordState{ - Name: name, - Type: CNAME, - ID: id, - Data: data, - } - recBytes := std.Serialize(rs) - storage.Put(ctx, recordKey, recBytes) - runtime.Notify("AddRecord", name, CNAME) } // updateSoaSerial stores soa domain record. @@ -859,7 +628,7 @@ func updateSoaSerial(ctx storage.Context, tokenId []byte) { recBytes := storage.Get(ctx, recordKey) if recBytes == nil { - return + panic("not found soa record") } rec := std.Deserialize(recBytes.([]byte)).(RecordState) @@ -900,14 +669,6 @@ func isValid(address interop.Hash160) bool { return address != nil && len(address) == interop.Hash160Len } -// checkCommitteeAndFrostfsID panics if the script container is not signed by the committee. -// or if the owner does not have permission in FrostfsID. -func checkCommitteeAndFrostfsID(ctx storage.Context, owner interop.Hash160) { - if !checkFrostfsID(ctx, owner) { - checkCommittee() - } -} - // checkCommittee panics if the script container is not signed by the committee. func checkCommittee() { committee := neo.GetCommittee() @@ -956,29 +717,24 @@ func isAlNum(c uint8) bool { } // splitAndCheck splits domain name into parts and validates it. -func splitAndCheck(name string) []string { - checkDomainNameLength(name) +func splitAndCheck(name string, allowMultipleFragments bool) []string { + l := len(name) + if l < minDomainNameLength || maxDomainNameLength < l { + return nil + } fragments := std.StringSplit(name, ".") - l := len(fragments) + l = len(fragments) + if l > 2 && !allowMultipleFragments { + return nil + } for i := 0; i < l; i++ { if !checkFragment(fragments[i], i == l-1) { - panic(errInvalidDomainName + " '" + name + "': invalid fragment '" + fragments[i] + "'") + return nil } } return fragments } -// checkDomainNameLength panics if domain name length is out of boundaries. -func checkDomainNameLength(name string) { - l := len(name) - if l > maxDomainNameLength { - panic(errInvalidDomainName + " '" + name + "': domain name too long: got = " + std.Itoa(l, 10) + ", max = " + std.Itoa(maxDomainNameLength, 10)) - } - if l < minDomainNameLength { - panic(errInvalidDomainName + " '" + name + "': domain name too short: got = " + std.Itoa(l, 10) + ", min = " + std.Itoa(minDomainNameLength, 10)) - } -} - // checkIPv4 checks record on IPv4 compliance. func checkIPv4(data string) bool { l := len(data) @@ -1091,17 +847,23 @@ func checkIPv6(data string) bool { // tokenIDFromName returns token ID (domain.root) from the provided name. func tokenIDFromName(name string) string { - fragments := splitAndCheck(name) + fragments := splitAndCheck(name, true) + if fragments == nil { + panic("invalid domain name format") + } ctx := storage.GetReadOnlyContext() sum := 0 - l := len(fragments) + l := len(fragments) - 1 for i := 0; i < l; i++ { tokenKey := getTokenKey([]byte(name[sum:])) nameKey := append([]byte{prefixName}, tokenKey...) nsBytes := storage.Get(ctx, nameKey) if nsBytes != nil { - return name[sum:] + ns := std.Deserialize(nsBytes.([]byte)).(NameState) + if int64(runtime.GetTime()) < ns.Expiration { + return name[sum:] + } } sum += len(fragments[i]) + 1 } @@ -1147,16 +909,3 @@ func getAllRecords(ctx storage.Context, name string) iterator.Iterator { recordsKey := getRecordsKey(tokenID, name) return storage.Find(ctx, recordsKey, storage.ValuesOnly|storage.DeserializeValues) } - -func updateSubdDomainCounter(ctx storage.Context, rootZone []byte, countZone int) { - countSubDomain := 0 - delInfoRaw := storage.Get(ctx, append([]byte{prefixCountSubDomains}, rootZone...)) - if delInfoRaw != nil { - countSubDomain = common.FromFixedWidth64(delInfoRaw.([]byte)) - } - - if delInfoRaw != nil || countZone == 1 { - countSubDomain = countSubDomain + 1 - storage.Put(ctx, append([]byte{prefixCountSubDomains}, rootZone...), common.ToFixedWidth64(countSubDomain)) - } -} diff --git a/policy/config.yml b/policy/config.yml deleted file mode 100644 index 921d853..0000000 --- a/policy/config.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: "APE" -permissions: - - methods: ["update"] -safemethods: - - "getAdmin" - - "listChains" - - "getChain" - - "listChainsByPrefix" - - "listTargets" - - "listChainNames" - - "iteratorChainsByPrefix" - - "version" \ No newline at end of file diff --git a/policy/doc.go b/policy/doc.go deleted file mode 100644 index d537585..0000000 --- a/policy/doc.go +++ /dev/null @@ -1,14 +0,0 @@ -/* - -# Contract storage scheme - - | Key | Value | Description | - |------------------------------------------|--------|-----------------------------------| - | 'c' + uint16(len(container)) + container | []byte | Namespace chain | - | 'n' + uint16(len(namespace)) + namespace | []byte | Container chain | - | 'm' + entity name (namespace/container) | []byte | Mapped name to an encoded number | - | 'Counter' | uint64 | Integer counter used for mapping | - -*/ - -package policy diff --git a/policy/policy_contract.go b/policy/policy_contract.go deleted file mode 100644 index 10f8cd7..0000000 --- a/policy/policy_contract.go +++ /dev/null @@ -1,317 +0,0 @@ -package policy - -import ( - "git.frostfs.info/TrueCloudLab/frostfs-contract/common" - "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid" - "git.frostfs.info/TrueCloudLab/frostfs-contract/nns" - "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/management" - "github.com/nspcc-dev/neo-go/pkg/interop/native/std" - "github.com/nspcc-dev/neo-go/pkg/interop/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" -) - -// Kind represents the object the chain is attached to. -// Currently only namespace and container are supported. -type Kind byte - -const ( - Namespace = 'n' - Container = 'c' - User = 'u' - Group = 'g' - IAM = 'i' -) - -const ( - ownerKeyPrefix = 'o' -) - -const ( - mappingKeyPrefix = 'm' - counterKey = "Counter" -) - -const ( - // ErrNotAuthorized is returned when the none of the transaction signers - // belongs to the list of autorized keys. - ErrNotAuthorized = "none of the signers is authorized to change the contract" -) - -const ( - purgeNsState = "purge" - frozenNsState = "frozen" -) - -// _deploy function sets up initial list of inner ring public keys. -func _deploy(data any, isUpdate bool) { - if isUpdate { - args := data.([]any) - common.CheckVersion(args[len(args)-1].(int)) - return - } - - args := data.(struct { - Admin interop.Hash160 - }) - ctx := storage.GetContext() - if args.Admin != nil { - if len(args.Admin) != 20 { - panic("invalid admin hash length") - } - storage.Put(ctx, []byte{ownerKeyPrefix}, args.Admin) - } - storage.Put(ctx, counterKey, 0) -} - -func checkAuthorization(ctx storage.Context) { - admin := getAdmin(ctx) - if admin != nil && runtime.CheckWitness(admin) { - return - } - if runtime.CheckWitness(common.AlphabetAddress()) { - return - } - - panic(ErrNotAuthorized) -} - -// Version returns the version of the contract. -func Version() int { - return common.Version -} - -// Update method updates contract source code and manifest. It can be invoked -// by committee only. -func Update(script []byte, manifest []byte, data any) { - if !common.HasUpdateAccess() { - panic("only committee can update contract") - } - - management.UpdateWithData(script, manifest, common.AppendVersion(data)) - runtime.Log("policy contract updated") -} - -func SetAdmin(addr interop.Hash160) { - common.CheckAlphabetWitness() - - ctx := storage.GetContext() - storage.Put(ctx, []byte{ownerKeyPrefix}, addr) -} - -func GetAdmin() interop.Hash160 { - ctx := storage.GetReadOnlyContext() - return getAdmin(ctx) -} - -func getAdmin(ctx storage.Context) interop.Hash160 { - return storage.Get(ctx, []byte{ownerKeyPrefix}).(interop.Hash160) -} - -func storageKey(prefix Kind, counter int, name []byte) []byte { - key := append([]byte{byte(prefix)}, common.ToFixedWidth64(counter)...) - return append(key, name...) -} - -func mapKey(kind Kind, name []byte) []byte { - return append([]byte{mappingKeyPrefix, byte(kind)}, name...) -} - -// mapToNumeric maps a name to a number. That allows to keep more space in -// a storage key shortening long names. Short entity -// names are also mapped to prevent collisions in the map. -func mapToNumeric(ctx storage.Context, kind Kind, name []byte) (mapped int, mappingExists bool) { - mKey := mapKey(kind, name) - numericID := storage.Get(ctx, mKey) - if numericID == nil { - return 0, false - } - mapped = numericID.(int) - mappingExists = true - return -} - -// mapToNumericCreateIfNotExists maps a name to a number. That allows to keep -// more space in a storage key shortening long names. Short entity -// names are also mapped to prevent collisions in the map. -// If a mapping cannot be found, then the method creates and returns it. -// mapToNumericCreateIfNotExists is NOT applicable for a read-only context. -func mapToNumericCreateIfNotExists(ctx storage.Context, kind Kind, name []byte) int { - mKey := mapKey(kind, name) - numericID := storage.Get(ctx, mKey) - if numericID == nil { - counter := storage.Get(ctx, counterKey).(int) - counter++ - storage.Put(ctx, counterKey, counter) - storage.Put(ctx, mKey, counter) - return counter - } - return numericID.(int) -} - -func checkChainNamespace(entity Kind, name string) { - if entity != Namespace { - return - } - frostfsidAddr := getContractHash(nns.FrostfsIDNNSName) - if frostfsidAddr == nil || management.GetContract(frostfsidAddr) == nil { - panic("could not get frostfsid contract") - } - ns := contract.Call(frostfsidAddr, "getNamespace", contract.ReadOnly, name).(frostfsid.Namespace) - if ns.State == purgeNsState || ns.State == frozenNsState { - panic("namespace is non-active") - } -} - -// getContractHash returns nil when it can't resolve contract name, -// so custom error message can be thrown. -func getContractHash(name string) interop.Hash160 { - nnsContract := management.GetContractByID(1) - records := contract.Call(nnsContract.Hash, "getRecords", contract.ReadOnly, name, nns.TXT).([]string) - for _, record := range records { - contractHash := readContractHashFromNNSRecord(record) - if contractHash != nil { - return contractHash - } - } - return nil -} - -func readContractHashFromNNSRecord(nnsResponse string) interop.Hash160 { - // 40 is size of hex encoded contract hash as string - if len(nnsResponse) == 40 { - return nil - } - - decoded := std.Base58Decode([]byte(nnsResponse)) - if len(decoded) != common.AddressLen || management.GetContract(decoded[1:21]) == nil { - return nil - } - return decoded[1:21] -} - -func AddChain(entity Kind, entityName string, name []byte, chain []byte) { - ctx := storage.GetContext() - checkAuthorization(ctx) - checkChainNamespace(entity, entityName) - - entityNameBytes := mapToNumericCreateIfNotExists(ctx, entity, []byte(entityName)) - key := storageKey(entity, entityNameBytes, name) - storage.Put(ctx, key, chain) -} - -func GetChain(entity Kind, entityName string, name []byte) []byte { - ctx := storage.GetReadOnlyContext() - - entityNameBytes, exists := mapToNumeric(ctx, entity, []byte(entityName)) - if !exists { - panic("not found") - } - - key := storageKey(entity, entityNameBytes, name) - data := storage.Get(ctx, key).([]byte) - if data == nil { - panic("not found") - } - - return data -} - -func RemoveChain(entity Kind, entityName string, name []byte) { - ctx := storage.GetContext() - checkAuthorization(ctx) - - entityNameNum, exists := mapToNumeric(ctx, entity, []byte(entityName)) - if !exists { - return - } - - key := storageKey(entity, entityNameNum, name) - storage.Delete(ctx, key) - - // If no chains are left for the target, then remove the mapping. - prefix := append([]byte{byte(entity)}, common.ToFixedWidth64(entityNameNum)...) - it := storage.Find(ctx, prefix, storage.KeysOnly) - if !iterator.Next(it) { - storage.Delete(ctx, mapKey(entity, []byte(entityName))) - } -} - -func RemoveChainsByPrefix(entity Kind, entityName string, name []byte) { - ctx := storage.GetContext() - checkAuthorization(ctx) - - entityNameNum, exists := mapToNumeric(ctx, entity, []byte(entityName)) - if !exists { - return - } - - key := storageKey(entity, entityNameNum, name) - it := storage.Find(ctx, key, storage.KeysOnly) - for iterator.Next(it) { - storage.Delete(ctx, iterator.Value(it).([]byte)) - } - - // If no chains are left for the target, then remove the mapping. - prefix := append([]byte{byte(entity)}, common.ToFixedWidth64(entityNameNum)...) - it = storage.Find(ctx, prefix, storage.KeysOnly) - if !iterator.Next(it) { - storage.Delete(ctx, mapKey(entity, []byte(entityName))) - } -} - -// ListChains lists all chains for the namespace by prefix. -// container may be empty. -func ListChains(namespace, container string, name []byte) [][]byte { - result := ListChainsByPrefix(Namespace, namespace, name) - - if container != "" { - result = append(result, ListChainsByPrefix(Container, container, name)...) - } - - return result -} - -// ListChainsByPrefix list all chains for the provided kind and entity by prefix. -func ListChainsByPrefix(entity Kind, entityName string, prefix []byte) [][]byte { - ctx := storage.GetReadOnlyContext() - - result := [][]byte{} - - entityNameBytes, exists := mapToNumeric(ctx, entity, []byte(entityName)) - if !exists { - return result - } - - keyPrefix := storageKey(entity, entityNameBytes, prefix) - it := storage.Find(ctx, keyPrefix, storage.ValuesOnly) - for iterator.Next(it) { - result = append(result, iterator.Value(it).([]byte)) - } - - return result -} - -func IteratorChainsByPrefix(entity Kind, entityName string, prefix []byte) iterator.Iterator { - ctx := storage.GetReadOnlyContext() - id, _ := mapToNumeric(ctx, entity, []byte(entityName)) - keyPrefix := storageKey(entity, id, prefix) - return storage.Find(ctx, keyPrefix, storage.ValuesOnly) -} - -// ListTargets iterates over targets for which rules are defined. -func ListTargets(entity Kind) iterator.Iterator { - ctx := storage.GetReadOnlyContext() - mKey := mapKey(entity, []byte{}) - return storage.Find(ctx, mKey, storage.KeysOnly|storage.RemovePrefix) -} - -// ListChainNames iterates over chain names for specific target. -func ListChainNames(entity Kind, entityName string) iterator.Iterator { - ctx := storage.GetReadOnlyContext() - id, _ := mapToNumeric(ctx, entity, []byte(entityName)) - keyPrefix := storageKey(entity, id, []byte{}) - return storage.Find(ctx, keyPrefix, storage.KeysOnly|storage.RemovePrefix) -} diff --git a/processing/doc.go b/processing/doc.go index fa2d4f0..f6a4979 100644 --- a/processing/doc.go +++ b/processing/doc.go @@ -18,11 +18,5 @@ execution. # Contract notifications Processing contract does not produce notifications to process. - -# Contract storage scheme - - | Key | Value | Description | - |-----------------------------|------------|----------------------------------| - | `frostfsScriptHash` | Hash160 | frostFS contract hash | */ package processing diff --git a/processing/processing_contract.go b/processing/processing_contract.go index 0ea4f2e..f96ffa6 100644 --- a/processing/processing_contract.go +++ b/processing/processing_contract.go @@ -3,34 +3,54 @@ package processing import ( "git.frostfs.info/TrueCloudLab/frostfs-contract/common" "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/native/gas" "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" "github.com/nspcc-dev/neo-go/pkg/interop/native/roles" "github.com/nspcc-dev/neo-go/pkg/interop/runtime" + "github.com/nspcc-dev/neo-go/pkg/interop/storage" +) + +const ( + frostfsContractKey = "frostfsScriptHash" + + multiaddrMethod = "alphabetAddress" ) // OnNEP17Payment is a callback for NEP-17 compatible native GAS contract. -func OnNEP17Payment(from interop.Hash160, amount int, data any) { +func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { caller := runtime.GetCallingScriptHash() if !common.BytesEqual(caller, []byte(gas.Hash)) { common.AbortWithMessage("processing contract accepts GAS only") } } -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } + args := data.(struct { + addrFrostFS interop.Hash160 + }) + + ctx := storage.GetContext() + + if len(args.addrFrostFS) != interop.Hash160Len { + panic("incorrect length of contract script hash") + } + + storage.Put(ctx, frostfsContractKey, args.addrFrostFS) + runtime.Log("processing contract initialized") } // Update method updates contract source code and manifest. It can be invoked // only by the sidechain committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { blockHeight := ledger.CurrentIndex() alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1)) alphabetCommittee := common.Multiaddress(alphabetKeys, true) @@ -39,14 +59,19 @@ func Update(script []byte, manifest []byte, data any) { panic("only side chain committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("processing contract updated") } // Verify method returns true if transaction contains valid multisignature of // Alphabet nodes of the Inner Ring. func Verify() bool { - return runtime.CheckWitness(common.AlphabetAddress()) + ctx := storage.GetContext() + frostfsContractAddr := storage.Get(ctx, frostfsContractKey).(interop.Hash160) + multiaddr := contract.Call(frostfsContractAddr, multiaddrMethod, contract.ReadOnly).(interop.Hash160) + + return runtime.CheckWitness(multiaddr) } // Version returns the version of the contract. diff --git a/proxy/doc.go b/proxy/doc.go index 2a261cc..3201a92 100644 --- a/proxy/doc.go +++ b/proxy/doc.go @@ -17,9 +17,5 @@ verified, Proxy contract pays for the execution. # Contract notifications Proxy contract does not produce notifications to process. - -# Contract storage scheme - -Proxy contract does not use storage */ package proxy diff --git a/proxy/proxy_contract.go b/proxy/proxy_contract.go index 613bc17..3d22ad6 100644 --- a/proxy/proxy_contract.go +++ b/proxy/proxy_contract.go @@ -3,34 +3,24 @@ package proxy import ( "git.frostfs.info/TrueCloudLab/frostfs-contract/common" "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/native/gas" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" + "github.com/nspcc-dev/neo-go/pkg/interop/native/neo" "github.com/nspcc-dev/neo-go/pkg/interop/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) -const accountKeyPrefix = 'a' - // OnNEP17Payment is a callback for NEP-17 compatible native GAS contract. -func OnNEP17Payment(from interop.Hash160, amount int, data any) { +func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { caller := runtime.GetCallingScriptHash() if !common.BytesEqual(caller, []byte(gas.Hash)) { common.AbortWithMessage("proxy contract accepts GAS only") } } -// OnNEP11Payment is a callback for NEP-11 compatible NNS contract. -func OnNEP11Payment(from interop.Hash160, amount int, token []byte, data any) { - caller := runtime.GetCallingScriptHash() - nnsHash := management.GetContractByID(1).Hash - if !common.BytesEqual(caller, []byte(nnsHash)) { - common.AbortWithMessage("proxy contract accepts NNS tokens only") - } -} - -func _deploy(data any, isUpdate bool) { +func _deploy(data interface{}, isUpdate bool) { if isUpdate { - args := data.([]any) + args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } @@ -40,56 +30,31 @@ func _deploy(data any, isUpdate bool) { // Update method updates contract source code and manifest. It can be invoked // only by committee. -func Update(script []byte, manifest []byte, data any) { +func Update(script []byte, manifest []byte, data interface{}) { if !common.HasUpdateAccess() { panic("only committee can update contract") } - management.UpdateWithData(script, manifest, common.AppendVersion(data)) + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) runtime.Log("proxy contract updated") } // Verify method returns true if transaction contains valid multisignature of -// Alphabet nodes of the Inner Ring or any of the trusted accounts added via AddAccount. +// Alphabet nodes of the Inner Ring. func Verify() bool { - if !runtime.GetScriptContainer().Sender.Equals(runtime.GetExecutingScriptHash()) { - return false + alphabet := neo.GetCommittee() + sig := common.Multiaddress(alphabet, false) + + if !runtime.CheckWitness(sig) { + sig = common.Multiaddress(alphabet, true) + return runtime.CheckWitness(sig) } - signers := runtime.CurrentSigners() - ctx := storage.GetReadOnlyContext() - for i := 1; /* skip sender */ i < len(signers); i++ { - if storage.Get(ctx, append([]byte{accountKeyPrefix}, signers[i].Account...)) != nil { - return true - } - } - - if runtime.CheckWitness(common.CommitteeAddress()) { - return true - } - - if runtime.CheckWitness(common.AlphabetAddress()) { - return true - } - - return false + return true } // Version returns the version of the contract. func Version() int { return common.Version } - -func AddAccount(addr interop.Hash160) { - common.CheckWitness(common.CommitteeAddress()) - - ctx := storage.GetContext() - storage.Put(ctx, append([]byte{accountKeyPrefix}, addr...), []byte{1}) -} - -func RemoveAccount(addr interop.Hash160) { - common.CheckWitness(common.CommitteeAddress()) - - ctx := storage.GetContext() - storage.Delete(ctx, append([]byte{accountKeyPrefix}, addr...)) -} diff --git a/reputation/config.yml b/reputation/config.yml new file mode 100644 index 0000000..ffe98c6 --- /dev/null +++ b/reputation/config.yml @@ -0,0 +1,13 @@ +name: "Reputation" +safemethods: ["get", "getByID", "listByEpoch"] +permissions: + - methods: ["update"] +events: + - name: reputationPut + parameters: + - name: epoch + type: Integer + - name: peerID + type: ByteArray + - name: value + type: ByteArray diff --git a/reputation/doc.go b/reputation/doc.go new file mode 100644 index 0000000..ad253af --- /dev/null +++ b/reputation/doc.go @@ -0,0 +1,17 @@ +/* +Reputation contract is a contract deployed in FrostFS sidechain. + +Inner Ring nodes produce data audit for each container during each epoch. In the end, +nodes produce DataAuditResult structure that contains information about audit +progress. Reputation contract provides storage for such structures and simple +interface to iterate over available DataAuditResults on specified epoch. + +During settlement process, Alphabet nodes fetch all DataAuditResult structures +from the epoch and execute balance transfers from data owners to Storage and +Inner Ring nodes if data audit succeeds. + +# Contract notifications + +Reputation contract does not produce notifications to process. +*/ +package reputation diff --git a/reputation/reputation_contract.go b/reputation/reputation_contract.go new file mode 100644 index 0000000..2055204 --- /dev/null +++ b/reputation/reputation_contract.go @@ -0,0 +1,125 @@ +package reputation + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-contract/common" + "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/convert" + "github.com/nspcc-dev/neo-go/pkg/interop/iterator" + "github.com/nspcc-dev/neo-go/pkg/interop/native/management" + "github.com/nspcc-dev/neo-go/pkg/interop/runtime" + "github.com/nspcc-dev/neo-go/pkg/interop/storage" +) + +const ( + notaryDisabledKey = "notary" + reputationValuePrefix = 'r' + reputationCountPrefix = 'c' +) + +func _deploy(data interface{}, isUpdate bool) { + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + + if isUpdate { + args := data.([]interface{}) + common.CheckVersion(args[len(args)-1].(int)) + return + } + + runtime.Log("reputation contract initialized") +} + +// Update method updates contract source code and manifest. It can be invoked +// only by committee. +func Update(script []byte, manifest []byte, data interface{}) { + if !common.HasUpdateAccess() { + panic("only committee can update contract") + } + + contract.Call(interop.Hash160(management.Hash), "update", + contract.All, script, manifest, common.AppendVersion(data)) + runtime.Log("reputation contract updated") +} + +// Put method saves DataAuditResult in contract storage. It can be invoked only by +// Inner Ring nodes. It does not require multisignature invocations. +// +// Epoch is the epoch number when DataAuditResult structure was generated. +// PeerID contains public keys of the Inner Ring node that has produced DataAuditResult. +// Value contains a stable marshaled structure of DataAuditResult. +func Put(epoch int, peerID []byte, value []byte) { + ctx := storage.GetContext() + + multiaddr := common.AlphabetAddress() + if !runtime.CheckWitness(multiaddr) { + runtime.Notify("reputationPut", epoch, peerID, value) + return + } + + id := storageID(epoch, peerID) + key := getReputationKey(reputationCountPrefix, id) + rawCnt := storage.Get(ctx, key) + cnt := 0 + if rawCnt != nil { + cnt = rawCnt.(int) + } + cnt++ + storage.Put(ctx, key, cnt) + + key[0] = reputationValuePrefix + key = append(key, convert.ToBytes(cnt)...) + storage.Put(ctx, key, value) +} + +// Get method returns a list of all stable marshaled DataAuditResult structures +// produced by the specified Inner Ring node during the specified epoch. +func Get(epoch int, peerID []byte) [][]byte { + id := storageID(epoch, peerID) + return GetByID(id) +} + +// GetByID method returns a list of all stable marshaled DataAuditResult with +// the specified id. Use ListByEpoch method to obtain the id. +func GetByID(id []byte) [][]byte { + ctx := storage.GetReadOnlyContext() + + var data [][]byte + + it := storage.Find(ctx, getReputationKey(reputationValuePrefix, id), storage.ValuesOnly) + for iterator.Next(it) { + data = append(data, iterator.Value(it).([]byte)) + } + return data +} + +func getReputationKey(prefix byte, id []byte) []byte { + return append([]byte{prefix}, id...) +} + +// ListByEpoch returns a list of IDs that may be used to get reputation data +// with GetByID method. +func ListByEpoch(epoch int) [][]byte { + ctx := storage.GetReadOnlyContext() + key := getReputationKey(reputationCountPrefix, convert.ToBytes(epoch)) + it := storage.Find(ctx, key, storage.KeysOnly) + + var result [][]byte + + for iterator.Next(it) { + key := iterator.Value(it).([]byte) // iterator MUST BE `storage.KeysOnly` + result = append(result, key[1:]) + } + + return result +} + +// Version returns the version of the contract. +func Version() int { + return common.Version +} + +func storageID(epoch int, peerID []byte) []byte { + var buf interface{} = epoch + + return append(buf.([]byte), peerID...) +} diff --git a/rpcclient/alphabet/client.go b/rpcclient/alphabet/client.go deleted file mode 100644 index 4b2e05e..0000000 --- a/rpcclient/alphabet/client.go +++ /dev/null @@ -1,138 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package alphabet contains RPC wrappers for Alphabet contract. -package alphabet - -import ( - "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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "math/big" -) - -// Invoker is used by ContractReader to call various safe methods. -type Invoker interface { - Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// Gas invokes `gas` method of contract. -func (c *ContractReader) Gas() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "gas")) -} - -// Name invokes `name` method of contract. -func (c *ContractReader) Name() (string, error) { - return unwrap.UTF8String(c.invoker.Call(c.hash, "name")) -} - -// Neo invokes `neo` method of contract. -func (c *ContractReader) Neo() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "neo")) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// Emit creates a transaction invoking `emit` 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) Emit() (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "emit") -} - -// EmitTransaction creates a transaction invoking `emit` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) EmitTransaction() (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "emit") -} - -// EmitUnsigned creates a transaction invoking `emit` 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) EmitUnsigned() (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "emit", nil) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} - -// Vote creates a transaction invoking `vote` 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) Vote(epoch *big.Int, candidates []any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "vote", epoch, candidates) -} - -// VoteTransaction creates a transaction invoking `vote` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) VoteTransaction(epoch *big.Int, candidates []any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "vote", epoch, candidates) -} - -// VoteUnsigned creates a transaction invoking `vote` 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) VoteUnsigned(epoch *big.Int, candidates []any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "vote", nil, epoch, candidates) -} diff --git a/rpcclient/balance/client.go b/rpcclient/balance/client.go deleted file mode 100644 index 6b86502..0000000 --- a/rpcclient/balance/client.go +++ /dev/null @@ -1,549 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package balance contains RPC wrappers for Balance contract. -package balance - -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/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" -) - -// LockEvent represents "Lock" event emitted by the contract. -type LockEvent struct { - TxID []byte - From util.Uint160 - To util.Uint160 - Amount *big.Int - Until *big.Int -} - -// TransferXEvent represents "TransferX" event emitted by the contract. -type TransferXEvent struct { - From util.Uint160 - To util.Uint160 - Amount *big.Int - Details []byte -} - -// MintEvent represents "Mint" event emitted by the contract. -type MintEvent struct { - To util.Uint160 - Amount *big.Int -} - -// BurnEvent represents "Burn" event emitted by the contract. -type BurnEvent struct { - From util.Uint160 - Amount *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 provided contract hash and the given Invoker. -func NewReader(invoker Invoker, hash util.Uint160) *ContractReader { - return &ContractReader{*nep17.NewReader(invoker, hash), invoker, hash} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - var nep17t = nep17.New(actor, hash) - return &Contract{ContractReader{nep17t.TokenReader, actor, hash}, nep17t.TokenWriter, actor, hash} -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// Burn creates a transaction invoking `burn` 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) Burn(from util.Uint160, amount *big.Int, txDetails []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "burn", from, amount, txDetails) -} - -// BurnTransaction creates a transaction invoking `burn` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) BurnTransaction(from util.Uint160, amount *big.Int, txDetails []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "burn", from, amount, txDetails) -} - -// BurnUnsigned creates a transaction invoking `burn` 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) BurnUnsigned(from util.Uint160, amount *big.Int, txDetails []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "burn", nil, from, amount, txDetails) -} - -// Lock creates a transaction invoking `lock` 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) Lock(txDetails []byte, from util.Uint160, to util.Uint160, amount *big.Int, until *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "lock", txDetails, from, to, amount, until) -} - -// LockTransaction creates a transaction invoking `lock` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) LockTransaction(txDetails []byte, from util.Uint160, to util.Uint160, amount *big.Int, until *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "lock", txDetails, from, to, amount, until) -} - -// LockUnsigned creates a transaction invoking `lock` 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) LockUnsigned(txDetails []byte, from util.Uint160, to util.Uint160, amount *big.Int, until *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "lock", nil, txDetails, from, to, amount, until) -} - -// 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(to util.Uint160, amount *big.Int, txDetails []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "mint", to, amount, txDetails) -} - -// 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(to util.Uint160, amount *big.Int, txDetails []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "mint", to, amount, txDetails) -} - -// 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(to util.Uint160, amount *big.Int, txDetails []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "mint", nil, to, amount, txDetails) -} - -// NewEpoch creates a transaction invoking `newEpoch` 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) NewEpoch(epochNum *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "newEpoch", epochNum) -} - -// NewEpochTransaction creates a transaction invoking `newEpoch` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) NewEpochTransaction(epochNum *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "newEpoch", epochNum) -} - -// NewEpochUnsigned creates a transaction invoking `newEpoch` 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) NewEpochUnsigned(epochNum *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "newEpoch", nil, epochNum) -} - -// TransferX creates a transaction invoking `transferX` 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) TransferX(from util.Uint160, to util.Uint160, amount *big.Int, details []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "transferX", from, to, amount, details) -} - -// TransferXTransaction creates a transaction invoking `transferX` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) TransferXTransaction(from util.Uint160, to util.Uint160, amount *big.Int, details []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "transferX", from, to, amount, details) -} - -// TransferXUnsigned creates a transaction invoking `transferX` 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) TransferXUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, details []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "transferX", nil, from, to, amount, details) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} - -// LockEventsFromApplicationLog retrieves a set of all emitted events -// with "Lock" name from the provided [result.ApplicationLog]. -func LockEventsFromApplicationLog(log *result.ApplicationLog) ([]*LockEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*LockEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Lock" { - continue - } - event := new(LockEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize LockEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to LockEvent or -// returns an error if it's not possible to do to so. -func (e *LockEvent) 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) != 5 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.TxID, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field TxID: %w", err) - } - - 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.Until, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Until: %w", err) - } - - return nil -} - -// TransferXEventsFromApplicationLog retrieves a set of all emitted events -// with "TransferX" name from the provided [result.ApplicationLog]. -func TransferXEventsFromApplicationLog(log *result.ApplicationLog) ([]*TransferXEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*TransferXEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "TransferX" { - continue - } - event := new(TransferXEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize TransferXEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to TransferXEvent or -// returns an error if it's not possible to do to so. -func (e *TransferXEvent) 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.Details, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Details: %w", err) - } - - return nil -} - -// MintEventsFromApplicationLog retrieves a set of all emitted events -// with "Mint" name from the provided [result.ApplicationLog]. -func MintEventsFromApplicationLog(log *result.ApplicationLog) ([]*MintEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*MintEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Mint" { - continue - } - event := new(MintEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize MintEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to MintEvent or -// returns an error if it's not possible to do to so. -func (e *MintEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - 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) - } - - return nil -} - -// BurnEventsFromApplicationLog retrieves a set of all emitted events -// with "Burn" name from the provided [result.ApplicationLog]. -func BurnEventsFromApplicationLog(log *result.ApplicationLog) ([]*BurnEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*BurnEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Burn" { - continue - } - event := new(BurnEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize BurnEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to BurnEvent or -// returns an error if it's not possible to do to so. -func (e *BurnEvent) 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) != 2 { - 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.Amount, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Amount: %w", err) - } - - return nil -} diff --git a/rpcclient/container/client.go b/rpcclient/container/client.go deleted file mode 100644 index 85b428a..0000000 --- a/rpcclient/container/client.go +++ /dev/null @@ -1,693 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package container contains RPC wrappers for Container contract. -package container - -import ( - "crypto/elliptic" - "errors" - "fmt" - "github.com/google/uuid" - "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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "math/big" -) - -// PutSuccessEvent represents "PutSuccess" event emitted by the contract. -type PutSuccessEvent struct { - ContainerID util.Uint256 - PublicKey *keys.PublicKey -} - -// DeleteSuccessEvent represents "DeleteSuccess" event emitted by the contract. -type DeleteSuccessEvent struct { - ContainerID util.Uint256 -} - -// SetEACLSuccessEvent represents "SetEACLSuccess" event emitted by the contract. -type SetEACLSuccessEvent struct { - ContainerID []byte - PublicKey *keys.PublicKey -} - -// StartEstimationEvent represents "StartEstimation" event emitted by the contract. -type StartEstimationEvent struct { - Epoch *big.Int -} - -// StopEstimationEvent represents "StopEstimation" event emitted by the contract. -type StopEstimationEvent struct { - Epoch *big.Int -} - -// 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) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// ContainersOf invokes `containersOf` method of contract. -func (c *ContractReader) ContainersOf(owner []byte) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "containersOf", owner)) -} - -// ContainersOfExpanded is similar to ContainersOf (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) ContainersOfExpanded(owner []byte, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "containersOf", _numOfIteratorItems, owner)) -} - -// Count invokes `count` method of contract. -func (c *ContractReader) Count() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "count")) -} - -// DeletionInfo invokes `deletionInfo` method of contract. -func (c *ContractReader) DeletionInfo(containerID []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "deletionInfo", containerID)) -} - -// EACL invokes `eACL` method of contract. -func (c *ContractReader) EACL(containerID []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "eACL", containerID)) -} - -// Get invokes `get` method of contract. -func (c *ContractReader) Get(containerID []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "get", containerID)) -} - -// GetContainerSize invokes `getContainerSize` method of contract. -func (c *ContractReader) GetContainerSize(id []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getContainerSize", id)) -} - -// IterateContainerSizes invokes `iterateContainerSizes` method of contract. -func (c *ContractReader) IterateContainerSizes(epoch *big.Int) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "iterateContainerSizes", epoch)) -} - -// IterateContainerSizesExpanded is similar to IterateContainerSizes (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) IterateContainerSizesExpanded(epoch *big.Int, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "iterateContainerSizes", _numOfIteratorItems, epoch)) -} - -// List invokes `list` method of contract. -func (c *ContractReader) List(owner []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "list", owner)) -} - -// ListContainerSizes invokes `listContainerSizes` method of contract. -func (c *ContractReader) ListContainerSizes(epoch *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "listContainerSizes", epoch)) -} - -// Owner invokes `owner` method of contract. -func (c *ContractReader) Owner(containerID []byte) ([]byte, error) { - return unwrap.Bytes(c.invoker.Call(c.hash, "owner", containerID)) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// Delete creates a transaction invoking `delete` 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) Delete(containerID util.Uint256, signature []byte, publicKey *keys.PublicKey, token []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "delete", containerID, signature, publicKey, token) -} - -// DeleteTransaction creates a transaction invoking `delete` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteTransaction(containerID util.Uint256, signature []byte, publicKey *keys.PublicKey, token []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "delete", containerID, signature, publicKey, token) -} - -// DeleteUnsigned creates a transaction invoking `delete` 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) DeleteUnsigned(containerID util.Uint256, signature []byte, publicKey *keys.PublicKey, token []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "delete", nil, containerID, signature, publicKey, token) -} - -// NewEpoch creates a transaction invoking `newEpoch` 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) NewEpoch(epochNum *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "newEpoch", epochNum) -} - -// NewEpochTransaction creates a transaction invoking `newEpoch` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) NewEpochTransaction(epochNum *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "newEpoch", epochNum) -} - -// NewEpochUnsigned creates a transaction invoking `newEpoch` 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) NewEpochUnsigned(epochNum *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "newEpoch", nil, epochNum) -} - -// Put creates a transaction invoking `put` 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) Put(container []byte, signature []byte, publicKey *keys.PublicKey, token []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "put", container, signature, publicKey, token) -} - -// PutTransaction creates a transaction invoking `put` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) PutTransaction(container []byte, signature []byte, publicKey *keys.PublicKey, token []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "put", container, signature, publicKey, token) -} - -// PutUnsigned creates a transaction invoking `put` 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) PutUnsigned(container []byte, signature []byte, publicKey *keys.PublicKey, token []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "put", nil, container, signature, publicKey, token) -} - -// PutContainerSize creates a transaction invoking `putContainerSize` 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) PutContainerSize(epoch *big.Int, cid []byte, usedSize *big.Int, pubKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "putContainerSize", epoch, cid, usedSize, pubKey) -} - -// PutContainerSizeTransaction creates a transaction invoking `putContainerSize` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) PutContainerSizeTransaction(epoch *big.Int, cid []byte, usedSize *big.Int, pubKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "putContainerSize", epoch, cid, usedSize, pubKey) -} - -// PutContainerSizeUnsigned creates a transaction invoking `putContainerSize` 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) PutContainerSizeUnsigned(epoch *big.Int, cid []byte, usedSize *big.Int, pubKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "putContainerSize", nil, epoch, cid, usedSize, pubKey) -} - -// PutNamed creates a transaction invoking `putNamed` 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) PutNamed(container []byte, signature []byte, publicKey *keys.PublicKey, token []byte, name string, zone string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "putNamed", container, signature, publicKey, token, name, zone) -} - -// PutNamedTransaction creates a transaction invoking `putNamed` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) PutNamedTransaction(container []byte, signature []byte, publicKey *keys.PublicKey, token []byte, name string, zone string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "putNamed", container, signature, publicKey, token, name, zone) -} - -// PutNamedUnsigned creates a transaction invoking `putNamed` 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) PutNamedUnsigned(container []byte, signature []byte, publicKey *keys.PublicKey, token []byte, name string, zone string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "putNamed", nil, container, signature, publicKey, token, name, zone) -} - -// 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(admin util.Uint160) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setAdmin", 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(admin util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setAdmin", 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(admin util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setAdmin", nil, admin) -} - -// SetEACL creates a transaction invoking `setEACL` 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) SetEACL(eACL []byte, signature []byte, publicKey *keys.PublicKey, token []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setEACL", eACL, signature, publicKey, token) -} - -// SetEACLTransaction creates a transaction invoking `setEACL` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetEACLTransaction(eACL []byte, signature []byte, publicKey *keys.PublicKey, token []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setEACL", eACL, signature, publicKey, token) -} - -// SetEACLUnsigned creates a transaction invoking `setEACL` 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) SetEACLUnsigned(eACL []byte, signature []byte, publicKey *keys.PublicKey, token []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setEACL", nil, eACL, signature, publicKey, token) -} - -// StartContainerEstimation creates a transaction invoking `startContainerEstimation` 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) StartContainerEstimation(epoch *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "startContainerEstimation", epoch) -} - -// StartContainerEstimationTransaction creates a transaction invoking `startContainerEstimation` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) StartContainerEstimationTransaction(epoch *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "startContainerEstimation", epoch) -} - -// StartContainerEstimationUnsigned creates a transaction invoking `startContainerEstimation` 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) StartContainerEstimationUnsigned(epoch *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "startContainerEstimation", nil, epoch) -} - -// StopContainerEstimation creates a transaction invoking `stopContainerEstimation` 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) StopContainerEstimation(epoch *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "stopContainerEstimation", epoch) -} - -// StopContainerEstimationTransaction creates a transaction invoking `stopContainerEstimation` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) StopContainerEstimationTransaction(epoch *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "stopContainerEstimation", epoch) -} - -// StopContainerEstimationUnsigned creates a transaction invoking `stopContainerEstimation` 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) StopContainerEstimationUnsigned(epoch *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "stopContainerEstimation", nil, epoch) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} - -// PutSuccessEventsFromApplicationLog retrieves a set of all emitted events -// with "PutSuccess" name from the provided [result.ApplicationLog]. -func PutSuccessEventsFromApplicationLog(log *result.ApplicationLog) ([]*PutSuccessEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*PutSuccessEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "PutSuccess" { - continue - } - event := new(PutSuccessEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize PutSuccessEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to PutSuccessEvent or -// returns an error if it's not possible to do to so. -func (e *PutSuccessEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.ContainerID, err = func(item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field ContainerID: %w", err) - } - - index++ - e.PublicKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field PublicKey: %w", err) - } - - return nil -} - -// DeleteSuccessEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteSuccess" name from the provided [result.ApplicationLog]. -func DeleteSuccessEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteSuccessEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteSuccessEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteSuccess" { - continue - } - event := new(DeleteSuccessEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteSuccessEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteSuccessEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteSuccessEvent) 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.ContainerID, err = func(item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field ContainerID: %w", err) - } - - return nil -} - -// SetEACLSuccessEventsFromApplicationLog retrieves a set of all emitted events -// with "SetEACLSuccess" name from the provided [result.ApplicationLog]. -func SetEACLSuccessEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetEACLSuccessEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*SetEACLSuccessEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "SetEACLSuccess" { - continue - } - event := new(SetEACLSuccessEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize SetEACLSuccessEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to SetEACLSuccessEvent or -// returns an error if it's not possible to do to so. -func (e *SetEACLSuccessEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.ContainerID, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field ContainerID: %w", err) - } - - index++ - e.PublicKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field PublicKey: %w", err) - } - - return nil -} - -// StartEstimationEventsFromApplicationLog retrieves a set of all emitted events -// with "StartEstimation" name from the provided [result.ApplicationLog]. -func StartEstimationEventsFromApplicationLog(log *result.ApplicationLog) ([]*StartEstimationEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*StartEstimationEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "StartEstimation" { - continue - } - event := new(StartEstimationEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize StartEstimationEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to StartEstimationEvent or -// returns an error if it's not possible to do to so. -func (e *StartEstimationEvent) 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.Epoch, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Epoch: %w", err) - } - - return nil -} - -// StopEstimationEventsFromApplicationLog retrieves a set of all emitted events -// with "StopEstimation" name from the provided [result.ApplicationLog]. -func StopEstimationEventsFromApplicationLog(log *result.ApplicationLog) ([]*StopEstimationEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*StopEstimationEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "StopEstimation" { - continue - } - event := new(StopEstimationEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize StopEstimationEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to StopEstimationEvent or -// returns an error if it's not possible to do to so. -func (e *StopEstimationEvent) 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.Epoch, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Epoch: %w", err) - } - - return nil -} diff --git a/rpcclient/frostfs/client.go b/rpcclient/frostfs/client.go deleted file mode 100644 index 057ae40..0000000 --- a/rpcclient/frostfs/client.go +++ /dev/null @@ -1,769 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package frostfs contains RPC wrappers for FrostFS contract. -package frostfs - -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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "math/big" -) - -// DepositEvent represents "Deposit" event emitted by the contract. -type DepositEvent struct { - From util.Uint160 - Amount *big.Int - Receiver util.Uint160 - TxHash util.Uint256 -} - -// WithdrawEvent represents "Withdraw" event emitted by the contract. -type WithdrawEvent struct { - User util.Uint160 - Amount *big.Int - TxHash util.Uint256 -} - -// ChequeEvent represents "Cheque" event emitted by the contract. -type ChequeEvent struct { - Id []byte - User util.Uint160 - Amount *big.Int - LockAccount []byte -} - -// BindEvent represents "Bind" event emitted by the contract. -type BindEvent struct { - User []byte - Keys []any -} - -// UnbindEvent represents "Unbind" event emitted by the contract. -type UnbindEvent struct { - User []byte - Keys []any -} - -// SetConfigEvent represents "SetConfig" event emitted by the contract. -type SetConfigEvent struct { - Id []byte - Key []byte - Value []byte -} - -// Invoker is used by ContractReader to call various safe methods. -type Invoker interface { - Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// Config invokes `config` method of contract. -func (c *ContractReader) Config(key []byte) (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, "config", key))) -} - -// InnerRingCandidates invokes `innerRingCandidates` method of contract. -func (c *ContractReader) InnerRingCandidates() ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "innerRingCandidates")) -} - -// ListConfig invokes `listConfig` method of contract. -func (c *ContractReader) ListConfig() ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "listConfig")) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// Bind creates a transaction invoking `bind` 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) Bind(user []byte, keys []any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "bind", user, keys) -} - -// BindTransaction creates a transaction invoking `bind` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) BindTransaction(user []byte, keys []any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "bind", user, keys) -} - -// BindUnsigned creates a transaction invoking `bind` 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) BindUnsigned(user []byte, keys []any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "bind", nil, user, keys) -} - -// Cheque creates a transaction invoking `cheque` 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) Cheque(id []byte, user util.Uint160, amount *big.Int, lockAcc []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "cheque", id, user, amount, lockAcc) -} - -// ChequeTransaction creates a transaction invoking `cheque` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) ChequeTransaction(id []byte, user util.Uint160, amount *big.Int, lockAcc []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "cheque", id, user, amount, lockAcc) -} - -// ChequeUnsigned creates a transaction invoking `cheque` 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) ChequeUnsigned(id []byte, user util.Uint160, amount *big.Int, lockAcc []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "cheque", nil, id, user, amount, lockAcc) -} - -// InnerRingCandidateAdd creates a transaction invoking `innerRingCandidateAdd` 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) InnerRingCandidateAdd(key *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "innerRingCandidateAdd", key) -} - -// InnerRingCandidateAddTransaction creates a transaction invoking `innerRingCandidateAdd` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) InnerRingCandidateAddTransaction(key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "innerRingCandidateAdd", key) -} - -// InnerRingCandidateAddUnsigned creates a transaction invoking `innerRingCandidateAdd` 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) InnerRingCandidateAddUnsigned(key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "innerRingCandidateAdd", nil, key) -} - -// InnerRingCandidateRemove creates a transaction invoking `innerRingCandidateRemove` 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) InnerRingCandidateRemove(key *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "innerRingCandidateRemove", key) -} - -// InnerRingCandidateRemoveTransaction creates a transaction invoking `innerRingCandidateRemove` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) InnerRingCandidateRemoveTransaction(key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "innerRingCandidateRemove", key) -} - -// InnerRingCandidateRemoveUnsigned creates a transaction invoking `innerRingCandidateRemove` 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) InnerRingCandidateRemoveUnsigned(key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "innerRingCandidateRemove", nil, key) -} - -// SetConfig creates a transaction invoking `setConfig` 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) SetConfig(id []byte, key []byte, val []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setConfig", id, key, val) -} - -// SetConfigTransaction creates a transaction invoking `setConfig` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetConfigTransaction(id []byte, key []byte, val []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setConfig", id, key, val) -} - -// SetConfigUnsigned creates a transaction invoking `setConfig` 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) SetConfigUnsigned(id []byte, key []byte, val []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setConfig", nil, id, key, val) -} - -// Unbind creates a transaction invoking `unbind` 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) Unbind(user []byte, keys []any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "unbind", user, keys) -} - -// UnbindTransaction creates a transaction invoking `unbind` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UnbindTransaction(user []byte, keys []any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "unbind", user, keys) -} - -// UnbindUnsigned creates a transaction invoking `unbind` 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) UnbindUnsigned(user []byte, keys []any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "unbind", nil, user, keys) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} - -// Withdraw creates a transaction invoking `withdraw` 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) Withdraw(user util.Uint160, amount *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "withdraw", user, amount) -} - -// WithdrawTransaction creates a transaction invoking `withdraw` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) WithdrawTransaction(user util.Uint160, amount *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "withdraw", user, amount) -} - -// WithdrawUnsigned creates a transaction invoking `withdraw` 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) WithdrawUnsigned(user util.Uint160, amount *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "withdraw", nil, user, amount) -} - -// DepositEventsFromApplicationLog retrieves a set of all emitted events -// with "Deposit" name from the provided [result.ApplicationLog]. -func DepositEventsFromApplicationLog(log *result.ApplicationLog) ([]*DepositEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DepositEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Deposit" { - continue - } - event := new(DepositEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DepositEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DepositEvent or -// returns an error if it's not possible to do to so. -func (e *DepositEvent) 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.Amount, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Amount: %w", err) - } - - index++ - e.Receiver, 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 Receiver: %w", err) - } - - index++ - e.TxHash, err = func(item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field TxHash: %w", err) - } - - return nil -} - -// WithdrawEventsFromApplicationLog retrieves a set of all emitted events -// with "Withdraw" name from the provided [result.ApplicationLog]. -func WithdrawEventsFromApplicationLog(log *result.ApplicationLog) ([]*WithdrawEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*WithdrawEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Withdraw" { - continue - } - event := new(WithdrawEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize WithdrawEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to WithdrawEvent or -// returns an error if it's not possible to do to so. -func (e *WithdrawEvent) 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.User, 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 User: %w", err) - } - - index++ - e.Amount, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Amount: %w", err) - } - - index++ - e.TxHash, err = func(item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field TxHash: %w", err) - } - - return nil -} - -// ChequeEventsFromApplicationLog retrieves a set of all emitted events -// with "Cheque" name from the provided [result.ApplicationLog]. -func ChequeEventsFromApplicationLog(log *result.ApplicationLog) ([]*ChequeEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*ChequeEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Cheque" { - continue - } - event := new(ChequeEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize ChequeEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to ChequeEvent or -// returns an error if it's not possible to do to so. -func (e *ChequeEvent) 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.Id, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Id: %w", err) - } - - index++ - e.User, 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 User: %w", err) - } - - index++ - e.Amount, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Amount: %w", err) - } - - index++ - e.LockAccount, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field LockAccount: %w", err) - } - - return nil -} - -// BindEventsFromApplicationLog retrieves a set of all emitted events -// with "Bind" name from the provided [result.ApplicationLog]. -func BindEventsFromApplicationLog(log *result.ApplicationLog) ([]*BindEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*BindEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Bind" { - continue - } - event := new(BindEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize BindEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to BindEvent or -// returns an error if it's not possible to do to so. -func (e *BindEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.User, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field User: %w", err) - } - - index++ - e.Keys, 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 Keys: %w", err) - } - - return nil -} - -// UnbindEventsFromApplicationLog retrieves a set of all emitted events -// with "Unbind" name from the provided [result.ApplicationLog]. -func UnbindEventsFromApplicationLog(log *result.ApplicationLog) ([]*UnbindEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*UnbindEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Unbind" { - continue - } - event := new(UnbindEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize UnbindEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to UnbindEvent or -// returns an error if it's not possible to do to so. -func (e *UnbindEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.User, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field User: %w", err) - } - - index++ - e.Keys, 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 Keys: %w", err) - } - - return nil -} - -// SetConfigEventsFromApplicationLog retrieves a set of all emitted events -// with "SetConfig" name from the provided [result.ApplicationLog]. -func SetConfigEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetConfigEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*SetConfigEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "SetConfig" { - continue - } - event := new(SetConfigEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize SetConfigEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to SetConfigEvent or -// returns an error if it's not possible to do to so. -func (e *SetConfigEvent) 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.Id, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Id: %w", err) - } - - index++ - e.Key, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Key: %w", err) - } - - index++ - e.Value, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Value: %w", err) - } - - return nil -} diff --git a/rpcclient/frostfsid/client.go b/rpcclient/frostfsid/client.go deleted file mode 100644 index 498b472..0000000 --- a/rpcclient/frostfsid/client.go +++ /dev/null @@ -1,2207 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package identity contains RPC wrappers for Identity contract. -package identity - -import ( - "crypto/elliptic" - "errors" - "fmt" - "github.com/google/uuid" - "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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "math/big" - "unicode/utf8" -) - -// CreateSubjectEvent represents "CreateSubject" event emitted by the contract. -type CreateSubjectEvent struct { - SubjectAddress util.Uint160 -} - -// AddSubjectKeyEvent represents "AddSubjectKey" event emitted by the contract. -type AddSubjectKeyEvent struct { - SubjectAddress util.Uint160 - SubjectKey *keys.PublicKey -} - -// RemoveSubjectKeyEvent represents "RemoveSubjectKey" event emitted by the contract. -type RemoveSubjectKeyEvent struct { - SubjectAddress util.Uint160 - SubjectKey *keys.PublicKey -} - -// SetSubjectNameEvent represents "SetSubjectName" event emitted by the contract. -type SetSubjectNameEvent struct { - SubjectAddress util.Uint160 - Name string -} - -// SetSubjectKVEvent represents "SetSubjectKV" event emitted by the contract. -type SetSubjectKVEvent struct { - SubjectAddress util.Uint160 - Key string - Value string -} - -// DeleteSubjectKVEvent represents "DeleteSubjectKV" event emitted by the contract. -type DeleteSubjectKVEvent struct { - SubjectAddress util.Uint160 - Key string -} - -// DeleteSubjectEvent represents "DeleteSubject" event emitted by the contract. -type DeleteSubjectEvent struct { - SubjectAddress util.Uint160 -} - -// CreateNamespaceEvent represents "CreateNamespace" event emitted by the contract. -type CreateNamespaceEvent struct { - Namespace string -} - -// UpdateNamespaceEvent represents "UpdateNamespace" event emitted by the contract. -type UpdateNamespaceEvent struct { - Namespace string - State string -} - -// DeleteNamespaceEvent represents "DeleteNamespace" event emitted by the contract. -type DeleteNamespaceEvent struct { - Namespace string -} - -// AddSubjectToNamespaceEvent represents "AddSubjectToNamespace" event emitted by the contract. -type AddSubjectToNamespaceEvent struct { - SubjectAddress util.Uint160 - Namespace string -} - -// RemoveSubjectFromNamespaceEvent represents "RemoveSubjectFromNamespace" event emitted by the contract. -type RemoveSubjectFromNamespaceEvent struct { - SubjectAddress util.Uint160 - Namespace string -} - -// CreateGroupEvent represents "CreateGroup" event emitted by the contract. -type CreateGroupEvent struct { - Namespace string - Group string -} - -// SetGroupNameEvent represents "SetGroupName" event emitted by the contract. -type SetGroupNameEvent struct { - Namespace string - GroupID *big.Int - Name string -} - -// SetGroupKVEvent represents "SetGroupKV" event emitted by the contract. -type SetGroupKVEvent struct { - Namespace string - GroupID *big.Int - Key string - Value string -} - -// DeleteGroupKVEvent represents "DeleteGroupKV" event emitted by the contract. -type DeleteGroupKVEvent struct { - Namespace string - GroupID *big.Int - Key string -} - -// AddSubjectToGroupEvent represents "AddSubjectToGroup" event emitted by the contract. -type AddSubjectToGroupEvent struct { - SubjectAddress util.Uint160 - Namespace string - GroupID *big.Int -} - -// RemoveSubjectFromGroupEvent represents "RemoveSubjectFromGroup" event emitted by the contract. -type RemoveSubjectFromGroupEvent struct { - SubjectAddress util.Uint160 - Namespace string - GroupID *big.Int -} - -// DeleteGroupEvent represents "DeleteGroup" event emitted by the contract. -type DeleteGroupEvent struct { - Namespace string - GroupID *big.Int -} - -// 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) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// GetAdmin invokes `getAdmin` method of contract. -func (c *ContractReader) GetAdmin() (util.Uint160, error) { - return unwrap.Uint160(c.invoker.Call(c.hash, "getAdmin")) -} - -// GetGroup invokes `getGroup` method of contract. -func (c *ContractReader) GetGroup(ns string, groupID *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getGroup", ns, groupID)) -} - -// GetGroupByName invokes `getGroupByName` method of contract. -func (c *ContractReader) GetGroupByName(ns string, name string) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getGroupByName", ns, name)) -} - -// GetGroupExtended invokes `getGroupExtended` method of contract. -func (c *ContractReader) GetGroupExtended(ns string, groupID *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getGroupExtended", ns, groupID)) -} - -// GetGroupIDByName invokes `getGroupIDByName` method of contract. -func (c *ContractReader) GetGroupIDByName(ns string, name string) (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "getGroupIDByName", ns, name)) -} - -// GetNamespace invokes `getNamespace` method of contract. -func (c *ContractReader) GetNamespace(ns string) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getNamespace", ns)) -} - -// GetNamespaceExtended invokes `getNamespaceExtended` method of contract. -func (c *ContractReader) GetNamespaceExtended(ns string) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getNamespaceExtended", ns)) -} - -// GetSubject invokes `getSubject` method of contract. -func (c *ContractReader) GetSubject(addr util.Uint160) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getSubject", addr)) -} - -// GetSubjectByKey invokes `getSubjectByKey` method of contract. -func (c *ContractReader) GetSubjectByKey(key *keys.PublicKey) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getSubjectByKey", key)) -} - -// GetSubjectByName invokes `getSubjectByName` method of contract. -func (c *ContractReader) GetSubjectByName(ns string, name string) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getSubjectByName", ns, name)) -} - -// GetSubjectExtended invokes `getSubjectExtended` method of contract. -func (c *ContractReader) GetSubjectExtended(addr util.Uint160) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getSubjectExtended", addr)) -} - -// GetSubjectKV invokes `getSubjectKV` method of contract. -func (c *ContractReader) GetSubjectKV(addr util.Uint160, name string) (string, error) { - return unwrap.UTF8String(c.invoker.Call(c.hash, "getSubjectKV", addr, name)) -} - -// GetSubjectKeyByName invokes `getSubjectKeyByName` method of contract. -func (c *ContractReader) GetSubjectKeyByName(ns string, name string) (*keys.PublicKey, error) { - return unwrap.PublicKey(c.invoker.Call(c.hash, "getSubjectKeyByName", ns, name)) -} - -// ListGroupSubjects invokes `listGroupSubjects` method of contract. -func (c *ContractReader) ListGroupSubjects(ns string, groupID *big.Int) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listGroupSubjects", ns, groupID)) -} - -// ListGroupSubjectsExpanded is similar to ListGroupSubjects (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) ListGroupSubjectsExpanded(ns string, groupID *big.Int, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listGroupSubjects", _numOfIteratorItems, ns, groupID)) -} - -// ListGroups invokes `listGroups` method of contract. -func (c *ContractReader) ListGroups(ns string) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listGroups", ns)) -} - -// ListGroupsExpanded is similar to ListGroups (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) ListGroupsExpanded(ns string, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listGroups", _numOfIteratorItems, ns)) -} - -// ListNamespaceSubjects invokes `listNamespaceSubjects` method of contract. -func (c *ContractReader) ListNamespaceSubjects(ns string) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listNamespaceSubjects", ns)) -} - -// ListNamespaceSubjectsExpanded is similar to ListNamespaceSubjects (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) ListNamespaceSubjectsExpanded(ns string, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listNamespaceSubjects", _numOfIteratorItems, ns)) -} - -// ListNamespaces invokes `listNamespaces` method of contract. -func (c *ContractReader) ListNamespaces() (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listNamespaces")) -} - -// ListNamespacesExpanded is similar to ListNamespaces (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) ListNamespacesExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listNamespaces", _numOfIteratorItems)) -} - -// ListSubjects invokes `listSubjects` method of contract. -func (c *ContractReader) ListSubjects() (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listSubjects")) -} - -// ListSubjectsExpanded is similar to ListSubjects (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) ListSubjectsExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listSubjects", _numOfIteratorItems)) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// AddSubjectKey creates a transaction invoking `addSubjectKey` 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) AddSubjectKey(addr util.Uint160, key *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addSubjectKey", addr, key) -} - -// AddSubjectKeyTransaction creates a transaction invoking `addSubjectKey` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddSubjectKeyTransaction(addr util.Uint160, key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addSubjectKey", addr, key) -} - -// AddSubjectKeyUnsigned creates a transaction invoking `addSubjectKey` 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) AddSubjectKeyUnsigned(addr util.Uint160, key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addSubjectKey", nil, addr, key) -} - -// AddSubjectToGroup creates a transaction invoking `addSubjectToGroup` 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) AddSubjectToGroup(addr util.Uint160, groupID *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addSubjectToGroup", addr, groupID) -} - -// AddSubjectToGroupTransaction creates a transaction invoking `addSubjectToGroup` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddSubjectToGroupTransaction(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addSubjectToGroup", addr, groupID) -} - -// AddSubjectToGroupUnsigned creates a transaction invoking `addSubjectToGroup` 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) AddSubjectToGroupUnsigned(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addSubjectToGroup", nil, addr, groupID) -} - -// ClearAdmin creates a transaction invoking `clearAdmin` 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) ClearAdmin() (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "clearAdmin") -} - -// ClearAdminTransaction creates a transaction invoking `clearAdmin` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) ClearAdminTransaction() (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "clearAdmin") -} - -// ClearAdminUnsigned creates a transaction invoking `clearAdmin` 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) ClearAdminUnsigned() (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "clearAdmin", nil) -} - -// CreateGroup creates a transaction invoking `createGroup` 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) CreateGroup(ns string, group string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "createGroup", ns, group) -} - -// CreateGroupTransaction creates a transaction invoking `createGroup` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) CreateGroupTransaction(ns string, group string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "createGroup", ns, group) -} - -// CreateGroupUnsigned creates a transaction invoking `createGroup` 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) CreateGroupUnsigned(ns string, group string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "createGroup", nil, ns, group) -} - -// CreateNamespace creates a transaction invoking `createNamespace` 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) CreateNamespace(ns string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "createNamespace", ns) -} - -// CreateNamespaceTransaction creates a transaction invoking `createNamespace` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) CreateNamespaceTransaction(ns string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "createNamespace", ns) -} - -// CreateNamespaceUnsigned creates a transaction invoking `createNamespace` 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) CreateNamespaceUnsigned(ns string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "createNamespace", nil, ns) -} - -// CreateSubject creates a transaction invoking `createSubject` 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) CreateSubject(ns string, key *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "createSubject", ns, key) -} - -// CreateSubjectTransaction creates a transaction invoking `createSubject` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) CreateSubjectTransaction(ns string, key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "createSubject", ns, key) -} - -// CreateSubjectUnsigned creates a transaction invoking `createSubject` 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) CreateSubjectUnsigned(ns string, key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "createSubject", nil, ns, key) -} - -// DeleteGroup creates a transaction invoking `deleteGroup` 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) DeleteGroup(ns string, groupID *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteGroup", ns, groupID) -} - -// DeleteGroupTransaction creates a transaction invoking `deleteGroup` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteGroupTransaction(ns string, groupID *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteGroup", ns, groupID) -} - -// DeleteGroupUnsigned creates a transaction invoking `deleteGroup` 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) DeleteGroupUnsigned(ns string, groupID *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteGroup", nil, ns, groupID) -} - -// DeleteGroupKV creates a transaction invoking `deleteGroupKV` 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) DeleteGroupKV(ns string, groupID *big.Int, key string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteGroupKV", ns, groupID, key) -} - -// DeleteGroupKVTransaction creates a transaction invoking `deleteGroupKV` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteGroupKVTransaction(ns string, groupID *big.Int, key string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteGroupKV", ns, groupID, key) -} - -// DeleteGroupKVUnsigned creates a transaction invoking `deleteGroupKV` 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) DeleteGroupKVUnsigned(ns string, groupID *big.Int, key string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteGroupKV", nil, ns, groupID, key) -} - -// DeleteNamespace creates a transaction invoking `deleteNamespace` 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) DeleteNamespace(ns string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteNamespace", ns) -} - -// DeleteNamespaceTransaction creates a transaction invoking `deleteNamespace` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteNamespaceTransaction(ns string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteNamespace", ns) -} - -// DeleteNamespaceUnsigned creates a transaction invoking `deleteNamespace` 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) DeleteNamespaceUnsigned(ns string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteNamespace", nil, ns) -} - -// DeleteSubject creates a transaction invoking `deleteSubject` 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) DeleteSubject(addr util.Uint160) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteSubject", addr) -} - -// DeleteSubjectTransaction creates a transaction invoking `deleteSubject` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteSubjectTransaction(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteSubject", addr) -} - -// DeleteSubjectUnsigned creates a transaction invoking `deleteSubject` 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) DeleteSubjectUnsigned(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteSubject", nil, addr) -} - -// DeleteSubjectKV creates a transaction invoking `deleteSubjectKV` 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) DeleteSubjectKV(addr util.Uint160, key string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteSubjectKV", addr, key) -} - -// DeleteSubjectKVTransaction creates a transaction invoking `deleteSubjectKV` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteSubjectKVTransaction(addr util.Uint160, key string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteSubjectKV", addr, key) -} - -// DeleteSubjectKVUnsigned creates a transaction invoking `deleteSubjectKV` 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) DeleteSubjectKVUnsigned(addr util.Uint160, key string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteSubjectKV", nil, addr, key) -} - -// RemoveSubjectFromGroup creates a transaction invoking `removeSubjectFromGroup` 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) RemoveSubjectFromGroup(addr util.Uint160, groupID *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeSubjectFromGroup", addr, groupID) -} - -// RemoveSubjectFromGroupTransaction creates a transaction invoking `removeSubjectFromGroup` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveSubjectFromGroupTransaction(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeSubjectFromGroup", addr, groupID) -} - -// RemoveSubjectFromGroupUnsigned creates a transaction invoking `removeSubjectFromGroup` 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) RemoveSubjectFromGroupUnsigned(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeSubjectFromGroup", nil, addr, groupID) -} - -// RemoveSubjectKey creates a transaction invoking `removeSubjectKey` 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) RemoveSubjectKey(addr util.Uint160, key *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeSubjectKey", addr, key) -} - -// RemoveSubjectKeyTransaction creates a transaction invoking `removeSubjectKey` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveSubjectKeyTransaction(addr util.Uint160, key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeSubjectKey", addr, key) -} - -// RemoveSubjectKeyUnsigned creates a transaction invoking `removeSubjectKey` 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) RemoveSubjectKeyUnsigned(addr util.Uint160, key *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeSubjectKey", nil, addr, key) -} - -// 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(addr util.Uint160) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setAdmin", addr) -} - -// 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(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setAdmin", addr) -} - -// 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(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setAdmin", nil, addr) -} - -// SetGroupKV creates a transaction invoking `setGroupKV` 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) SetGroupKV(ns string, groupID *big.Int, key string, val string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setGroupKV", ns, groupID, key, val) -} - -// SetGroupKVTransaction creates a transaction invoking `setGroupKV` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetGroupKVTransaction(ns string, groupID *big.Int, key string, val string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setGroupKV", ns, groupID, key, val) -} - -// SetGroupKVUnsigned creates a transaction invoking `setGroupKV` 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) SetGroupKVUnsigned(ns string, groupID *big.Int, key string, val string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setGroupKV", nil, ns, groupID, key, val) -} - -// SetGroupName creates a transaction invoking `setGroupName` 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) SetGroupName(ns string, groupID *big.Int, name string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setGroupName", ns, groupID, name) -} - -// SetGroupNameTransaction creates a transaction invoking `setGroupName` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetGroupNameTransaction(ns string, groupID *big.Int, name string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setGroupName", ns, groupID, name) -} - -// SetGroupNameUnsigned creates a transaction invoking `setGroupName` 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) SetGroupNameUnsigned(ns string, groupID *big.Int, name string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setGroupName", nil, ns, groupID, name) -} - -// SetSubjectKV creates a transaction invoking `setSubjectKV` 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) SetSubjectKV(addr util.Uint160, key string, val string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setSubjectKV", addr, key, val) -} - -// SetSubjectKVTransaction creates a transaction invoking `setSubjectKV` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetSubjectKVTransaction(addr util.Uint160, key string, val string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setSubjectKV", addr, key, val) -} - -// SetSubjectKVUnsigned creates a transaction invoking `setSubjectKV` 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) SetSubjectKVUnsigned(addr util.Uint160, key string, val string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setSubjectKV", nil, addr, key, val) -} - -// SetSubjectName creates a transaction invoking `setSubjectName` 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) SetSubjectName(addr util.Uint160, name string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setSubjectName", addr, name) -} - -// SetSubjectNameTransaction creates a transaction invoking `setSubjectName` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetSubjectNameTransaction(addr util.Uint160, name string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setSubjectName", addr, name) -} - -// SetSubjectNameUnsigned creates a transaction invoking `setSubjectName` 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) SetSubjectNameUnsigned(addr util.Uint160, name string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setSubjectName", nil, addr, name) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} - -// UpdateNamespace creates a transaction invoking `updateNamespace` 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) UpdateNamespace(ns string, state string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "updateNamespace", ns, state) -} - -// UpdateNamespaceTransaction creates a transaction invoking `updateNamespace` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UpdateNamespaceTransaction(ns string, state string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "updateNamespace", ns, state) -} - -// UpdateNamespaceUnsigned creates a transaction invoking `updateNamespace` 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) UpdateNamespaceUnsigned(ns string, state string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "updateNamespace", nil, ns, state) -} - -// CreateSubjectEventsFromApplicationLog retrieves a set of all emitted events -// with "CreateSubject" name from the provided [result.ApplicationLog]. -func CreateSubjectEventsFromApplicationLog(log *result.ApplicationLog) ([]*CreateSubjectEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*CreateSubjectEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "CreateSubject" { - continue - } - event := new(CreateSubjectEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize CreateSubjectEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to CreateSubjectEvent or -// returns an error if it's not possible to do to so. -func (e *CreateSubjectEvent) 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.SubjectAddress, 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 SubjectAddress: %w", err) - } - - return nil -} - -// AddSubjectKeyEventsFromApplicationLog retrieves a set of all emitted events -// with "AddSubjectKey" name from the provided [result.ApplicationLog]. -func AddSubjectKeyEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddSubjectKeyEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*AddSubjectKeyEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "AddSubjectKey" { - continue - } - event := new(AddSubjectKeyEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize AddSubjectKeyEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to AddSubjectKeyEvent or -// returns an error if it's not possible to do to so. -func (e *AddSubjectKeyEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.SubjectKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field SubjectKey: %w", err) - } - - return nil -} - -// RemoveSubjectKeyEventsFromApplicationLog retrieves a set of all emitted events -// with "RemoveSubjectKey" name from the provided [result.ApplicationLog]. -func RemoveSubjectKeyEventsFromApplicationLog(log *result.ApplicationLog) ([]*RemoveSubjectKeyEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*RemoveSubjectKeyEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "RemoveSubjectKey" { - continue - } - event := new(RemoveSubjectKeyEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize RemoveSubjectKeyEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to RemoveSubjectKeyEvent or -// returns an error if it's not possible to do to so. -func (e *RemoveSubjectKeyEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.SubjectKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field SubjectKey: %w", err) - } - - return nil -} - -// SetSubjectNameEventsFromApplicationLog retrieves a set of all emitted events -// with "SetSubjectName" name from the provided [result.ApplicationLog]. -func SetSubjectNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetSubjectNameEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*SetSubjectNameEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "SetSubjectName" { - continue - } - event := new(SetSubjectNameEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize SetSubjectNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to SetSubjectNameEvent or -// returns an error if it's not possible to do to so. -func (e *SetSubjectNameEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.SubjectAddress, 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 SubjectAddress: %w", err) - } - - 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) - } - - return nil -} - -// SetSubjectKVEventsFromApplicationLog retrieves a set of all emitted events -// with "SetSubjectKV" name from the provided [result.ApplicationLog]. -func SetSubjectKVEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetSubjectKVEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*SetSubjectKVEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "SetSubjectKV" { - continue - } - event := new(SetSubjectKVEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize SetSubjectKVEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to SetSubjectKVEvent or -// returns an error if it's not possible to do to so. -func (e *SetSubjectKVEvent) 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.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.Key, 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 Key: %w", err) - } - - index++ - e.Value, 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 Value: %w", err) - } - - return nil -} - -// DeleteSubjectKVEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteSubjectKV" name from the provided [result.ApplicationLog]. -func DeleteSubjectKVEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteSubjectKVEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteSubjectKVEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteSubjectKV" { - continue - } - event := new(DeleteSubjectKVEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteSubjectKVEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteSubjectKVEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteSubjectKVEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.Key, 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 Key: %w", err) - } - - return nil -} - -// DeleteSubjectEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteSubject" name from the provided [result.ApplicationLog]. -func DeleteSubjectEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteSubjectEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteSubjectEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteSubject" { - continue - } - event := new(DeleteSubjectEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteSubjectEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteSubjectEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteSubjectEvent) 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.SubjectAddress, 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 SubjectAddress: %w", err) - } - - return nil -} - -// CreateNamespaceEventsFromApplicationLog retrieves a set of all emitted events -// with "CreateNamespace" name from the provided [result.ApplicationLog]. -func CreateNamespaceEventsFromApplicationLog(log *result.ApplicationLog) ([]*CreateNamespaceEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*CreateNamespaceEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "CreateNamespace" { - continue - } - event := new(CreateNamespaceEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize CreateNamespaceEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to CreateNamespaceEvent or -// returns an error if it's not possible to do to so. -func (e *CreateNamespaceEvent) 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.Namespace, 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 Namespace: %w", err) - } - - return nil -} - -// UpdateNamespaceEventsFromApplicationLog retrieves a set of all emitted events -// with "UpdateNamespace" name from the provided [result.ApplicationLog]. -func UpdateNamespaceEventsFromApplicationLog(log *result.ApplicationLog) ([]*UpdateNamespaceEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*UpdateNamespaceEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "UpdateNamespace" { - continue - } - event := new(UpdateNamespaceEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize UpdateNamespaceEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to UpdateNamespaceEvent or -// returns an error if it's not possible to do to so. -func (e *UpdateNamespaceEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.Namespace, 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 Namespace: %w", err) - } - - index++ - e.State, 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 State: %w", err) - } - - return nil -} - -// DeleteNamespaceEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteNamespace" name from the provided [result.ApplicationLog]. -func DeleteNamespaceEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteNamespaceEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteNamespaceEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteNamespace" { - continue - } - event := new(DeleteNamespaceEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteNamespaceEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteNamespaceEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteNamespaceEvent) 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.Namespace, 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 Namespace: %w", err) - } - - return nil -} - -// AddSubjectToNamespaceEventsFromApplicationLog retrieves a set of all emitted events -// with "AddSubjectToNamespace" name from the provided [result.ApplicationLog]. -func AddSubjectToNamespaceEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddSubjectToNamespaceEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*AddSubjectToNamespaceEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "AddSubjectToNamespace" { - continue - } - event := new(AddSubjectToNamespaceEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize AddSubjectToNamespaceEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to AddSubjectToNamespaceEvent or -// returns an error if it's not possible to do to so. -func (e *AddSubjectToNamespaceEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.Namespace, 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 Namespace: %w", err) - } - - return nil -} - -// RemoveSubjectFromNamespaceEventsFromApplicationLog retrieves a set of all emitted events -// with "RemoveSubjectFromNamespace" name from the provided [result.ApplicationLog]. -func RemoveSubjectFromNamespaceEventsFromApplicationLog(log *result.ApplicationLog) ([]*RemoveSubjectFromNamespaceEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*RemoveSubjectFromNamespaceEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "RemoveSubjectFromNamespace" { - continue - } - event := new(RemoveSubjectFromNamespaceEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize RemoveSubjectFromNamespaceEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to RemoveSubjectFromNamespaceEvent or -// returns an error if it's not possible to do to so. -func (e *RemoveSubjectFromNamespaceEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.Namespace, 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 Namespace: %w", err) - } - - return nil -} - -// CreateGroupEventsFromApplicationLog retrieves a set of all emitted events -// with "CreateGroup" name from the provided [result.ApplicationLog]. -func CreateGroupEventsFromApplicationLog(log *result.ApplicationLog) ([]*CreateGroupEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*CreateGroupEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "CreateGroup" { - continue - } - event := new(CreateGroupEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize CreateGroupEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to CreateGroupEvent or -// returns an error if it's not possible to do to so. -func (e *CreateGroupEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.Namespace, 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 Namespace: %w", err) - } - - index++ - e.Group, 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 Group: %w", err) - } - - return nil -} - -// SetGroupNameEventsFromApplicationLog retrieves a set of all emitted events -// with "SetGroupName" name from the provided [result.ApplicationLog]. -func SetGroupNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetGroupNameEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*SetGroupNameEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "SetGroupName" { - continue - } - event := new(SetGroupNameEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize SetGroupNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to SetGroupNameEvent or -// returns an error if it's not possible to do to so. -func (e *SetGroupNameEvent) 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.Namespace, 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 Namespace: %w", err) - } - - index++ - e.GroupID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field GroupID: %w", err) - } - - 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) - } - - return nil -} - -// SetGroupKVEventsFromApplicationLog retrieves a set of all emitted events -// with "SetGroupKV" name from the provided [result.ApplicationLog]. -func SetGroupKVEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetGroupKVEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*SetGroupKVEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "SetGroupKV" { - continue - } - event := new(SetGroupKVEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize SetGroupKVEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to SetGroupKVEvent or -// returns an error if it's not possible to do to so. -func (e *SetGroupKVEvent) 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.Namespace, 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 Namespace: %w", err) - } - - index++ - e.GroupID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field GroupID: %w", err) - } - - index++ - e.Key, 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 Key: %w", err) - } - - index++ - e.Value, 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 Value: %w", err) - } - - return nil -} - -// DeleteGroupKVEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteGroupKV" name from the provided [result.ApplicationLog]. -func DeleteGroupKVEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteGroupKVEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteGroupKVEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteGroupKV" { - continue - } - event := new(DeleteGroupKVEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteGroupKVEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteGroupKVEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteGroupKVEvent) 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.Namespace, 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 Namespace: %w", err) - } - - index++ - e.GroupID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field GroupID: %w", err) - } - - index++ - e.Key, 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 Key: %w", err) - } - - return nil -} - -// AddSubjectToGroupEventsFromApplicationLog retrieves a set of all emitted events -// with "AddSubjectToGroup" name from the provided [result.ApplicationLog]. -func AddSubjectToGroupEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddSubjectToGroupEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*AddSubjectToGroupEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "AddSubjectToGroup" { - continue - } - event := new(AddSubjectToGroupEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize AddSubjectToGroupEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to AddSubjectToGroupEvent or -// returns an error if it's not possible to do to so. -func (e *AddSubjectToGroupEvent) 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.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.Namespace, 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 Namespace: %w", err) - } - - index++ - e.GroupID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field GroupID: %w", err) - } - - return nil -} - -// RemoveSubjectFromGroupEventsFromApplicationLog retrieves a set of all emitted events -// with "RemoveSubjectFromGroup" name from the provided [result.ApplicationLog]. -func RemoveSubjectFromGroupEventsFromApplicationLog(log *result.ApplicationLog) ([]*RemoveSubjectFromGroupEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*RemoveSubjectFromGroupEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "RemoveSubjectFromGroup" { - continue - } - event := new(RemoveSubjectFromGroupEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize RemoveSubjectFromGroupEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to RemoveSubjectFromGroupEvent or -// returns an error if it's not possible to do to so. -func (e *RemoveSubjectFromGroupEvent) 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.SubjectAddress, 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 SubjectAddress: %w", err) - } - - index++ - e.Namespace, 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 Namespace: %w", err) - } - - index++ - e.GroupID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field GroupID: %w", err) - } - - return nil -} - -// DeleteGroupEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteGroup" name from the provided [result.ApplicationLog]. -func DeleteGroupEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteGroupEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteGroupEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteGroup" { - continue - } - event := new(DeleteGroupEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteGroupEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteGroupEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteGroupEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.Namespace, 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 Namespace: %w", err) - } - - index++ - e.GroupID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field GroupID: %w", err) - } - - return nil -} diff --git a/rpcclient/netmap/client.go b/rpcclient/netmap/client.go deleted file mode 100644 index 3f018a5..0000000 --- a/rpcclient/netmap/client.go +++ /dev/null @@ -1,629 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package netmap contains RPC wrappers for Netmap contract. -package netmap - -import ( - "crypto/elliptic" - "errors" - "fmt" - "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/nspcc-dev/neo-go/pkg/crypto/keys" - "github.com/nspcc-dev/neo-go/pkg/neorpc/result" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "math/big" -) - -// AddPeerEvent represents "AddPeer" event emitted by the contract. -type AddPeerEvent struct { - NodeInfo []byte -} - -// AddPeerSuccessEvent represents "AddPeerSuccess" event emitted by the contract. -type AddPeerSuccessEvent struct { - PublicKey *keys.PublicKey -} - -// UpdateStateEvent represents "UpdateState" event emitted by the contract. -type UpdateStateEvent struct { - State *big.Int - PublicKey *keys.PublicKey -} - -// UpdateStateSuccessEvent represents "UpdateStateSuccess" event emitted by the contract. -type UpdateStateSuccessEvent struct { - PublicKey *keys.PublicKey - State *big.Int -} - -// NewEpochEvent represents "NewEpoch" event emitted by the contract. -type NewEpochEvent struct { - Epoch *big.Int -} - -// Invoker is used by ContractReader to call various safe methods. -type Invoker interface { - Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// Config invokes `config` method of contract. -func (c *ContractReader) Config(key []byte) (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, "config", key))) -} - -// Epoch invokes `epoch` method of contract. -func (c *ContractReader) Epoch() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "epoch")) -} - -// ListConfig invokes `listConfig` method of contract. -func (c *ContractReader) ListConfig() ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "listConfig")) -} - -// Netmap invokes `netmap` method of contract. -func (c *ContractReader) Netmap() ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "netmap")) -} - -// NetmapCandidates invokes `netmapCandidates` method of contract. -func (c *ContractReader) NetmapCandidates() ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "netmapCandidates")) -} - -// Snapshot invokes `snapshot` method of contract. -func (c *ContractReader) Snapshot(diff *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "snapshot", diff)) -} - -// SnapshotByEpoch invokes `snapshotByEpoch` method of contract. -func (c *ContractReader) SnapshotByEpoch(epoch *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "snapshotByEpoch", epoch)) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// AddPeer creates a transaction invoking `addPeer` 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) AddPeer(nodeInfo []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addPeer", nodeInfo) -} - -// AddPeerTransaction creates a transaction invoking `addPeer` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddPeerTransaction(nodeInfo []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addPeer", nodeInfo) -} - -// AddPeerUnsigned creates a transaction invoking `addPeer` 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) AddPeerUnsigned(nodeInfo []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addPeer", nil, nodeInfo) -} - -// AddPeerIR creates a transaction invoking `addPeerIR` 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) AddPeerIR(nodeInfo []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addPeerIR", nodeInfo) -} - -// AddPeerIRTransaction creates a transaction invoking `addPeerIR` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddPeerIRTransaction(nodeInfo []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addPeerIR", nodeInfo) -} - -// AddPeerIRUnsigned creates a transaction invoking `addPeerIR` 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) AddPeerIRUnsigned(nodeInfo []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addPeerIR", nil, nodeInfo) -} - -// LastEpochBlock creates a transaction invoking `lastEpochBlock` 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) LastEpochBlock() (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "lastEpochBlock") -} - -// LastEpochBlockTransaction creates a transaction invoking `lastEpochBlock` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) LastEpochBlockTransaction() (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "lastEpochBlock") -} - -// LastEpochBlockUnsigned creates a transaction invoking `lastEpochBlock` 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) LastEpochBlockUnsigned() (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "lastEpochBlock", nil) -} - -// NewEpoch creates a transaction invoking `newEpoch` 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) NewEpoch(epochNum *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "newEpoch", epochNum) -} - -// NewEpochTransaction creates a transaction invoking `newEpoch` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) NewEpochTransaction(epochNum *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "newEpoch", epochNum) -} - -// NewEpochUnsigned creates a transaction invoking `newEpoch` 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) NewEpochUnsigned(epochNum *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "newEpoch", nil, epochNum) -} - -// SetConfig creates a transaction invoking `setConfig` 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) SetConfig(id []byte, key []byte, val []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setConfig", id, key, val) -} - -// SetConfigTransaction creates a transaction invoking `setConfig` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) SetConfigTransaction(id []byte, key []byte, val []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setConfig", id, key, val) -} - -// SetConfigUnsigned creates a transaction invoking `setConfig` 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) SetConfigUnsigned(id []byte, key []byte, val []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setConfig", nil, id, key, val) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} - -// UpdateSnapshotCount creates a transaction invoking `updateSnapshotCount` 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) UpdateSnapshotCount(count *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "updateSnapshotCount", count) -} - -// UpdateSnapshotCountTransaction creates a transaction invoking `updateSnapshotCount` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UpdateSnapshotCountTransaction(count *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "updateSnapshotCount", count) -} - -// UpdateSnapshotCountUnsigned creates a transaction invoking `updateSnapshotCount` 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) UpdateSnapshotCountUnsigned(count *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "updateSnapshotCount", nil, count) -} - -// UpdateState creates a transaction invoking `updateState` 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) UpdateState(state *big.Int, publicKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "updateState", state, publicKey) -} - -// UpdateStateTransaction creates a transaction invoking `updateState` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UpdateStateTransaction(state *big.Int, publicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "updateState", state, publicKey) -} - -// UpdateStateUnsigned creates a transaction invoking `updateState` 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) UpdateStateUnsigned(state *big.Int, publicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "updateState", nil, state, publicKey) -} - -// UpdateStateIR creates a transaction invoking `updateStateIR` 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) UpdateStateIR(state *big.Int, publicKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "updateStateIR", state, publicKey) -} - -// UpdateStateIRTransaction creates a transaction invoking `updateStateIR` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UpdateStateIRTransaction(state *big.Int, publicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "updateStateIR", state, publicKey) -} - -// UpdateStateIRUnsigned creates a transaction invoking `updateStateIR` 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) UpdateStateIRUnsigned(state *big.Int, publicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "updateStateIR", nil, state, publicKey) -} - -// AddPeerEventsFromApplicationLog retrieves a set of all emitted events -// with "AddPeer" name from the provided [result.ApplicationLog]. -func AddPeerEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddPeerEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*AddPeerEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "AddPeer" { - continue - } - event := new(AddPeerEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize AddPeerEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to AddPeerEvent or -// returns an error if it's not possible to do to so. -func (e *AddPeerEvent) 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.NodeInfo, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field NodeInfo: %w", err) - } - - return nil -} - -// AddPeerSuccessEventsFromApplicationLog retrieves a set of all emitted events -// with "AddPeerSuccess" name from the provided [result.ApplicationLog]. -func AddPeerSuccessEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddPeerSuccessEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*AddPeerSuccessEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "AddPeerSuccess" { - continue - } - event := new(AddPeerSuccessEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize AddPeerSuccessEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to AddPeerSuccessEvent or -// returns an error if it's not possible to do to so. -func (e *AddPeerSuccessEvent) 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.PublicKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field PublicKey: %w", err) - } - - return nil -} - -// UpdateStateEventsFromApplicationLog retrieves a set of all emitted events -// with "UpdateState" name from the provided [result.ApplicationLog]. -func UpdateStateEventsFromApplicationLog(log *result.ApplicationLog) ([]*UpdateStateEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*UpdateStateEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "UpdateState" { - continue - } - event := new(UpdateStateEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize UpdateStateEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to UpdateStateEvent or -// returns an error if it's not possible to do to so. -func (e *UpdateStateEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.State, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field State: %w", err) - } - - index++ - e.PublicKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field PublicKey: %w", err) - } - - return nil -} - -// UpdateStateSuccessEventsFromApplicationLog retrieves a set of all emitted events -// with "UpdateStateSuccess" name from the provided [result.ApplicationLog]. -func UpdateStateSuccessEventsFromApplicationLog(log *result.ApplicationLog) ([]*UpdateStateSuccessEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*UpdateStateSuccessEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "UpdateStateSuccess" { - continue - } - event := new(UpdateStateSuccessEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize UpdateStateSuccessEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to UpdateStateSuccessEvent or -// returns an error if it's not possible to do to so. -func (e *UpdateStateSuccessEvent) 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) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - e.PublicKey, err = func(item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - }(arr[index]) - if err != nil { - return fmt.Errorf("field PublicKey: %w", err) - } - - index++ - e.State, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field State: %w", err) - } - - return nil -} - -// NewEpochEventsFromApplicationLog retrieves a set of all emitted events -// with "NewEpoch" name from the provided [result.ApplicationLog]. -func NewEpochEventsFromApplicationLog(log *result.ApplicationLog) ([]*NewEpochEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*NewEpochEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "NewEpoch" { - continue - } - event := new(NewEpochEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize NewEpochEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to NewEpochEvent or -// returns an error if it's not possible to do to so. -func (e *NewEpochEvent) 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.Epoch, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Epoch: %w", err) - } - - return nil -} diff --git a/rpcclient/nns/client.go b/rpcclient/nns/client.go deleted file mode 100644 index 43c0d0a..0000000 --- a/rpcclient/nns/client.go +++ /dev/null @@ -1,720 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--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" -) - -// RegisterDomainEvent represents "RegisterDomain" event emitted by the contract. -type RegisterDomainEvent struct { - Name string -} - -// AddRecordEvent represents "AddRecord" event emitted by the contract. -type AddRecordEvent struct { - Name string - Type *big.Int -} - -// DeleteRecordEvent represents "DeleteRecord" event emitted by the contract. -type DeleteRecordEvent struct { - Name string - Type *big.Int -} - -// DeleteRecordsEvent represents "DeleteRecords" event emitted by the contract. -type DeleteRecordsEvent struct { - Name string - Type *big.Int -} - -// DeleteDomainEvent represents "DeleteDomain" event emitted by the contract. -type DeleteDomainEvent struct { - Name string -} - -// 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 provided contract hash and the given Invoker. -func NewReader(invoker Invoker, hash util.Uint160) *ContractReader { - return &ContractReader{*nep11.NewNonDivisibleReader(invoker, hash), invoker, hash} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - var nep11ndt = nep11.NewNonDivisible(actor, hash) - return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor, hash}, nep11ndt.BaseWriter, actor, hash} -} - -// 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)) -} - -// GetPrice invokes `getPrice` method of contract. -func (c *ContractReader) GetPrice() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "getPrice")) -} - -// GetRecords invokes `getRecords` method of contract. -func (c *ContractReader) GetRecords(name string, typ *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "getRecords", name, typ)) -} - -// IsAvailable invokes `isAvailable` method of contract. -func (c *ContractReader) IsAvailable(name string) (bool, error) { - return unwrap.Bool(c.invoker.Call(c.hash, "isAvailable", name)) -} - -// Resolve invokes `resolve` method of contract. -func (c *ContractReader) Resolve(name string, typ *big.Int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "resolve", name, typ)) -} - -// 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)) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// AddRecord creates a transaction invoking `addRecord` 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) AddRecord(name string, typ *big.Int, data string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addRecord", name, typ, data) -} - -// AddRecordTransaction creates a transaction invoking `addRecord` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddRecordTransaction(name string, typ *big.Int, data string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addRecord", name, typ, data) -} - -// AddRecordUnsigned creates a transaction invoking `addRecord` 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) AddRecordUnsigned(name string, typ *big.Int, data string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addRecord", nil, name, typ, data) -} - -// DeleteDomain creates a transaction invoking `deleteDomain` 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) DeleteDomain(name string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteDomain", name) -} - -// DeleteDomainTransaction creates a transaction invoking `deleteDomain` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteDomainTransaction(name string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteDomain", name) -} - -// DeleteDomainUnsigned creates a transaction invoking `deleteDomain` 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) DeleteDomainUnsigned(name string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteDomain", nil, name) -} - -func (c *Contract) scriptForDeleteRecord(name string, typ *big.Int, data string) ([]byte, error) { - return smartcontract.CreateCallWithAssertScript(c.hash, "deleteRecord", name, typ, 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, typ *big.Int, data string) (util.Uint256, uint32, error) { - script, err := c.scriptForDeleteRecord(name, typ, data) - if err != nil { - return util.Uint256{}, 0, err - } - return c.actor.SendRun(script) -} - -// 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, typ *big.Int, data string) (*transaction.Transaction, error) { - script, err := c.scriptForDeleteRecord(name, typ, data) - if err != nil { - return nil, err - } - return c.actor.MakeRun(script) -} - -// 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, typ *big.Int, data string) (*transaction.Transaction, error) { - script, err := c.scriptForDeleteRecord(name, typ, data) - if err != nil { - return nil, err - } - return c.actor.MakeUnsignedRun(script, nil) -} - -// DeleteRecords creates a transaction invoking `deleteRecords` 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) DeleteRecords(name string, typ *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "deleteRecords", name, typ) -} - -// DeleteRecordsTransaction creates a transaction invoking `deleteRecords` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) DeleteRecordsTransaction(name string, typ *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "deleteRecords", name, typ) -} - -// DeleteRecordsUnsigned creates a transaction invoking `deleteRecords` 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) DeleteRecordsUnsigned(name string, typ *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "deleteRecords", nil, name, typ) -} - -func (c *Contract) scriptForRegister(name string, owner util.Uint160, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) ([]byte, error) { - return smartcontract.CreateCallWithAssertScript(c.hash, "register", name, owner, email, refresh, retry, expire, ttl) -} - -// 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, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) (util.Uint256, uint32, error) { - script, err := c.scriptForRegister(name, owner, email, refresh, retry, expire, ttl) - 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, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) (*transaction.Transaction, error) { - script, err := c.scriptForRegister(name, owner, email, refresh, retry, expire, ttl) - 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, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) (*transaction.Transaction, error) { - script, err := c.scriptForRegister(name, owner, email, refresh, retry, expire, ttl) - if err != nil { - return nil, err - } - return c.actor.MakeUnsignedRun(script, nil) -} - -// 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) -} - -// 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(price *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setPrice", price) -} - -// 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(price *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setPrice", price) -} - -// 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(price *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setPrice", nil, price) -} - -// 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, typ *big.Int, id *big.Int, data string) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setRecord", name, typ, id, 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, typ *big.Int, id *big.Int, data string) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setRecord", name, typ, id, 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, typ *big.Int, id *big.Int, data string) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setRecord", nil, name, typ, id, 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 string, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", nef, manifest, data) -} - -// 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, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", nef, manifest, data) -} - -// 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, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, nef, manifest, data) -} - -// UpdateSOA creates a transaction invoking `updateSOA` 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) UpdateSOA(name string, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "updateSOA", name, email, refresh, retry, expire, ttl) -} - -// UpdateSOATransaction creates a transaction invoking `updateSOA` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UpdateSOATransaction(name string, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "updateSOA", name, email, refresh, retry, expire, ttl) -} - -// UpdateSOAUnsigned creates a transaction invoking `updateSOA` 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) UpdateSOAUnsigned(name string, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "updateSOA", nil, name, email, refresh, retry, expire, ttl) -} - -// RegisterDomainEventsFromApplicationLog retrieves a set of all emitted events -// with "RegisterDomain" name from the provided [result.ApplicationLog]. -func RegisterDomainEventsFromApplicationLog(log *result.ApplicationLog) ([]*RegisterDomainEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*RegisterDomainEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "RegisterDomain" { - continue - } - event := new(RegisterDomainEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize RegisterDomainEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to RegisterDomainEvent or -// returns an error if it's not possible to do to so. -func (e *RegisterDomainEvent) 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.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) - } - - return nil -} - -// AddRecordEventsFromApplicationLog retrieves a set of all emitted events -// with "AddRecord" name from the provided [result.ApplicationLog]. -func AddRecordEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddRecordEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*AddRecordEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "AddRecord" { - continue - } - event := new(AddRecordEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize AddRecordEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to AddRecordEvent or -// returns an error if it's not possible to do to so. -func (e *AddRecordEvent) 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) != 2 { - 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.Type, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Type: %w", err) - } - - return nil -} - -// DeleteRecordEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteRecord" name from the provided [result.ApplicationLog]. -func DeleteRecordEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteRecordEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteRecordEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteRecord" { - continue - } - event := new(DeleteRecordEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteRecordEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteRecordEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteRecordEvent) 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) != 2 { - 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.Type, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Type: %w", err) - } - - return nil -} - -// DeleteRecordsEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteRecords" name from the provided [result.ApplicationLog]. -func DeleteRecordsEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteRecordsEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteRecordsEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteRecords" { - continue - } - event := new(DeleteRecordsEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteRecordsEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteRecordsEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteRecordsEvent) 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) != 2 { - 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.Type, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Type: %w", err) - } - - return nil -} - -// DeleteDomainEventsFromApplicationLog retrieves a set of all emitted events -// with "DeleteDomain" name from the provided [result.ApplicationLog]. -func DeleteDomainEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteDomainEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteDomainEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "DeleteDomain" { - continue - } - event := new(DeleteDomainEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteDomainEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteDomainEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteDomainEvent) 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.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) - } - - return nil -} diff --git a/rpcclient/policy/client.go b/rpcclient/policy/client.go deleted file mode 100644 index 36d1e5f..0000000 --- a/rpcclient/policy/client.go +++ /dev/null @@ -1,234 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package ape contains RPC wrappers for APE contract. -package ape - -import ( - "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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "math/big" -) - -// 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) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// GetAdmin invokes `getAdmin` method of contract. -func (c *ContractReader) GetAdmin() (util.Uint160, error) { - return unwrap.Uint160(c.invoker.Call(c.hash, "getAdmin")) -} - -// GetChain invokes `getChain` method of contract. -func (c *ContractReader) GetChain(entity *big.Int, entityName string, name []byte) ([]byte, error) { - return unwrap.Bytes(c.invoker.Call(c.hash, "getChain", entity, entityName, name)) -} - -// IteratorChainsByPrefix invokes `iteratorChainsByPrefix` method of contract. -func (c *ContractReader) IteratorChainsByPrefix(entity *big.Int, entityName string, prefix []byte) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "iteratorChainsByPrefix", entity, entityName, prefix)) -} - -// IteratorChainsByPrefixExpanded is similar to IteratorChainsByPrefix (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) IteratorChainsByPrefixExpanded(entity *big.Int, entityName string, prefix []byte, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "iteratorChainsByPrefix", _numOfIteratorItems, entity, entityName, prefix)) -} - -// ListChainNames invokes `listChainNames` method of contract. -func (c *ContractReader) ListChainNames(entity *big.Int, entityName string) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listChainNames", entity, entityName)) -} - -// ListChainNamesExpanded is similar to ListChainNames (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) ListChainNamesExpanded(entity *big.Int, entityName string, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listChainNames", _numOfIteratorItems, entity, entityName)) -} - -// ListChains invokes `listChains` method of contract. -func (c *ContractReader) ListChains(namespace string, container string, name []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "listChains", namespace, container, name)) -} - -// ListChainsByPrefix invokes `listChainsByPrefix` method of contract. -func (c *ContractReader) ListChainsByPrefix(entity *big.Int, entityName string, prefix []byte) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.Call(c.hash, "listChainsByPrefix", entity, entityName, prefix)) -} - -// ListTargets invokes `listTargets` method of contract. -func (c *ContractReader) ListTargets(entity *big.Int) (uuid.UUID, result.Iterator, error) { - return unwrap.SessionIterator(c.invoker.Call(c.hash, "listTargets", entity)) -} - -// ListTargetsExpanded is similar to ListTargets (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) ListTargetsExpanded(entity *big.Int, _numOfIteratorItems int) ([]stackitem.Item, error) { - return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "listTargets", _numOfIteratorItems, entity)) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// AddChain creates a transaction invoking `addChain` 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) AddChain(entity *big.Int, entityName string, name []byte, chain []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addChain", entity, entityName, name, chain) -} - -// AddChainTransaction creates a transaction invoking `addChain` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddChainTransaction(entity *big.Int, entityName string, name []byte, chain []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addChain", entity, entityName, name, chain) -} - -// AddChainUnsigned creates a transaction invoking `addChain` 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) AddChainUnsigned(entity *big.Int, entityName string, name []byte, chain []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addChain", nil, entity, entityName, name, chain) -} - -// RemoveChain creates a transaction invoking `removeChain` 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) RemoveChain(entity *big.Int, entityName string, name []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeChain", entity, entityName, name) -} - -// RemoveChainTransaction creates a transaction invoking `removeChain` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveChainTransaction(entity *big.Int, entityName string, name []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeChain", entity, entityName, name) -} - -// RemoveChainUnsigned creates a transaction invoking `removeChain` 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) RemoveChainUnsigned(entity *big.Int, entityName string, name []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeChain", nil, entity, entityName, name) -} - -// RemoveChainsByPrefix creates a transaction invoking `removeChainsByPrefix` 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) RemoveChainsByPrefix(entity *big.Int, entityName string, name []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeChainsByPrefix", entity, entityName, name) -} - -// RemoveChainsByPrefixTransaction creates a transaction invoking `removeChainsByPrefix` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveChainsByPrefixTransaction(entity *big.Int, entityName string, name []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeChainsByPrefix", entity, entityName, name) -} - -// RemoveChainsByPrefixUnsigned creates a transaction invoking `removeChainsByPrefix` 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) RemoveChainsByPrefixUnsigned(entity *big.Int, entityName string, name []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeChainsByPrefix", nil, entity, entityName, name) -} - -// 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(addr util.Uint160) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "setAdmin", addr) -} - -// 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(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "setAdmin", addr) -} - -// 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(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "setAdmin", nil, addr) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} diff --git a/rpcclient/processing/client.go b/rpcclient/processing/client.go deleted file mode 100644 index de296fb..0000000 --- a/rpcclient/processing/client.go +++ /dev/null @@ -1,84 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package multisignatureprocessing contains RPC wrappers for Multi Signature Processing contract. -package multisignatureprocessing - -import ( - "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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "math/big" -) - -// Invoker is used by ContractReader to call various safe methods. -type Invoker interface { - Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// Verify invokes `verify` method of contract. -func (c *ContractReader) Verify() (bool, error) { - return unwrap.Bool(c.invoker.Call(c.hash, "verify")) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} diff --git a/rpcclient/proxy/client.go b/rpcclient/proxy/client.go deleted file mode 100644 index 7c75af6..0000000 --- a/rpcclient/proxy/client.go +++ /dev/null @@ -1,128 +0,0 @@ -// Code generated by neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. - -// Package notaryproxy contains RPC wrappers for Notary Proxy contract. -package notaryproxy - -import ( - "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/unwrap" - "github.com/nspcc-dev/neo-go/pkg/util" - "math/big" -) - -// Invoker is used by ContractReader to call various safe methods. -type Invoker interface { - Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) -} - -// Actor is used by Contract to call state-changing methods. -type Actor interface { - Invoker - - 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 { - invoker Invoker - hash util.Uint160 -} - -// Contract implements all contract methods. -type Contract struct { - ContractReader - actor Actor - 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} -} - -// New creates an instance of Contract using provided contract hash and the given Actor. -func New(actor Actor, hash util.Uint160) *Contract { - return &Contract{ContractReader{actor, hash}, actor, hash} -} - -// Verify invokes `verify` method of contract. -func (c *ContractReader) Verify() (bool, error) { - return unwrap.Bool(c.invoker.Call(c.hash, "verify")) -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// AddAccount creates a transaction invoking `addAccount` 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) AddAccount(addr util.Uint160) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addAccount", addr) -} - -// AddAccountTransaction creates a transaction invoking `addAccount` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddAccountTransaction(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addAccount", addr) -} - -// AddAccountUnsigned creates a transaction invoking `addAccount` 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) AddAccountUnsigned(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addAccount", nil, addr) -} - -// RemoveAccount creates a transaction invoking `removeAccount` 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) RemoveAccount(addr util.Uint160) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeAccount", addr) -} - -// RemoveAccountTransaction creates a transaction invoking `removeAccount` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveAccountTransaction(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeAccount", addr) -} - -// RemoveAccountUnsigned creates a transaction invoking `removeAccount` 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) RemoveAccountUnsigned(addr util.Uint160) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeAccount", nil, addr) -} - -// 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(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "update", script, manifest, data) -} - -// 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(script []byte, manifest []byte, data any) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data) -} diff --git a/tests/alphabet_test.go b/tests/alphabet_test.go index 463dd61..3d15a43 100644 --- a/tests/alphabet_test.go +++ b/tests/alphabet_test.go @@ -21,12 +21,13 @@ const alphabetPath = "../alphabet" func deployAlphabetContract(t *testing.T, e *neotest.Executor, addrNetmap, addrProxy util.Uint160, name string, index, total int64) util.Uint160 { c := neotest.CompileFile(t, e.CommitteeHash, alphabetPath, path.Join(alphabetPath, "config.yml")) - args := make([]any, 5) - args[0] = addrNetmap - args[1] = addrProxy - args[2] = name - args[3] = index - args[4] = total + args := make([]interface{}, 6) + args[0] = false + args[1] = addrNetmap + args[2] = addrProxy + args[3] = name + args[4] = index + args[5] = total e.DeployContract(t, c, args) return c.Hash @@ -47,7 +48,7 @@ func newAlphabetInvoker(t *testing.T) (*neotest.Executor, *neotest.ContractInvok container.AliasFeeKey, int64(containerAliasFee)) deployBalanceContract(t, e, ctrNetmap.Hash, ctrContainer.Hash) deployContainerContract(t, e, ctrNetmap.Hash, ctrBalance.Hash, ctrNNS.Hash) - deployProxyContract(t, e) + deployProxyContract(t, e, ctrNetmap.Hash) hash := deployAlphabetContract(t, e, ctrNetmap.Hash, ctrProxy.Hash, "Az", 0, 1) alphabet := getAlphabetAcc(t, e) @@ -87,8 +88,8 @@ func TestVote(t *testing.T) { require.True(t, ok) cNewAlphabet := c.WithSigners(newAlphabet) - cNewAlphabet.InvokeFail(t, common.ErrAlphabetWitnessFailed, method, int64(0), []any{newAlphabetPub}) - c.InvokeFail(t, "invalid epoch", method, int64(1), []any{newAlphabetPub}) + cNewAlphabet.InvokeFail(t, common.ErrAlphabetWitnessFailed, method, int64(0), []interface{}{newAlphabetPub}) + c.InvokeFail(t, "invalid epoch", method, int64(1), []interface{}{newAlphabetPub}) setAlphabetRole(t, e, newAlphabetPub) transferNeoToContract(t, c) @@ -108,7 +109,7 @@ func TestVote(t *testing.T) { newInvoker := neoInvoker.WithSigners(newAlphabet) newInvoker.Invoke(t, stackitem.NewBool(true), "registerCandidate", newAlphabetPub) - c.Invoke(t, stackitem.Null{}, method, int64(0), []any{newAlphabetPub}) + c.Invoke(t, stackitem.Null{}, method, int64(0), []interface{}{newAlphabetPub}) // wait one block util // a new committee is accepted @@ -138,7 +139,7 @@ func setAlphabetRole(t *testing.T, e *neotest.Executor, new []byte) { designInvoker := e.CommitteeInvoker(designSH) // set committee as NeoFSAlphabet - designInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(noderoles.NeoFSAlphabet), []any{new}) + designInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(noderoles.NeoFSAlphabet), []interface{}{new}) } func getAlphabetAcc(t *testing.T, e *neotest.Executor) *wallet.Account { diff --git a/tests/balance_test.go b/tests/balance_test.go index 22d319b..03b076e 100644 --- a/tests/balance_test.go +++ b/tests/balance_test.go @@ -14,9 +14,10 @@ const balancePath = "../balance" func deployBalanceContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) util.Uint160 { c := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml")) - args := make([]any, 3) - args[0] = addrNetmap - args[1] = addrContainer + args := make([]interface{}, 3) + args[0] = false + args[1] = addrNetmap + args[2] = addrContainer e.DeployContract(t, c, args) return c.Hash diff --git a/tests/common_test.go b/tests/common_test.go deleted file mode 100644 index 0085d2c..0000000 --- a/tests/common_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package tests - -import ( - "math" - "math/big" - "path" - "testing" - - "github.com/nspcc-dev/neo-go/pkg/neotest" - "github.com/stretchr/testify/require" -) - -const testdataPath = "./testdata" - -func newTestdataInvoker(t *testing.T) *neotest.ContractInvoker { - e := newExecutor(t) - ctr := neotest.CompileFile(t, e.CommitteeHash, testdataPath, path.Join(testdataPath, "config.yml")) - e.DeployContract(t, ctr, nil) - return e.CommitteeInvoker(ctr.Hash) -} - -func TestEncodeU64(t *testing.T) { - // Let's check boundary values for all bit sizes: - var nums []uint64 - for i := 0; i < 64; i++ { - if i != 0 { - nums = append(nums, (1< 0, isSet) - if isSet { - require.Equal(t, owners[0], address) - } -} - -func TestFrostFSID_Client_SubjectManagement(t *testing.T) { - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - subjKey, subjAddr := newKey(t) - extraKey, _ := newKey(t) - subjLogin := "subj-login" - iamPathKV := "iam/path" - - ffsid.a.await(ffsid.cli.CreateSubject(defaultNamespace, subjKey.PublicKey())) - ffsid.a.await(ffsid.cli.SetSubjectName(subjAddr, subjLogin)) - ffsid.a.await(ffsid.cli.SetSubjectKV(subjAddr, client.IAMPathKey, iamPathKV)) - ffsid.a.await(ffsid.cli.AddSubjectKey(subjAddr, extraKey.PublicKey())) - - subj, err := ffsid.cli.GetSubject(subjAddr) - require.NoError(t, err) - require.True(t, subjKey.PublicKey().Equal(subj.PrimaryKey)) - require.Equal(t, subj.Name, subjLogin) - require.Equal(t, map[string]string{client.IAMPathKey: iamPathKV}, subj.KV) - require.ElementsMatch(t, []*keys.PublicKey{extraKey.PublicKey()}, subj.AdditionalKeys) - - ffsid.a.await(ffsid.cli.DeleteSubjectKV(subjAddr, client.IAMPathKey)) - subj, err = ffsid.cli.GetSubject(subjAddr) - require.NoError(t, err) - require.Empty(t, subj.KV) - - subjects, err := ffsid.cli.ListSubjects() - require.NoError(t, err) - require.ElementsMatch(t, subjects, []util.Uint160{subjAddr}) - - subj, err = ffsid.cli.GetSubjectByKey(extraKey.PublicKey()) - require.NoError(t, err) - require.True(t, subjKey.PublicKey().Equal(subj.PrimaryKey)) - - ffsid.a.await(ffsid.cli.RemoveSubjectKey(subjAddr, extraKey.PublicKey())) - _, err = ffsid.cli.GetSubjectByKey(extraKey.PublicKey()) - require.ErrorContains(t, err, "not found") - - ffsid.a.await(ffsid.cli.DeleteSubject(subjAddr)) - - _, err = ffsid.cli.GetSubject(subjAddr) - require.ErrorContains(t, err, "not found") - subjects, err = ffsid.cli.ListSubjects() - require.NoError(t, err) - require.Empty(t, subjects) -} - -func TestFrostFSID_Client_NamespaceManagement(t *testing.T) { - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - namespace := "namespace" - subjKey, subjAddr := newKey(t) - - ffsid.a.await(ffsid.cli.CreateNamespace(namespace)) - _, _, err := ffsid.cli.CreateNamespace(namespace) - require.ErrorContains(t, err, "already exists") - - ffsid.a.await(ffsid.cli.CreateSubject(namespace, subjKey.PublicKey())) - - ns, err := ffsid.cli.GetNamespace(namespace) - require.NoError(t, err) - require.Equal(t, namespace, ns.Name) - require.Equal(t, client.Active, ns.State) - - namespaces, err := ffsid.cli.ListNamespaces() - require.NoError(t, err) - require.ElementsMatch(t, []*client.Namespace{{State: client.Active}, ns}, namespaces) - - subj, err := ffsid.cli.GetSubject(subjAddr) - require.NoError(t, err) - require.Equal(t, namespace, subj.Namespace) - - subjects, err := ffsid.cli.ListNamespaceSubjects(namespace) - require.NoError(t, err) - require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects) - - ffsid.a.await(ffsid.cli.DeleteSubject(subjAddr)) - - subjects, err = ffsid.cli.ListNamespaceSubjects(namespace) - require.NoError(t, err) - require.Empty(t, subjects) - - namespace2 := "namespace2" - ffsid.a.await(ffsid.cli.CreateNamespace(namespace2)) - ns1, err := ffsid.cli.GetNamespace(namespace) - require.NoError(t, err) - require.Equal(t, namespace, ns1.Name) - require.Equal(t, client.Active, ns1.State) - - nsExt2, err := ffsid.cli.GetNamespaceExtended(namespace2) - require.NoError(t, err) - require.Equal(t, namespace2, nsExt2.Name) - require.Equal(t, client.Active, nsExt2.State) - - ffsid.a.await(ffsid.cli.UpdateNamespace(namespace2, client.Frozen)) - nsExt2, err = ffsid.cli.GetNamespaceExtended(namespace2) - require.NoError(t, err) - require.Equal(t, namespace2, nsExt2.Name) - require.Equal(t, client.Frozen, nsExt2.State) - - _, _, err = ffsid.cli.DeleteNamespace(namespace2) - require.ErrorContains(t, err, "namespace should be in 'purge' state for deletion") - - ffsid.a.await(ffsid.cli.UpdateNamespace(namespace2, client.Active)) - nsExt2, err = ffsid.cli.GetNamespaceExtended(namespace2) - require.NoError(t, err) - require.Equal(t, client.Active, nsExt2.State) - - subjKey2, subjAddr2 := newKey(t) - ffsid.a.await(ffsid.cli.CreateSubject(namespace2, subjKey2.PublicKey())) - - subj2, err := ffsid.cli.GetSubject(subjAddr2) - require.NoError(t, err) - require.Equal(t, namespace2, subj2.Namespace) - - ffsid.a.await(ffsid.cli.UpdateNamespace(namespace2, client.Purge)) - nsExt2, err = ffsid.cli.GetNamespaceExtended(namespace2) - require.NoError(t, err) - require.Equal(t, client.Purge, nsExt2.State) - - _, _, err = ffsid.cli.DeleteNamespace(namespace2) - require.ErrorContains(t, err, "can't delete non-empty namespace: users still present") - - ffsid.a.await(ffsid.cli.DeleteSubject(subjAddr2)) - - ffsid.a.await(ffsid.cli.UpdateNamespace(namespace2, client.Active)) - nsExt2, err = ffsid.cli.GetNamespaceExtended(namespace2) - require.NoError(t, err) - require.Equal(t, client.Active, nsExt2.State) - - groupName := "ns_group" - ffsid.a.await(ffsid.cli.CreateGroup(namespace2, groupName)) - group, err := ffsid.cli.GetGroupByName(namespace2, groupName) - require.NoError(t, err) - - ffsid.a.await(ffsid.cli.UpdateNamespace(namespace2, client.Purge)) - nsExt2, err = ffsid.cli.GetNamespaceExtended(namespace2) - require.NoError(t, err) - require.Equal(t, client.Purge, nsExt2.State) - - _, _, err = ffsid.cli.DeleteNamespace(namespace2) - require.ErrorContains(t, err, "can't delete non-empty namespace: groups still present") - - ffsid.a.await(ffsid.cli.DeleteGroup(namespace2, group.ID)) - - ffsid.a.await(ffsid.cli.DeleteNamespace(namespace2)) - _, err = ffsid.cli.GetNamespace(namespace2) - require.ErrorContains(t, err, "not found") - - namespace3 := "namespace3" - _, err = ffsid.cli.GetNamespace(namespace3) - require.ErrorContains(t, err, "not found") - _, _, err = ffsid.cli.DeleteNamespace(namespace3) - require.NoError(t, err) -} - -func TestFrostFSID_Client_DefaultNamespace(t *testing.T) { - ctx := context.Background() - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - group := "group" - subjKey, subjAddr := newKey(t) - - ffsid.a.await(ffsid.cli.CreateSubject(defaultNamespace, subjKey.PublicKey())) - - txHash, vub, err := ffsid.cli.CreateGroup(defaultNamespace, group) - groupID, err := ffsid.cli.ParseGroupID(ffsid.cli.Waiter().WaitCtx(ctx, txHash, vub, err)) - require.NoError(t, err) - ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupID)) - - namespaces, err := ffsid.cli.ListNamespaces() - require.NoError(t, err) - require.EqualValues(t, []*client.Namespace{{State: client.Active}}, namespaces) - - groups, err := ffsid.cli.ListGroups(defaultNamespace) - require.NoError(t, err) - require.EqualValues(t, []*client.Group{{ID: groupID, Name: group, Namespace: defaultNamespace}}, groups) - - subjects, err := ffsid.cli.ListNamespaceSubjects(defaultNamespace) - require.NoError(t, err) - require.EqualValues(t, []util.Uint160{subjAddr}, subjects) - - subjects, err = ffsid.cli.ListGroupSubjects(defaultNamespace, groupID) - require.NoError(t, err) - require.EqualValues(t, []util.Uint160{subjAddr}, subjects) - - subject, err := ffsid.cli.GetSubjectExtended(subjAddr) - require.NoError(t, err) - require.True(t, subjKey.PublicKey().Equal(subject.PrimaryKey)) - require.Equal(t, defaultNamespace, subject.Namespace) - require.EqualValues(t, []*client.Group{{ID: groupID, Name: group, Namespace: defaultNamespace}}, subject.Groups) -} - -func TestFrostFSID_Client_GroupManagement(t *testing.T) { - ctx := context.Background() - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - namespace := "namespace" - subjKey, subjAddr := newKey(t) - - ffsid.a.await(ffsid.cli.CreateNamespace(namespace)) - ffsid.a.await(ffsid.cli.CreateSubject(namespace, subjKey.PublicKey())) - - groupName := "group" - groupID := int64(1) - txHash, vub, err := ffsid.cli.CreateGroup(namespace, groupName) - actGroupID, err := ffsid.cli.ParseGroupID(ffsid.cli.Waiter().WaitCtx(ctx, txHash, vub, err)) - require.NoError(t, err) - require.Equal(t, groupID, actGroupID) - - _, _, err = ffsid.cli.CreateGroup(namespace, groupName) - require.ErrorContains(t, err, "is not available") - - iamARN := "arn" - ffsid.a.await(ffsid.cli.SetGroupKV(namespace, groupID, client.IAMARNKey, iamARN)) - - group, err := ffsid.cli.GetGroup(namespace, groupID) - require.NoError(t, err) - require.Equal(t, groupName, group.Name) - require.Equal(t, map[string]string{client.IAMARNKey: iamARN}, group.KV) - - ffsid.a.await(ffsid.cli.DeleteGroupKV(namespace, groupID, client.IAMARNKey)) - - groupExt, err := ffsid.cli.GetGroupExtended(namespace, groupID) - require.NoError(t, err) - require.Zero(t, groupExt.SubjectsCount) - - ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupID)) - - subjExt, err := ffsid.cli.GetSubjectExtended(subjAddr) - require.NoError(t, err) - require.ElementsMatch(t, []*client.Group{{ID: groupID, Name: groupName, Namespace: namespace, KV: map[string]string{}}}, subjExt.Groups) - - groupExt, err = ffsid.cli.GetGroupExtended(namespace, groupID) - require.NoError(t, err) - require.EqualValues(t, 1, groupExt.SubjectsCount) - - subjects, err := ffsid.cli.ListGroupSubjects(namespace, groupID) - require.NoError(t, err) - require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects) - - ffsid.a.await(ffsid.cli.RemoveSubjectFromGroup(subjAddr, groupID)) - - subjects, err = ffsid.cli.ListGroupSubjects(namespace, groupID) - require.NoError(t, err) - require.Empty(t, subjects) - - subjects, err = ffsid.cli.ListNamespaceSubjects(namespace) - require.NoError(t, err) - require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects) - - groups, err := ffsid.cli.ListGroups(namespace) - require.NoError(t, err) - require.ElementsMatch(t, []*client.Group{{ID: groupID, Name: groupName, Namespace: namespace, KV: map[string]string{}}}, groups) - - ffsid.a.await(ffsid.cli.DeleteGroup(namespace, groupID)) - _, err = ffsid.cli.GetGroup(namespace, groupID) - require.ErrorContains(t, err, "not found") - - groups, err = ffsid.cli.ListGroups(namespace) - require.NoError(t, err) - require.Empty(t, groups) -} - -type testSubject struct { - key *keys.PrivateKey - addr util.Uint160 -} - -func TestFrostFSID_Client_Lists(t *testing.T) { - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - namespaces := append([]string{defaultNamespace}, createNamespaces(t, ffsid, 3)...) - - subjects := createSubjectsInNS(t, ffsid, namespaces[1], 3) - subjects = append(subjects, createSubjectsInNS(t, ffsid, namespaces[2], 2)...) - subjects = append(subjects, createSubjectsInNS(t, ffsid, namespaces[3], 5)...) - - groups := createGroupsInNS(t, ffsid, namespaces[0], 1) - groups = append(groups, createGroupsInNS(t, ffsid, namespaces[1], 2)...) - groups = append(groups, createGroupsInNS(t, ffsid, namespaces[2], 1)...) - groups = append(groups, createGroupsInNS(t, ffsid, namespaces[3], 2)...) - - addSubjectsToGroups(t, ffsid, groups, subjects) - - nsList, err := ffsid.cli.ListNamespaces() - require.NoError(t, err) - require.ElementsMatch(t, - []*client.Namespace{ - {Name: namespaces[0], State: client.Active}, - {Name: namespaces[1], State: client.Active}, - {Name: namespaces[2], State: client.Active}, - {Name: namespaces[3], State: client.Active}, - }, - nsList) - - nonEmptyNs, err := ffsid.cli.ListNonEmptyNamespaces() - require.NoError(t, err) - require.ElementsMatch(t, namespaces[1:], nonEmptyNs) - - checkNamespaceSubjects(t, ffsid.cli, namespaces[0], subjects, 0, 0) - checkNamespaceSubjects(t, ffsid.cli, namespaces[1], subjects, 0, 3) - checkNamespaceSubjects(t, ffsid.cli, namespaces[2], subjects, 3, 5) - checkNamespaceSubjects(t, ffsid.cli, namespaces[3], subjects, 5, 10) - - nonEmptyGroups, err := ffsid.cli.ListNonEmptyGroups(namespaces[1]) - require.NoError(t, err) - require.ElementsMatch(t, []string{groups[2].Name}, nonEmptyGroups) - - checkGroupSubjects(t, ffsid.cli, groups[0], subjects, 0, 0) - checkGroupSubjects(t, ffsid.cli, groups[1], subjects, 0, 0) - checkGroupSubjects(t, ffsid.cli, groups[2], subjects, 2, 3) - checkGroupSubjects(t, ffsid.cli, groups[3], subjects, 3, 5) - checkGroupSubjects(t, ffsid.cli, groups[4], subjects, 6, 8) - checkGroupSubjects(t, ffsid.cli, groups[5], subjects, 8, 10) -} - -func createSubjectsInNS(t *testing.T, ffsid *testFrostFSIDClientInvoker, ns string, count int) []testSubject { - subjects := make([]testSubject, count) - - tx := ffsid.cli.StartTx() - for i := range subjects { - subjects[i].key, subjects[i].addr = newKey(t) - err := tx.WrapCall(ffsid.cli.CreateSubjectCall(ns, subjects[i].key.PublicKey())) - require.NoError(t, err) - } - ffsid.a.await(ffsid.cli.SendTx(tx)) - - return subjects -} - -func createGroupsInNS(t *testing.T, ffsid *testFrostFSIDClientInvoker, ns string, count int) []client.Group { - groups := make([]client.Group, count) - - tx := ffsid.cli.StartTx() - for i := range groups { - groups[i].Namespace = ns - groups[i].Name = ns + "/group" + strconv.Itoa(i+1) - - err := tx.WrapCall(ffsid.cli.CreateGroupCall(ns, groups[i].Name)) - require.NoError(t, err) - } - res := ffsid.a.await(ffsid.cli.SendTx(tx)) - - ids, err := unwrap.ArrayOfBigInts(makeValidRes(stackitem.NewArray(res.Stack)), nil) - require.NoError(t, err) - - for i, id := range ids { - groups[i].ID = id.Int64() - } - - return groups -} - -func createNamespaces(t *testing.T, ffsid *testFrostFSIDClientInvoker, count int) []string { - namespaces := make([]string, count) - - tx := ffsid.cli.StartTx() - for i := range namespaces { - namespaces[i] = "ns" + strconv.Itoa(i+1) - err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespaces[i])) - require.NoError(t, err) - } - ffsid.a.await(ffsid.cli.SendTx(tx)) - - return namespaces -} - -func addSubjectsToGroups(t *testing.T, ffsid *testFrostFSIDClientInvoker, groups []client.Group, subjects []testSubject) { - cli := ffsid.cli - tx := cli.StartTx() - - err := tx.WrapCall(cli.AddSubjectToGroupCall(subjects[2].addr, groups[2].ID)) - require.NoError(t, err) - - err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[3].addr, groups[3].ID)) - require.NoError(t, err) - err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[4].addr, groups[3].ID)) - require.NoError(t, err) - - ffsid.a.await(cli.SendTx(tx)) - - // we have to start new tx because of insufficient gas / gas limit exceeded error - tx = cli.StartTx() - - err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[6].addr, groups[4].ID)) - require.NoError(t, err) - err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[7].addr, groups[4].ID)) - require.NoError(t, err) - err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[8].addr, groups[5].ID)) - require.NoError(t, err) - err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[9].addr, groups[5].ID)) - require.NoError(t, err) - - ffsid.a.await(cli.SendTx(tx)) -} - -func checkNamespaceSubjects(t *testing.T, cli *client.Client, ns string, subjects []testSubject, start, end int) { - nsSubjects, err := cli.ListNamespaceSubjects(ns) - require.NoError(t, err) - require.ElementsMatch(t, subjSlice(subjects, start, end), nsSubjects) -} - -func checkGroupSubjects(t *testing.T, cli *client.Client, group client.Group, subjects []testSubject, start, end int) { - groupSubjects, err := cli.ListGroupSubjects(group.Namespace, group.ID) - require.NoError(t, err) - require.ElementsMatch(t, subjSlice(subjects, start, end), groupSubjects) -} - -func subjSlice(subjects []testSubject, start, end int) []util.Uint160 { - res := make([]util.Uint160, 0, end-start) - for i := start; i < end; i++ { - res = append(res, subjects[i].addr) - } - return res -} - -func TestFrostFSID_Client_UseCaseWithS3GW(t *testing.T) { - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - namespace := "namespace" - login := "login" - dataUserKey, dataUserAddr := newKey(t) - extraDataUserKey, _ := newKey(t) - - // admin - tx := ffsid.cli.StartTx() - err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespace)) - require.NoError(t, err) - err = tx.WrapCall(ffsid.cli.CreateSubjectCall(namespace, dataUserKey.PublicKey())) - require.NoError(t, err) - err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(dataUserAddr, login)) - require.NoError(t, err) - err = tx.WrapCall(ffsid.cli.AddSubjectKeyCall(dataUserAddr, extraDataUserKey.PublicKey())) - require.NoError(t, err) - ffsid.a.await(ffsid.cli.SendTx(tx)) - - // s3-gw - subj, err := ffsid.cli.GetSubjectByKey(extraDataUserKey.PublicKey()) - require.NoError(t, err) - require.Equal(t, login, subj.Name) - require.True(t, dataUserKey.PublicKey().Equal(subj.PrimaryKey)) - require.Equal(t, namespace, subj.Namespace) -} - -func TestFrostFSID_Client_UseCaseListNSSubjects(t *testing.T) { - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - namespace := "namespace" - group := "group" - groupID := int64(1) - - tx := ffsid.cli.StartTx() - err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespace)) - require.NoError(t, err) - err = tx.WrapCall(ffsid.cli.CreateGroupCall(namespace, group)) - require.NoError(t, err) - ffsid.a.await(ffsid.cli.SendTx(tx)) - - // admin - - subjects := make([]testSubject, 5) - - for i := range subjects { - tx = ffsid.cli.StartTx() - subjects[i].key, subjects[i].addr = newKey(t) - err = tx.WrapCall(ffsid.cli.CreateSubjectCall(namespace, subjects[i].key.PublicKey())) - require.NoError(t, err) - err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(subjects[i].addr, "login"+strconv.Itoa(i))) - require.NoError(t, err) - - if i > len(subjects)/2 { - err = tx.WrapCall(ffsid.cli.AddSubjectToGroupCall(subjects[i].addr, groupID)) - require.NoError(t, err) - } - ffsid.a.await(ffsid.cli.SendTx(tx)) - } - - nsSubjects, err := ffsid.cli.ListNamespaceSubjects(namespace) - require.NoError(t, err) - - res := make([]*client.SubjectExtended, len(nsSubjects)) - for i, subj := range nsSubjects { - res[i], err = ffsid.cli.GetSubjectExtended(subj) - require.NoError(t, err) - } - prettyPrintExtendedSubjects(res) -} - -func TestFrostFSID_Client_GetSubjectByName(t *testing.T) { - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - key, addr := newKey(t) - subjName := "name" - - tx := ffsid.cli.StartTx() - err := tx.WrapCall(ffsid.cli.CreateSubjectCall(defaultNamespace, key.PublicKey())) - require.NoError(t, err) - err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(addr, subjName)) - require.NoError(t, err) - ffsid.a.await(ffsid.cli.SendTx(tx)) - - subj, err := ffsid.cli.GetSubjectByName(defaultNamespace, subjName) - require.NoError(t, err) - require.Equal(t, subjName, subj.Name) - require.True(t, key.PublicKey().Equal(subj.PrimaryKey)) - require.Equal(t, defaultNamespace, subj.Namespace) -} - -func TestFrostFSID_Client_GetGroupByName(t *testing.T) { - ctx := context.Background() - ffsid, cancel := initFrostfsIFClientTest(t) - defer cancel() - - groupName := "group" - txHash, vub, err := ffsid.cli.CreateGroup(defaultNamespace, groupName) - actGroupID, err := ffsid.cli.ParseGroupID(ffsid.cli.Waiter().WaitCtx(ctx, txHash, vub, err)) - require.NoError(t, err) - - group, err := ffsid.cli.GetGroupByName(defaultNamespace, groupName) - require.NoError(t, err) - require.Equal(t, actGroupID, group.ID) - require.Equal(t, defaultNamespace, group.Namespace) - require.Equal(t, groupName, group.Name) -} - -func prettyPrintExtendedSubjects(subjects []*client.SubjectExtended) { - for _, subj := range subjects { - var sb strings.Builder - sb.WriteString(fmt.Sprintf("login: %s, namespace: %v, groups: [ ", subj.Name, subj.Namespace)) - - for _, group := range subj.Groups { - sb.WriteString(group.Namespace + ":" + group.Name + " ") - } - - sb.WriteByte(']') - fmt.Println(sb.String()) - } -} - -func TestFrostfsID_ConcurrentAddSubjectKey(t *testing.T) { - f := newFrostFSIDInvoker(t) - - newKey := func(t *testing.T) *keys.PrivateKey { - pk, err := keys.NewPrivateKey() - require.NoError(t, err) - return pk - } - - subjKey := newKey(t) - subjKeyAddr := subjKey.PublicKey().GetScriptHash() - invoker := f.OwnerInvoker() - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes()) - - additionalKey1 := newKey(t) - additionalKey2 := newKey(t) - tx1 := invoker.PrepareInvoke(t, addSubjectKeyMethod, subjKeyAddr, additionalKey1.PublicKey().Bytes()) - tx2 := invoker.PrepareInvoke(t, addSubjectKeyMethod, subjKeyAddr, additionalKey2.PublicKey().Bytes()) - - invoker.AddBlockCheckHalt(t, tx1, tx2) -} diff --git a/tests/frostfsid_test.go b/tests/frostfsid_test.go index f91865b..4089b9b 100644 --- a/tests/frostfsid_test.go +++ b/tests/frostfsid_test.go @@ -1,1142 +1,113 @@ package tests import ( - "encoding/json" - "errors" - "fmt" + "bytes" "path" + "sort" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client" - "github.com/nspcc-dev/neo-go/pkg/core/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "git.frostfs.info/TrueCloudLab/frostfs-contract/container" + "github.com/mr-tron/base58" "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/encoding/address" "github.com/nspcc-dev/neo-go/pkg/neotest" - "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" "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/wallet" "github.com/stretchr/testify/require" ) const frostfsidPath = "../frostfsid" -const ( - defaultNamespace = "" - customNamespace = "custom" -) - -const ( - setAdminMethod = "setAdmin" - getAdminMethod = "getAdmin" - clearAdminMethod = "clearAdmin" - - createSubjectMethod = "createSubject" - getSubjectMethod = "getSubject" - listSubjectsMethod = "listSubjects" - addSubjectKeyMethod = "addSubjectKey" - removeSubjectKeyMethod = "removeSubjectKey" - getSubjectByKeyMethod = "getSubjectByKey" - getSubjectKeyByNameMethod = "getSubjectKeyByName" - setSubjectNameMethod = "setSubjectName" - setSubjectKVMethod = "setSubjectKV" - deleteSubjectKVMethod = "deleteSubjectKV" - deleteSubjectMethod = "deleteSubject" - - createNamespaceMethod = "createNamespace" - getNamespaceMethod = "getNamespace" - getNamespaceExtendedMethod = "getNamespaceExtended" - updateNamespaceMethod = "updateNamespace" - deleteNamespaceMethod = "deleteNamespace" - listNamespacesMethod = "listNamespaces" - listNamespaceSubjectsMethod = "listNamespaceSubjects" - - createGroupMethod = "createGroup" - getGroupMethod = "getGroup" - getGroupExtendedMethod = "getGroupExtended" - getGroupIDByNameMethod = "getGroupIDByName" - setGroupNameMethod = "setGroupName" - setGroupKVMethod = "setGroupKV" - deleteGroupKVMethod = "deleteGroupKV" - listGroupsMethod = "listGroups" - addSubjectToGroupMethod = "addSubjectToGroup" - removeSubjectFromGroupMethod = "removeSubjectFromGroup" - listGroupSubjectsMethod = "listGroupSubjects" - deleteGroupMethod = "deleteGroup" - - nsActiveState = "active" -) - -const ( - frozenState = "frozen" - purgeState = "purge" - namespaceNonActive = "namespace is non-active" - notWitnessedError = "not witnessed" - notFoundError = "namespace not found" - cantDeleteNonEmptyNamespceGroupsPresent = "can't delete non-empty namespace: groups still present" - cantDeleteNonEmptyNamespceUsersPresent = "can't delete non-empty namespace: users still present" - namespaceShouldBeInPurgeStateError = "namespace should be in 'purge' state for deletion" -) - -type testFrostFSIDInvoker struct { - e *neotest.Executor - contractHash util.Uint160 - owner *wallet.Account -} - -func (f *testFrostFSIDInvoker) OwnerInvoker() *neotest.ContractInvoker { - return f.e.NewInvoker(f.contractHash, neotest.NewSingleSigner(f.owner)) -} - -func (f *testFrostFSIDInvoker) CommitteeInvoker() *neotest.ContractInvoker { - return f.e.CommitteeInvoker(f.contractHash) -} - -func (f *testFrostFSIDInvoker) AnonInvoker(t *testing.T) *neotest.ContractInvoker { - acc, err := wallet.NewAccount() - require.NoError(t, err) - - return f.e.NewInvoker(f.contractHash, newSigner(t, f.CommitteeInvoker(), acc)) -} - -func newSigner(t *testing.T, c *neotest.ContractInvoker, acc *wallet.Account) neotest.Signer { - amount := int64(100_0000_0000) - - tx := c.NewTx(t, []neotest.Signer{c.Validator}, - c.NativeHash(t, nativenames.Gas), "transfer", - c.Validator.ScriptHash(), acc.Contract.ScriptHash(), amount, nil) - c.AddNewBlock(t, tx) - c.CheckHalt(t, tx.Hash()) - return neotest.NewSingleSigner(acc) -} - -func deployFrostFSIDContract(t *testing.T, e *neotest.Executor, contractOwner util.Uint160) util.Uint160 { - args := make([]any, 5) - args[0] = contractOwner +func deployFrostFSIDContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) util.Uint160 { + args := make([]interface{}, 5) + args[0] = false + args[1] = addrNetmap + args[2] = addrContainer c := neotest.CompileFile(t, e.CommitteeHash, frostfsidPath, path.Join(frostfsidPath, "config.yml")) e.DeployContract(t, c, args) return c.Hash } -func newFrostFSIDInvoker(t *testing.T) *testFrostFSIDInvoker { +func newFrostFSIDInvoker(t *testing.T) *neotest.ContractInvoker { e := newExecutor(t) - acc, err := wallet.NewAccount() - require.NoError(t, err) + ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) + ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml")) + ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml")) + ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml")) - h := deployFrostFSIDContract(t, e, acc.ScriptHash()) + e.DeployContract(t, ctrNNS, nil) + deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash, + container.RegistrationFeeKey, int64(containerFee), + container.AliasFeeKey, int64(containerAliasFee)) + deployBalanceContract(t, e, ctrNetmap.Hash, ctrContainer.Hash) + deployContainerContract(t, e, ctrNetmap.Hash, ctrBalance.Hash, ctrNNS.Hash) + h := deployFrostFSIDContract(t, e, ctrNetmap.Hash, ctrContainer.Hash) + return e.CommitteeInvoker(h) +} - newSigner(t, e.CommitteeInvoker(h), acc) +func TestFrostFSID_AddKey(t *testing.T) { + e := newFrostFSIDInvoker(t) - return &testFrostFSIDInvoker{ - e: e, - contractHash: h, - owner: acc, + pubs := make([][]byte, 6) + for i := range pubs { + p, err := keys.NewPrivateKey() + require.NoError(t, err) + pubs[i] = p.PublicKey().Bytes() } -} + acc := e.NewAccount(t) + owner, _ := base58.Decode(address.Uint160ToString(acc.ScriptHash())) + e.Invoke(t, stackitem.Null{}, "addKey", owner, + []interface{}{pubs[0], pubs[1]}) -func TestFrostFSID_ContractOwnersManagement(t *testing.T) { - f := newFrostFSIDInvoker(t) - - anonInvoker := f.AnonInvoker(t) - anonInvokerHash := anonInvoker.Signers[0].ScriptHash() - invoker := f.OwnerInvoker() - invokerHash := invoker.Signers[0].ScriptHash() - committeeInvoker := f.CommitteeInvoker() - - checkOwner(t, anonInvoker, invokerHash) - - anonInvoker.InvokeFail(t, notWitnessedError, createNamespaceMethod, "namespace") - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, "namespace") - - t.Run("setAdmin is only allowed for committee", func(t *testing.T) { - invoker.InvokeFail(t, notWitnessedError, setAdminMethod, anonInvokerHash) + sort.Slice(pubs[:2], func(i, j int) bool { + return bytes.Compare(pubs[i], pubs[j]) == -1 }) - - t.Run("replace owner", func(t *testing.T) { - committeeInvoker.Invoke(t, stackitem.Null{}, setAdminMethod, anonInvokerHash) - checkOwner(t, anonInvoker, anonInvokerHash) - - invoker.InvokeFail(t, notWitnessedError, createNamespaceMethod, "namespace2") - anonInvoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, "namespace2") - }) - t.Run("remove owner", func(t *testing.T) { - committeeInvoker.Invoke(t, stackitem.Null{}, clearAdminMethod) - checkOwner(t, anonInvoker) - - invoker.InvokeFail(t, notWitnessedError, createNamespaceMethod, "namespace3") - anonInvoker.InvokeFail(t, notWitnessedError, createNamespaceMethod, "namespace3") - }) -} - -func checkOwner(t *testing.T, invoker *neotest.ContractInvoker, owner ...util.Uint160) { - if len(owner) > 1 { - require.Fail(t, "invalid testcase") + arr := []stackitem.Item{ + stackitem.NewBuffer(pubs[0]), + stackitem.NewBuffer(pubs[1]), } + e.Invoke(t, stackitem.NewArray(arr), "key", owner) - s, err := invoker.TestInvoke(t, getAdminMethod) - require.NoError(t, err) - require.Equal(t, 1, s.Len(), "unexpected number items on stack") - if len(owner) == 0 { - _, isMissing := s.Pop().Item().(stackitem.Null) - require.True(t, isMissing) - return - } + t.Run("multiple addKey per block", func(t *testing.T) { + tx1 := e.PrepareInvoke(t, "addKey", owner, []interface{}{pubs[2]}) + tx2 := e.PrepareInvoke(t, "addKey", owner, []interface{}{pubs[3], pubs[4]}) + e.AddNewBlock(t, tx1, tx2) + e.CheckHalt(t, tx1.Hash(), stackitem.Null{}) + e.CheckHalt(t, tx2.Hash(), stackitem.Null{}) - bs, err := s.Pop().Item().TryBytes() - require.NoError(t, err) - require.Equal(t, bs, owner[0].BytesBE()) -} - -func TestFrostFSID_DefaultNamespace(t *testing.T) { - f := newFrostFSIDInvoker(t) - - subjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - subjKeyAddr := subjKey.PublicKey().GetScriptHash() - - invoker := f.OwnerInvoker() - - groupID := int64(1) - groupName := "group" - - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Make(groupID), createGroupMethod, defaultNamespace, groupName) - invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKeyAddr, groupID) - invoker.Invoke(t, stackitem.Null{}, removeSubjectFromGroupMethod, subjKeyAddr, groupID) - invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, defaultNamespace, groupID) - invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjKeyAddr) -} - -func TestFrostFSID_SubjectManagement(t *testing.T) { - f := newFrostFSIDInvoker(t) - - subjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - subjKeyAddr := subjKey.PublicKey().GetScriptHash() - - anonInvoker := f.AnonInvoker(t) - invoker := f.OwnerInvoker() - - anonInvoker.InvokeFail(t, notWitnessedError, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes()) - invoker.InvokeFail(t, "already exists", createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes()) - - s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr) - require.NoError(t, err) - - subj := parseSubject(t, s) - require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey)) - - t.Run("add subject key", func(t *testing.T) { - subjNewKey, err := keys.NewPrivateKey() - require.NoError(t, err) - - anonInvoker.InvokeFail(t, notWitnessedError, addSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes()) - - s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr) - require.NoError(t, err) - subj := parseSubject(t, s) - require.Len(t, subj.AdditionalKeys, 1) - require.True(t, subjNewKey.PublicKey().Equal(subj.AdditionalKeys[0])) - - t.Run("get subject by additional key", func(t *testing.T) { - s, err = anonInvoker.TestInvoke(t, getSubjectByKeyMethod, subjNewKey.PublicKey().Bytes()) - require.NoError(t, err) - subj := parseSubject(t, s) - require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey), "keys must be the same") - - s, err = anonInvoker.TestInvoke(t, getSubjectByKeyMethod, subjKey.PublicKey().Bytes()) - require.NoError(t, err) - subj = parseSubject(t, s) - require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey), "keys must be the same") - - t.Run("with GetSubject", func(t *testing.T) { - s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKey.PublicKey().GetScriptHash()) - require.NoError(t, err) - subj = parseSubject(t, s) - require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey), "keys must be the same") - }) - - t.Run("remove subject key", func(t *testing.T) { - anonInvoker.InvokeFail(t, notWitnessedError, removeSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, removeSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes()) - - anonInvoker.InvokeFail(t, "not found", getSubjectByKeyMethod, subjNewKey.PublicKey().Bytes()) - }) + sort.Slice(pubs[:5], func(i, j int) bool { + return bytes.Compare(pubs[i], pubs[j]) == -1 }) - }) - - t.Run("set subject name", func(t *testing.T) { - login := "some-login" - - anonInvoker.InvokeFail(t, notWitnessedError, setSubjectNameMethod, subjKeyAddr, login) - invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr, login) - - s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr) - require.NoError(t, err) - subj = parseSubject(t, s) - require.Equal(t, login, subj.Name) - }) - - t.Run("set subject KVs", func(t *testing.T) { - iamPath := "iam/path" - - anonInvoker.InvokeFail(t, notWitnessedError, setSubjectKVMethod, subjKeyAddr, client.IAMPathKey, iamPath) - invoker.Invoke(t, stackitem.Null{}, setSubjectKVMethod, subjKeyAddr, client.IAMPathKey, iamPath) - - s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr) - require.NoError(t, err) - subj = parseSubject(t, s) - require.Equal(t, iamPath, subj.KV[client.IAMPathKey]) - - anonInvoker.InvokeFail(t, notWitnessedError, deleteSubjectKVMethod, subjKeyAddr, client.IAMPathKey) - invoker.Invoke(t, stackitem.Null{}, deleteSubjectKVMethod, subjKeyAddr, client.IAMPathKey) - - s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr) - require.NoError(t, err) - subj = parseSubject(t, s) - require.Empty(t, subj.KV) - }) - - t.Run("list subjects", func(t *testing.T) { - newSubjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, newSubjKey.PublicKey().Bytes()) - - s, err = anonInvoker.TestInvoke(t, listSubjectsMethod) - require.NoError(t, err) - - addresses, err := unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(readIteratorAll(s))), nil) - require.NoError(t, err) - require.Len(t, addresses, 2) - require.ElementsMatch(t, addresses, []util.Uint160{subjKeyAddr, newSubjKey.PublicKey().GetScriptHash()}) - }) - - t.Run("subject operations for non-active namespace", func(t *testing.T) { - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, customNamespace) - - baseKey, err := keys.NewPrivateKey() - require.NoError(t, err) - baseAddr, baseBytes := baseKey.PublicKey().GetScriptHash(), baseKey.PublicKey().Bytes() - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - - invoker.InvokeFail(t, namespaceNonActive, createSubjectMethod, customNamespace, baseBytes) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, createSubjectMethod, customNamespace, baseBytes) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, "active") - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, customNamespace, baseBytes) - - t.Run("addSubjectKey", func(t *testing.T) { - newSubjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - keyBytes := newSubjKey.PublicKey().Bytes() - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, addSubjectKeyMethod, baseAddr, keyBytes) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, addSubjectKeyMethod, baseAddr, keyBytes) - }) - - t.Run("setSubjectKV", func(t *testing.T) { - const key, val = "key", "val" - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, setSubjectKVMethod, baseAddr, key, val) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, setSubjectKVMethod, baseAddr, key, val) - }) - - t.Run("setSubjectName", func(t *testing.T) { - const login = "testlogin" - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, setSubjectNameMethod, baseAddr, login) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, setSubjectNameMethod, baseAddr, login) - }) - }) - - anonInvoker.InvokeFail(t, notWitnessedError, deleteSubjectMethod, subjKeyAddr) - invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjKeyAddr) - - anonInvoker.InvokeFail(t, "subject not found", getSubjectMethod, subjKeyAddr) -} - -func TestFrostFSIS_SubjectNameRelatedInvariants(t *testing.T) { - f := newFrostFSIDInvoker(t) - - subjName1 := "subj1" - subjKey1, err := keys.NewPrivateKey() - require.NoError(t, err) - subjKeyAddr1 := subjKey1.PublicKey().GetScriptHash() - - subjName2 := "subj2" - subjKey2, err := keys.NewPrivateKey() - require.NoError(t, err) - subjKeyAddr2 := subjKey2.PublicKey().GetScriptHash() - - subjName3 := "subj3" - subjKey3, err := keys.NewPrivateKey() - require.NoError(t, err) - subjKeyAddr3 := subjKey3.PublicKey().GetScriptHash() - - invoker := f.OwnerInvoker() - - ns1, ns2 := "ns1", "ns2" - - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns1) - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns2) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns1, subjKey1.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr1, subjName1) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns1, subjKey2.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns2, subjKey3.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr3, subjName3) - - // Check that we can find public key by name for subj1 (with name) - // and cannot find key for subj2 (without name) - s, err := invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns1, subjName1) - checkPublicKeyResult(t, s, err, subjKey1) - s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns1, subjName2) - checkPublicKeyResult(t, s, err, nil) - - // Check that we can find public key for by name for subj2 when we set its name - invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr2, subjName2) - s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns1, subjName2) - checkPublicKeyResult(t, s, err, subjKey2) - - // Check that we cannot set for second subject name that the first subject has already taken - invoker.InvokeFail(t, "not available", setSubjectNameMethod, subjKeyAddr2, subjName1) - - // Check that we cannot find public key by name for subject that was removed - invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjKeyAddr2) - s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns1, subjName2) - checkPublicKeyResult(t, s, err, nil) - - // Check that subj3 can have the same name as subj1 if they belong to different namespaces - // Also check that after subject renaming its key cannot be found by old name - invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr3, subjName1) - s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName1) - checkPublicKeyResult(t, s, err, subjKey3) - s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName3) - checkPublicKeyResult(t, s, err, nil) -} - -func TestFrostFSIS_GroupNameRelatedInvariants(t *testing.T) { - f := newFrostFSIDInvoker(t) - - groupName1, groupName2 := "group1", "group2" - groupID1, groupID2 := int64(1), int64(2) - - invoker := f.OwnerInvoker() - - ns1, ns2 := "ns1", "ns2" - - // Create two group - // Create two namespace. - // Add these groups to ns1 - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns1) - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns2) - invoker.Invoke(t, stackitem.Make(groupID1), createGroupMethod, ns1, groupName1) - invoker.Invoke(t, stackitem.Make(groupID2), createGroupMethod, ns1, groupName2) - - // Check that we can find group id by name for group1 in ns1 and not in ns2 - s, err := invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, groupName1) - checkGroupIDResult(t, s, err, groupID1) - s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns2, groupName1) - checkGroupIDResult(t, s, err, -1) - - // Check that we cannot set for second group name that the first subject has already taken - invoker.InvokeFail(t, "not available", setGroupNameMethod, ns1, groupID1, groupName2) - - // Check that we cannot create group with the same name in namespace, but can in another - invoker.InvokeFail(t, "not available", createGroupMethod, ns1, groupName2) - invoker.Invoke(t, stackitem.Make(3), createGroupMethod, ns2, groupName2) - - // Check that we cannot find group id by name for group that was removed - invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, ns1, groupID2) - s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, groupName2) - checkGroupIDResult(t, s, err, -1) - - // Check that we can create group with the name that was freed after deleting - invoker.Invoke(t, stackitem.Make(4), createGroupMethod, ns1, groupName2) - - // Check that after group renaming its id cannot be found by old name - newGroupName := "new" - invoker.Invoke(t, stackitem.Null{}, setGroupNameMethod, ns1, groupID1, newGroupName) - s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, groupName1) - checkGroupIDResult(t, s, err, -1) - s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, newGroupName) - checkGroupIDResult(t, s, err, groupID1) -} - -func TestFrostFSID_NamespaceManagement(t *testing.T) { - f := newFrostFSIDInvoker(t) - - anonInvoker := f.AnonInvoker(t) - invoker := f.OwnerInvoker() - - namespace := "some-namespace" - - anonInvoker.InvokeFail(t, notWitnessedError, createNamespaceMethod, namespace) - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, namespace) - invoker.InvokeFail(t, "already exists", createNamespaceMethod, namespace) - - s, err := anonInvoker.TestInvoke(t, getNamespaceMethod, namespace) - require.NoError(t, err) - - ns := parseNamespace(t, s.Pop().Item()) - require.Equal(t, namespace, ns.Name) - require.Equal(t, nsActiveState, ns.State) - - t.Run("add user to namespace", func(t *testing.T) { - subjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns.Name, subjKey.PublicKey().Bytes()) - - subjName := "name" - subjAddress := subjKey.PublicKey().GetScriptHash() - invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjAddress, subjName) - - s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjAddress) - require.NoError(t, err) - subj := parseSubject(t, s) - require.Equal(t, namespace, subj.Namespace) - - t.Run("list namespace subjects", func(t *testing.T) { - s, err := anonInvoker.TestInvoke(t, listNamespaceSubjectsMethod, namespace) - require.NoError(t, err) - - addresses, err := unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(readIteratorAll(s))), nil) - require.NoError(t, err) - require.ElementsMatch(t, addresses, []util.Uint160{subjAddress}) - }) - - t.Run("get subject key by name", func(t *testing.T) { - s, err := anonInvoker.TestInvoke(t, getSubjectKeyByNameMethod, namespace, subjName) - require.NoError(t, err) - - foundKey, err := unwrap.PublicKey(makeValidRes(s.Pop().Item()), nil) - require.NoError(t, err) - require.Equal(t, subjKey.PublicKey(), foundKey) - }) - - t.Run("list namespaces", func(t *testing.T) { - namespace2 := "some-namespace2" - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, namespace2) - - s, err := anonInvoker.TestInvoke(t, listNamespacesMethod) - require.NoError(t, err) - - namespaces := parseNamespaces(t, readIteratorAll(s)) - require.NoError(t, err) - require.ElementsMatch(t, - namespaces, - []Namespace{ - {Name: defaultNamespace, State: nsActiveState}, - {Name: namespace, State: nsActiveState}, - {Name: namespace2, State: nsActiveState}, - }) - - t.Run("find namespaces with some subjects", func(t *testing.T) { - for _, ns := range namespaces { - s, err := anonInvoker.TestInvoke(t, getNamespaceExtendedMethod, ns.Name) - require.NoError(t, err) - - nsExt := parseNamespaceExtended(t, s.Pop().Item()) - if nsExt.SubjectsCount > 0 { - require.Equal(t, namespace, nsExt.Name) - require.Equal(t, nsActiveState, nsExt.State) - } - } - }) - }) - }) - - t.Run("update namespace", func(t *testing.T) { - anonInvoker.InvokeFail(t, notWitnessedError, updateNamespaceMethod, namespace, "frozen") - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, namespace, "frozen") - require.NoError(t, err) - - s, err = invoker.TestInvoke(t, getNamespaceMethod, namespace) - require.NoError(t, err) - - ns := parseNamespace(t, s.Pop().Item()) - require.Equal(t, namespace, ns.Name) - require.Equal(t, "frozen", ns.State) - }) - - t.Run("delete namespace", func(t *testing.T) { - namespace3 := "some-namespace3" - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, namespace3) - - s, err = invoker.TestInvoke(t, getNamespaceMethod, namespace3) - require.NoError(t, err) - - ns := parseNamespace(t, s.Pop().Item()) - require.Equal(t, namespace3, ns.Name) - - t.Run("delete existing namespace not in a 'purge' state", func(t *testing.T) { - anonInvoker.InvokeFail(t, notWitnessedError, deleteNamespaceMethod, namespace3) - invoker.InvokeFail(t, namespaceShouldBeInPurgeStateError, deleteNamespaceMethod, namespace3) - }) - - subjKey, err := keys.NewPrivateKey() - subjKeyAddr := subjKey.PublicKey().GetScriptHash() - require.NoError(t, err) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns.Name, subjKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, namespace3, "purge") - - t.Run("delete namespace with user fails", func(t *testing.T) { - invoker.InvokeFail(t, cantDeleteNonEmptyNamespceUsersPresent, deleteNamespaceMethod, namespace3) - }) - - invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjKeyAddr) - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, namespace3, "active") - - groupID1 := int64(1) - groupName1 := "group1" - invoker.Invoke(t, stackitem.Make(groupID1), createGroupMethod, ns.Name, groupName1) - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, namespace3, "purge") - - t.Run("delete namespace with group fails", func(t *testing.T) { - invoker.InvokeFail(t, cantDeleteNonEmptyNamespceGroupsPresent, deleteNamespaceMethod, namespace3) - }) - - invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, ns.Name, groupID1) - - t.Run("delete existing namespace", func(t *testing.T) { - anonInvoker.InvokeFail(t, notWitnessedError, deleteNamespaceMethod, namespace3) - invoker.Invoke(t, stackitem.Null{}, deleteNamespaceMethod, namespace3) - invoker.InvokeFail(t, notFoundError, getNamespaceMethod, namespace3) - }) - - t.Run("delete non-existing namespace", func(t *testing.T) { - nonExistingNamespace := "non-existing-namespace" - invoker.InvokeFail(t, notFoundError, getNamespaceMethod, nonExistingNamespace) - anonInvoker.InvokeFail(t, notWitnessedError, deleteNamespaceMethod, nonExistingNamespace) - invoker.Invoke(t, stackitem.Null{}, deleteNamespaceMethod, nonExistingNamespace) - }) - }) -} - -func TestFrostFSID_GroupManagement(t *testing.T) { - f := newFrostFSIDInvoker(t) - - anonInvoker := f.AnonInvoker(t) - invoker := f.OwnerInvoker() - - nsName := "namespace" - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, nsName) - - groupID := int64(1) - groupName := "group" - anonInvoker.InvokeFail(t, notWitnessedError, createGroupMethod, nsName, groupName) - invoker.Invoke(t, stackitem.Make(groupID), createGroupMethod, nsName, groupName) - - s, err := anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID) - require.NoError(t, err) - group := parseGroup(t, s.Pop().Item()) - require.Equal(t, groupID, group.ID) - require.Equal(t, groupName, group.Name) - - s, err = anonInvoker.TestInvoke(t, listGroupsMethod, nsName) - require.NoError(t, err) - groups := parseGroups(t, readIteratorAll(s)) - require.ElementsMatch(t, groups, []Group{{ID: groupID, Name: groupName, Namespace: nsName}}) - - t.Run("add subjects to group", func(t *testing.T) { - subjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, nsName, subjKey.PublicKey().Bytes()) - - subjAddress := subjKey.PublicKey().GetScriptHash() - anonInvoker.InvokeFail(t, "not witnessed", addSubjectToGroupMethod, subjAddress, groupID) - invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjAddress, groupID) - - t.Run("list group subjects", func(t *testing.T) { - s, err = anonInvoker.TestInvoke(t, listGroupSubjectsMethod, nsName, groupID) - require.NoError(t, err) - - addresses, err := unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(readIteratorAll(s))), nil) - require.NoError(t, err) - require.ElementsMatch(t, addresses, []util.Uint160{subjAddress}) - - anonInvoker.InvokeFail(t, "not witnessed", removeSubjectFromGroupMethod, subjAddress, groupID) - invoker.Invoke(t, stackitem.Null{}, removeSubjectFromGroupMethod, subjAddress, groupID) - - s, err = anonInvoker.TestInvoke(t, listGroupSubjectsMethod, nsName, groupID) - require.NoError(t, err) - - addresses, err = unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(readIteratorAll(s))), nil) - require.NoError(t, err) - require.Empty(t, addresses) - - t.Run("get group extended", func(t *testing.T) { - subjectsCount := 10 - for i := 0; i < subjectsCount; i++ { - subjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, nsName, subjKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), groupID) - } - - s, err = anonInvoker.TestInvoke(t, getGroupExtendedMethod, nsName, groupID) - require.NoError(t, err) - groupExt := parseGroupExtended(t, s.Pop().Item()) - require.Equal(t, groupID, groupExt.ID) - require.Equal(t, groupName, groupExt.Name) - require.Empty(t, groupExt.KV) - require.EqualValues(t, subjectsCount, groupExt.SubjectsCount) - }) - }) - }) - - t.Run("set group name", func(t *testing.T) { - newGroupName := "new-name" - - anonInvoker.InvokeFail(t, notWitnessedError, setGroupNameMethod, nsName, groupID, newGroupName) - invoker.Invoke(t, stackitem.Null{}, setGroupNameMethod, nsName, groupID, newGroupName) - - s, err = anonInvoker.TestInvoke(t, getGroupIDByNameMethod, nsName, newGroupName) - require.NoError(t, err) - require.Equal(t, groupID, s.Pop().BigInt().Int64()) - - s, err = anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID) - require.NoError(t, err) - group = parseGroup(t, s.Pop().Item()) - require.Equal(t, newGroupName, group.Name) - }) - - t.Run("set group KVs", func(t *testing.T) { - iamARN := "arn" - - anonInvoker.InvokeFail(t, notWitnessedError, setGroupKVMethod, nsName, groupID, client.IAMARNKey, iamARN) - invoker.Invoke(t, stackitem.Null{}, setGroupKVMethod, nsName, groupID, client.IAMARNKey, iamARN) - - s, err = anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID) - require.NoError(t, err) - group = parseGroup(t, s.Pop().Item()) - require.Equal(t, iamARN, group.KV[client.IAMARNKey]) - - anonInvoker.InvokeFail(t, notWitnessedError, deleteGroupKVMethod, nsName, groupID, client.IAMARNKey) - invoker.Invoke(t, stackitem.Null{}, deleteGroupKVMethod, nsName, groupID, client.IAMARNKey) - - s, err = anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID) - require.NoError(t, err) - group = parseGroup(t, s.Pop().Item()) - require.Empty(t, group.KV) - }) - - t.Run("delete group", func(t *testing.T) { - anonInvoker.InvokeFail(t, notWitnessedError, deleteGroupMethod, nsName, groupID) - invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, nsName, groupID) - - anonInvoker.InvokeFail(t, "group not found", getGroupMethod, nsName, groupID) - - s, err = anonInvoker.TestInvoke(t, listGroupsMethod, nsName) - require.NoError(t, err) - groups := parseGroups(t, readIteratorAll(s)) - require.Empty(t, groups) - }) - - t.Run("operations with non-active namespace", func(t *testing.T) { - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, customNamespace) - - customGroupID := int64(2) - customGroupName := "customGroup" - invoker.Invoke(t, stackitem.Make(customGroupID), createGroupMethod, customNamespace, customGroupName) - - subjKey, err := keys.NewPrivateKey() - require.NoError(t, err) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, customNamespace, subjKey.PublicKey().Bytes()) - - t.Run("createGroup", func(t *testing.T) { - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, createGroupMethod, customNamespace, customGroupName) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, createGroupMethod, customNamespace, customGroupName) - }) - - t.Run("addSubjectToGroup", func(t *testing.T) { - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), customGroupID) - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), customGroupID) - }) - - t.Run("setGroupKV", func(t *testing.T) { - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, setGroupKVMethod, customNamespace, customGroupID, client.IAMARNKey, "arn") - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, setGroupKVMethod, customNamespace, customGroupID, client.IAMARNKey, "arn") - }) - - t.Run("setGroupName", func(t *testing.T) { - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, frozenState) - invoker.InvokeFail(t, namespaceNonActive, setGroupNameMethod, customNamespace, customGroupID, "newCustomGroup") - - invoker.Invoke(t, stackitem.Null{}, updateNamespaceMethod, customNamespace, purgeState) - invoker.InvokeFail(t, namespaceNonActive, setGroupNameMethod, customNamespace, customGroupID, "newCustomGroup") - }) - }) -} - -func TestAdditionalKeyFromPrimarySubject(t *testing.T) { - f := newFrostFSIDInvoker(t) - invoker := f.OwnerInvoker() - - subjAPrimaryKey, err := keys.NewPrivateKey() - require.NoError(t, err) - subjAKeyAddr := subjAPrimaryKey.PublicKey().GetScriptHash() - - subjBPrimaryKey, err := keys.NewPrivateKey() - require.NoError(t, err) - subjBKeyAddr := subjBPrimaryKey.PublicKey().GetScriptHash() - - subjCPrimaryKey, err := keys.NewPrivateKey() - require.NoError(t, err) - - subjDPrimaryKey, err := keys.NewPrivateKey() - require.NoError(t, err) - - subjFPrimaryKey, err := keys.NewPrivateKey() - require.NoError(t, err) - - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjAPrimaryKey.PublicKey().Bytes()) - - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjBPrimaryKey.PublicKey().Bytes()) - - invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjAPrimaryKey.PublicKey().Bytes()) - - invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjCPrimaryKey.PublicKey().Bytes()) - invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjCPrimaryKey.PublicKey().Bytes()) - - invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes()) - - invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjDPrimaryKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, removeSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjBKeyAddr, subjDPrimaryKey.PublicKey().Bytes()) - - invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjBKeyAddr) - invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes()) - - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjFPrimaryKey.PublicKey().Bytes()) - invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjFPrimaryKey.PublicKey().GetScriptHash()) - invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjFPrimaryKey.PublicKey().Bytes()) -} - -func TestFrostFSIS_GroupsAfterUpdate(t *testing.T) { - countNamesepce := 2 - f := newFrostFSIDInvoker(t) - invoker := f.OwnerInvoker() - - groupid := int64(1) - - for i := range countNamesepce { - namespace := fmt.Sprintf("nm_%d", i) - invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, namespace) - } - - for i := range 5 { - namespace := fmt.Sprintf("nm_%d", i%2) - groupName := fmt.Sprintf("group_%d", groupid) - - invoker.Invoke(t, stackitem.Make(groupid), createGroupMethod, namespace, groupName) - s, err := invoker.TestInvoke(t, getGroupIDByNameMethod, namespace, groupName) - checkGroupIDResult(t, s, err, groupid) - groupid++ - } - - args := make([]any, 2) - args[0] = f.owner.ScriptHash() - args[1] = 21 * 1_000 - - c := neotest.CompileFile(t, f.e.CommitteeHash, frostfsidPath, path.Join(frostfsidPath, "config.yml")) - - nef, err := c.NEF.Bytes() - require.NoError(t, err) - - manifest, err := json.Marshal(c.Manifest) - require.NoError(t, err) - - f.CommitteeInvoker().Invoke(t, stackitem.Null{}, "update", nef, manifest, args) - - for i := range 5 { - namespace := fmt.Sprintf("nm_%d", i%2) - groupName := fmt.Sprintf("group_%d", groupid) - - invoker.Invoke(t, stackitem.Make(groupid), createGroupMethod, namespace, groupName) - s, err := invoker.TestInvoke(t, getGroupIDByNameMethod, namespace, groupName) - checkGroupIDResult(t, s, err, groupid) - groupid++ - } -} - -func checkPublicKeyResult(t *testing.T, s *vm.Stack, err error, key *keys.PrivateKey) { - if key == nil { - require.ErrorContains(t, err, "not found") - return - } - - require.NoError(t, err) - foundKey, err := unwrap.PublicKey(makeValidRes(s.Pop().Item()), nil) - require.NoError(t, err) - require.Equal(t, key.PublicKey(), foundKey) -} - -func checkGroupIDResult(t *testing.T, s *vm.Stack, err error, groupID int64) { - if groupID == -1 { - require.ErrorContains(t, err, "not found") - return - } - - require.NoError(t, err) - foundGroupID, err := unwrap.Int64(makeValidRes(s.Pop().Item()), nil) - require.NoError(t, err) - require.Equal(t, groupID, foundGroupID) -} - -func readIteratorAll(s *vm.Stack) []stackitem.Item { - iter := s.Pop().Value().(*storage.Iterator) - - stackItems := make([]stackitem.Item, 0) - for iter.Next() { - stackItems = append(stackItems, iter.Value()) - } - - return stackItems -} - -type Subject struct { - PrimaryKey keys.PublicKey - AdditionalKeys keys.PublicKeys - Namespace string - Name string - KV map[string]string -} - -func parseSubject(t *testing.T, s *vm.Stack) Subject { - var subj Subject - - subjStruct := s.Pop().Array() - require.Len(t, subjStruct, 5) - - pkBytes, err := subjStruct[0].TryBytes() - require.NoError(t, err) - err = subj.PrimaryKey.DecodeBytes(pkBytes) - require.NoError(t, err) - - if !subjStruct[1].Equals(stackitem.Null{}) { - subj.AdditionalKeys, err = unwrap.ArrayOfPublicKeys(makeValidRes(subjStruct[1]), nil) - require.NoError(t, err) - } - - nsBytes, err := subjStruct[2].TryBytes() - require.NoError(t, err) - subj.Namespace = string(nsBytes) - - nameBytes, err := subjStruct[3].TryBytes() - require.NoError(t, err) - subj.Name = string(nameBytes) - - subj.KV, err = parseMap(subjStruct[4]) - require.NoError(t, err) - - return subj -} - -func parseMap(item stackitem.Item) (map[string]string, error) { - if item.Equals(stackitem.Null{}) { - return nil, nil - } - - metaMap, err := unwrap.Map(makeValidRes(item), nil) - if err != nil { - return nil, err - } - - meta, ok := metaMap.Value().([]stackitem.MapElement) - if !ok { - return nil, errors.New("invalid map type") - } - - res := make(map[string]string, len(meta)) - for _, element := range meta { - key, err := element.Key.TryBytes() - if err != nil { - return nil, err + arr = []stackitem.Item{ + stackitem.NewBuffer(pubs[0]), + stackitem.NewBuffer(pubs[1]), + stackitem.NewBuffer(pubs[2]), + stackitem.NewBuffer(pubs[3]), + stackitem.NewBuffer(pubs[4]), } - val, err := element.Value.TryBytes() - if err != nil { - return nil, err - } - res[string(key)] = string(val) + e.Invoke(t, stackitem.NewArray(arr), "key", owner) + }) + + e.Invoke(t, stackitem.Null{}, "removeKey", owner, + []interface{}{pubs[1], pubs[5]}) + arr = []stackitem.Item{ + stackitem.NewBuffer(pubs[0]), + stackitem.NewBuffer(pubs[2]), + stackitem.NewBuffer(pubs[3]), + stackitem.NewBuffer(pubs[4]), } + e.Invoke(t, stackitem.NewArray(arr), "key", owner) - return res, nil -} - -type Namespace struct { - Name string - State string -} - -type NamespaceExtended struct { - Name string - State string - SubjectsCount int64 - GroupsCount int64 -} - -func parseNamespace(t *testing.T, item stackitem.Item) Namespace { - var ns Namespace - - subjStruct := item.Value().([]stackitem.Item) - require.Len(t, subjStruct, 2) - - nameBytes, err := subjStruct[0].TryBytes() - require.NoError(t, err) - ns.Name = string(nameBytes) - - stateBytes, err := subjStruct[1].TryBytes() - require.NoError(t, err) - ns.State = string(stateBytes) - - return ns -} - -func parseNamespaceExtended(t *testing.T, item stackitem.Item) NamespaceExtended { - var ns NamespaceExtended - - subjStruct := item.Value().([]stackitem.Item) - require.Len(t, subjStruct, 4) - - nameBytes, err := subjStruct[0].TryBytes() - require.NoError(t, err) - ns.Name = string(nameBytes) - - groupCountInt, err := subjStruct[1].TryInteger() - require.NoError(t, err) - ns.GroupsCount = groupCountInt.Int64() - - subjectsCountInt, err := subjStruct[2].TryInteger() - require.NoError(t, err) - ns.SubjectsCount = subjectsCountInt.Int64() - - stateBytes, err := subjStruct[3].TryBytes() - require.NoError(t, err) - ns.State = string(stateBytes) - - return ns -} - -func parseNamespaces(t *testing.T, items []stackitem.Item) []Namespace { - res := make([]Namespace, len(items)) - - for i := 0; i < len(items); i++ { - res[i] = parseNamespace(t, items[i]) - } - - return res -} - -type Group struct { - ID int64 - Name string - Namespace string - KV map[string]string -} - -type GroupExtended struct { - ID int64 - Name string - Namespace string - KV map[string]string - SubjectsCount int64 -} - -func parseGroup(t *testing.T, item stackitem.Item) Group { - var group Group - - subjStruct := item.Value().([]stackitem.Item) - require.Len(t, subjStruct, 4) - - groupID, err := subjStruct[0].TryInteger() - require.NoError(t, err) - group.ID = groupID.Int64() - - nameBytes, err := subjStruct[1].TryBytes() - require.NoError(t, err) - group.Name = string(nameBytes) - - namespaceBytes, err := subjStruct[2].TryBytes() - require.NoError(t, err) - group.Namespace = string(namespaceBytes) - - group.KV, err = parseMap(subjStruct[3]) - require.NoError(t, err) - - return group -} - -func parseGroupExtended(t *testing.T, item stackitem.Item) GroupExtended { - var gr GroupExtended - - subjStruct := item.Value().([]stackitem.Item) - require.Len(t, subjStruct, 5) - - groupID, err := subjStruct[0].TryInteger() - require.NoError(t, err) - gr.ID = groupID.Int64() - - nameBytes, err := subjStruct[1].TryBytes() - require.NoError(t, err) - gr.Name = string(nameBytes) - - namespaceBytes, err := subjStruct[2].TryBytes() - require.NoError(t, err) - gr.Namespace = string(namespaceBytes) - - gr.KV, err = parseMap(subjStruct[3]) - require.NoError(t, err) - - subjectsCountInt, err := subjStruct[4].TryInteger() - require.NoError(t, err) - gr.SubjectsCount = subjectsCountInt.Int64() - - return gr -} - -func parseGroups(t *testing.T, items []stackitem.Item) []Group { - res := make([]Group, len(items)) - - for i := 0; i < len(items); i++ { - res[i] = parseGroup(t, items[i]) - } - - return res -} - -func makeValidRes(item stackitem.Item) *result.Invoke { - return &result.Invoke{ - Stack: []stackitem.Item{item}, - State: vmstate.Halt.String(), - } + t.Run("multiple removeKey per block", func(t *testing.T) { + tx1 := e.PrepareInvoke(t, "removeKey", owner, []interface{}{pubs[2]}) + tx2 := e.PrepareInvoke(t, "removeKey", owner, []interface{}{pubs[0], pubs[4]}) + e.AddNewBlock(t, tx1, tx2) + e.CheckHalt(t, tx1.Hash(), stackitem.Null{}) + e.CheckHalt(t, tx2.Hash(), stackitem.Null{}) + + arr = []stackitem.Item{stackitem.NewBuffer(pubs[3])} + e.Invoke(t, stackitem.NewArray(arr), "key", owner) + }) } diff --git a/tests/netmap_test.go b/tests/netmap_test.go index a2f7ae4..4c08c0f 100644 --- a/tests/netmap_test.go +++ b/tests/netmap_test.go @@ -20,22 +20,23 @@ import ( const netmapPath = "../netmap" -func deployNetmapContract(t *testing.T, e *neotest.Executor, addrBalance, addrContainer util.Uint160, config ...any) util.Uint160 { +func deployNetmapContract(t *testing.T, e *neotest.Executor, addrBalance, addrContainer util.Uint160, config ...interface{}) util.Uint160 { _, pubs, ok := vm.ParseMultiSigContract(e.Committee.Script()) require.True(t, ok) - args := make([]any, 4) - args[0] = addrBalance - args[1] = addrContainer - args[2] = []any{pubs[0]} - args[3] = append([]any{}, config...) + args := make([]interface{}, 5) + args[0] = false + args[1] = addrBalance + args[2] = addrContainer + args[3] = []interface{}{pubs[0]} + args[4] = append([]interface{}{}, config...) c := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml")) e.DeployContract(t, c, args) return c.Hash } -func newNetmapInvoker(t *testing.T, config ...any) *neotest.ContractInvoker { +func newNetmapInvoker(t *testing.T, config ...interface{}) *neotest.ContractInvoker { e := newExecutor(t) ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) diff --git a/tests/nns_test.go b/tests/nns_test.go index 24f5761..1b738d9 100644 --- a/tests/nns_test.go +++ b/tests/nns_test.go @@ -4,19 +4,14 @@ import ( "fmt" "math/big" "path" + "strings" "testing" "time" "git.frostfs.info/TrueCloudLab/frostfs-contract/nns" "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/transaction" - "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/neotest" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/gas" - "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/stretchr/testify/require" ) @@ -24,7 +19,8 @@ const nnsPath = "../nns" const msPerYear = 365 * 24 * time.Hour / time.Millisecond -func deployNNS(t *testing.T, e *neotest.Executor, addRoot bool) *neotest.ContractInvoker { +func newNNSInvoker(t *testing.T, addRoot bool) *neotest.ContractInvoker { + e := newExecutor(t) ctr := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) e.DeployContract(t, ctr, nil) @@ -34,33 +30,11 @@ func deployNNS(t *testing.T, e *neotest.Executor, addRoot bool) *neotest.Contrac refresh, retry, expire, ttl := int64(101), int64(102), int64(msPerYear/1000*100), int64(104) c.Invoke(t, true, "register", "com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) } return c } -func newNNSInvoker(t *testing.T, addRoot bool) *neotest.ContractInvoker { - e := newExecutor(t) - return deployNNS(t, e, addRoot) -} - -func newNNSInvokerWithFrostfsID(t *testing.T, addRoot bool) (*neotest.ContractInvoker, *neotest.ContractInvoker) { - e := newExecutor(t) - c := deployNNS(t, e, addRoot) - - frostfdID := deployFrostFSIDContract(t, e, e.CommitteeHash) - c.Invoke(t, true, "register", - nns.FrostfsIDNNSName, c.CommitteeHash, - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c.Invoke(t, stackitem.Null{}, "addRecord", - nns.FrostfsIDNNSName, int64(nns.TXT), frostfdID.StringLE()) - - c.Invoke(t, stackitem.Null{}, "addRecord", - nns.FrostfsIDNNSName, int64(nns.TXT), address.Uint160ToString(frostfdID)) - return e.NewInvoker(c.Hash), e.CommitteeInvoker(frostfdID) -} - func TestNNSGeneric(t *testing.T) { c := newNNSInvoker(t, false) @@ -76,40 +50,21 @@ func TestNNSRegisterTLD(t *testing.T) { c.InvokeFail(t, "invalid domain name format", "register", "0com", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) - c.InvokeFail(t, "invalid fragment '0com'", "register", - "0com", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) + "email@nspcc.ru", refresh, retry, expire, ttl) acc := c.NewAccount(t) cAcc := c.WithSigners(acc) cAcc.InvokeFail(t, "not witnessed by committee", "register", "com", acc.ScriptHash(), - "email@frostfs.info", refresh, retry, expire, ttl) - - t.Run("size checks", func(t *testing.T) { - c.Invoke(t, true, "register", - "ns", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) - - c.InvokeFail(t, "invalid domain name format", "register", - "x", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) - c.InvokeFail(t, "domain name too short", "register", - "x", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) - c.InvokeFail(t, "domain name too long", "register", - getTooLongDomainName(255), c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) - }) + "email@nspcc.ru", refresh, retry, expire, ttl) c.Invoke(t, true, "register", "com", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) + "email@nspcc.ru", refresh, retry, expire, ttl) c.InvokeFail(t, "TLD already exists", "register", "com", c.CommitteeHash, - "email@frostfs.info", refresh, retry, expire, ttl) + "email@nspcc.ru", refresh, retry, expire, ttl) } func TestNNSRegister(t *testing.T) { @@ -120,70 +75,39 @@ func TestNNSRegister(t *testing.T) { c1 := c.WithSigners(c.Committee, accTop) c1.Invoke(t, true, "register", "com", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, true, "register", - "aa.bb.zz", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.InvokeFail(t, "TLD already exists", "register", - "zz", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, true, "register", - "xx.bb.zz", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) acc := c.NewAccount(t) c2 := c.WithSigners(c.Committee, acc) c2.InvokeFail(t, "not witnessed by admin", "register", "testdomain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) c3 := c.WithSigners(accTop, acc) t.Run("domain names with hyphen", func(t *testing.T) { c3.InvokeFail(t, "invalid domain name format", "register", "-testdomain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - c3.InvokeFail(t, "invalid fragment '-testdomain'", "register", - "-testdomain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - + "myemail@nspcc.ru", refresh, retry, expire, ttl) c3.InvokeFail(t, "invalid domain name format", "register", "testdomain-.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - c3.InvokeFail(t, "invalid fragment 'testdomain-'", "register", - "testdomain-.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - + "myemail@nspcc.ru", refresh, retry, expire, ttl) c3.Invoke(t, true, "register", "test-domain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) }) - expected := stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("testdomain.com")), - }) - tx := c3.Invoke(t, true, "register", + c3.Invoke(t, true, "register", "testdomain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - c.CheckTxNotificationEvent(t, tx, -1, state.NotificationEvent{ScriptHash: c.Hash, Name: "RegisterDomain", Item: expected}) + "myemail@nspcc.ru", refresh, retry, expire, ttl) b := c.TopBlock(t) - expected = stackitem.NewArray([]stackitem.Item{stackitem.NewBuffer( - []byte(fmt.Sprintf("testdomain.com myemail@frostfs.info %d %d %d %d %d", + expected := stackitem.NewArray([]stackitem.Item{stackitem.NewBuffer( + []byte(fmt.Sprintf("testdomain.com myemail@nspcc.ru %d %d %d %d %d", b.Timestamp, refresh, retry, expire, ttl)))}) c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.SOA)) cAcc := c.WithSigners(acc) - - expected = stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("testdomain.com")), - stackitem.NewBigInteger(big.NewInt(int64(nns.TXT))), - }) - tx = cAcc.Invoke(t, stackitem.Null{}, "addRecord", + cAcc.Invoke(t, stackitem.Null{}, "addRecord", "testdomain.com", int64(nns.TXT), "first TXT record") - c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "AddRecord", Item: expected}) - cAcc.InvokeFail(t, "record already exists", "addRecord", "testdomain.com", int64(nns.TXT), "first TXT record") cAcc.Invoke(t, stackitem.Null{}, "addRecord", @@ -191,243 +115,16 @@ func TestNNSRegister(t *testing.T) { expected = stackitem.NewArray([]stackitem.Item{ stackitem.NewByteArray([]byte("first TXT record")), - stackitem.NewByteArray([]byte("second TXT record")), - }) + stackitem.NewByteArray([]byte("second TXT record"))}) c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT)) - expected = stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("testdomain.com")), - stackitem.NewBigInteger(big.NewInt(int64(nns.TXT))), - }) - tx = cAcc.Invoke(t, stackitem.Null{}, "setRecord", + cAcc.Invoke(t, stackitem.Null{}, "setRecord", "testdomain.com", int64(nns.TXT), int64(0), "replaced first") - c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "AddRecord", Item: expected}) expected = stackitem.NewArray([]stackitem.Item{ stackitem.NewByteArray([]byte("replaced first")), - stackitem.NewByteArray([]byte("second TXT record")), - }) + stackitem.NewByteArray([]byte("second TXT record"))}) c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT)) - - tx = cAcc.Invoke(t, stackitem.Null{}, "deleteRecords", "testdomain.com", int64(nns.TXT)) - expected = stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("testdomain.com")), - stackitem.NewBigInteger(big.NewInt(int64(nns.TXT))), - }) - c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteRecords", Item: expected}) - - c.Invoke(t, stackitem.Null{}, "getRecords", "testdomain.com", int64(nns.TXT)) - - cAcc.Invoke(t, stackitem.Null{}, "addRecord", - "testdomain.com", int64(nns.TXT), "rec1") - - cAcc.Invoke(t, stackitem.Null{}, "addRecord", - "testdomain.com", int64(nns.TXT), "rec2") - - cAcc.Invoke(t, stackitem.Null{}, "addRecord", - "testdomain.com", int64(nns.TXT), "rec3") - - cAcc.Invoke(t, stackitem.Null{}, "addRecord", - "testdomain.com", int64(nns.TXT), "rec4") - - cAcc.Invoke(t, false, "deleteRecord", - "testdomain.com", int64(nns.TXT), "rec9999") - - cAcc.Invoke(t, true, "deleteRecord", - "testdomain.com", int64(nns.TXT), "rec1") - - expected = stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("rec2")), - stackitem.NewByteArray([]byte("rec3")), - stackitem.NewByteArray([]byte("rec4")), - }) - c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT)) - - cAcc.Invoke(t, true, "deleteRecord", - "testdomain.com", int64(nns.TXT), "rec4") - - cAcc.Invoke(t, true, "deleteRecord", - "testdomain.com", int64(nns.TXT), "rec2") - - expected = stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("rec3")), - }) - c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT)) - - cAcc.Invoke(t, true, "deleteRecord", - "testdomain.com", int64(nns.TXT), "rec3") - - c.Invoke(t, stackitem.Null{}, "getRecords", "testdomain.com", int64(nns.TXT)) - - tx = cAcc.Invoke(t, stackitem.Null{}, "deleteDomain", "testdomain.com") - expected = stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("testdomain.com")), - stackitem.NewBigInteger(big.NewInt(int64(nns.CNAME))), - }) - c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteRecords", Item: expected}) - - expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com"))}) - c.CheckTxNotificationEvent(t, tx, 4, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteDomain", Item: expected}) - - c.Invoke(t, stackitem.Null{}, "getRecords", "testdomain.com", int64(nns.SOA)) -} - -func TestDeleteRecords_SubdomainNoRegister(t *testing.T) { - c := newNNSInvoker(t, true) - - refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) - c.Invoke(t, true, "register", - "test.com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) - - checkRecords := func(t *testing.T, domain string, typ nns.RecordType, expected ...string) { - s, err := c.TestInvoke(t, "getRecords", domain, int64(typ)) - require.NoError(t, err) - - if len(expected) == 0 { - _, ok := s.Pop().Item().(stackitem.Null) - require.True(t, ok, "expected 0 records") - return - } - - arr, ok := s.Pop().Value().([]stackitem.Item) - require.True(t, ok, "expected an array '%s' %d", domain, typ) - - actual := make([]string, len(arr)) - for i := range actual { - b, err := arr[i].TryBytes() - require.NoError(t, err) - actual[i] = string(b) - } - - require.ElementsMatch(t, expected, actual) - } - - c.Invoke(t, stackitem.Null{}, "addRecord", "a.test.com", int64(nns.TXT), "recA1") - c.Invoke(t, stackitem.Null{}, "addRecord", "a.test.com", int64(nns.TXT), "recA2") - c.Invoke(t, stackitem.Null{}, "addRecord", "b.test.com", int64(nns.TXT), "recB") - c.Invoke(t, stackitem.Null{}, "addRecord", "test.com", int64(nns.TXT), "recTop") - - { // Delete subdomain records. - c.Invoke(t, stackitem.Null{}, "deleteRecords", "a.test.com", int64(nns.TXT)) - checkRecords(t, "test.com", nns.TXT, "recTop") - checkRecords(t, "a.test.com", nns.TXT) - checkRecords(t, "b.test.com", nns.TXT, "recB") - } - - { // Delete domain records. - c.Invoke(t, stackitem.Null{}, "deleteRecords", "test.com", int64(nns.TXT)) - checkRecords(t, "test.com", nns.TXT) - checkRecords(t, "a.test.com", nns.TXT) - checkRecords(t, "b.test.com", nns.TXT, "recB") - } -} - -func TestDeleteDomain(t *testing.T) { - c := newNNSInvoker(t, false) - - acc1 := c.NewAccount(t) - c1 := c.WithSigners(c.Committee, acc1) - - acc2 := c.NewAccount(t) - c2 := c.WithSigners(c.Committee, acc2) - c1.Invoke(t, true, "register", - "com", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, true, "register", - "testdomain.com", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, true, "register", - "domik.testdomain.com", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.InvokeFail(t, "domain not found", "deleteDomain", "ru") - c1.InvokeFail(t, "can't delete TLD domain that has subdomains", "deleteDomain", "com") - c1.Invoke(t, stackitem.Null{}, "deleteDomain", "testdomain.com") - - c1.Invoke(t, true, "register", - "aa.bb.zz", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.InvokeFail(t, "TLD already exists", "register", - "zz", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, stackitem.Null{}, "deleteDomain", "aa.bb.zz") - - c1.Invoke(t, true, "register", - "zz", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, true, "register", - "cn", acc1.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c2.InvokeFail(t, "not witnessed by admin", "deleteDomain", "cn") - - c1.Invoke(t, stackitem.Null{}, "deleteDomain", "cn") - - c2.Invoke(t, true, "register", - "cn", acc2.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, true, "register", - "gu.bububu.bubu.bu", c.CommitteeHash, - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, true, "register", - "buu.gu.bububu.bubu.bu", c.CommitteeHash, - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - c1.Invoke(t, true, "register", - "bubu.bu", c.CommitteeHash, - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) -} - -func TestGlobalDomain(t *testing.T) { - c := newNNSInvoker(t, false) - - accTop := c.NewAccount(t) - refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) - c1 := c.WithSigners(c.Committee, accTop) - c1.Invoke(t, true, "register", - "com", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, true, "register", - "testdomain.com", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, true, "register", - "globaldomain.com", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, true, "register", - "domik.testdomain.com", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - c1.Invoke(t, stackitem.Null{}, "addRecord", - "domik.testdomain.com", int64(nns.TXT), "CID") - - c.Invoke(t, true, "isAvailable", "domik.globaldomain.com") - - c1.Invoke(t, stackitem.Null{}, "addRecord", - "testdomain.com", int64(nns.TXT), nns.Cnametgt+"=globaldomain.com") - c.Invoke(t, true, "isAvailable", "dom.testdomain.com") - - c1.Invoke(t, stackitem.Null{}, "addRecord", - "domik.testdomain.com", int64(nns.TXT), "random txt record") - c.Invoke(t, true, "isAvailable", "domik.globaldomain.com") - - c1.Invoke(t, true, "register", - "dom.testdomain.com", accTop.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, stackitem.Null{}, "addRecord", - "dom.testdomain.com", int64(nns.TXT), "CID") - - c.InvokeFail(t, "global domain is already taken", "isAvailable", "dom.testdomain.com") } func TestTLDRecord(t *testing.T) { @@ -437,17 +134,13 @@ func TestTLDRecord(t *testing.T) { result := []stackitem.Item{stackitem.NewByteArray([]byte("1.2.3.4"))} c.Invoke(t, result, "resolve", "com", int64(nns.A)) - - t.Run("subdomain", func(t *testing.T) { - c.Invoke(t, stackitem.Null{}, "addRecord", "a.com", int64(nns.TXT), "test=frostfs") - }) } func TestNNSRegisterMulti(t *testing.T) { c := newNNSInvoker(t, true) - newArgs := func(domain string, account neotest.Signer) []any { - return []any{ + newArgs := func(domain string, account neotest.Signer) []interface{} { + return []interface{}{ domain, account.ScriptHash(), "doesnt@matter.com", int64(101), int64(102), int64(103), int64(104), } @@ -458,6 +151,11 @@ func TestNNSRegisterMulti(t *testing.T) { cBoth.Invoke(t, true, "register", args...) c1 := c.WithSigners(acc) + t.Run("parent domain is missing", func(t *testing.T) { + msg := "one of the parent domains is not registered" + args[0] = "testnet.fs.neo.com" + c1.InvokeFail(t, msg, "register", args...) + }) args[0] = "fs.neo.com" c1.Invoke(t, true, "register", args...) @@ -487,8 +185,7 @@ func TestNNSRegisterMulti(t *testing.T) { c2.Invoke(t, stackitem.Null{}, "addRecord", "cdn.mainnet.fs.neo.com", int64(nns.A), "166.15.14.13") result := stackitem.NewArray([]stackitem.Item{ - stackitem.NewByteArray([]byte("166.15.14.13")), - }) + stackitem.NewByteArray([]byte("166.15.14.13"))}) c2.Invoke(t, result, "resolve", "cdn.mainnet.fs.neo.com", int64(nns.A)) } @@ -498,18 +195,18 @@ func TestNNSUpdateSOA(t *testing.T) { refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c.Invoke(t, true, "register", "testdomain.com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) refresh *= 2 retry *= 2 expire *= 2 ttl *= 2 c.Invoke(t, stackitem.Null{}, "updateSOA", - "testdomain.com", "newemail@frostfs.info", refresh, retry, expire, ttl) + "testdomain.com", "newemail@nspcc.ru", refresh, retry, expire, ttl) b := c.TopBlock(t) expected := stackitem.NewArray([]stackitem.Item{stackitem.NewBuffer( - []byte(fmt.Sprintf("testdomain.com newemail@frostfs.info %d %d %d %d %d", + []byte(fmt.Sprintf("testdomain.com newemail@nspcc.ru %d %d %d %d %d", b.Timestamp, refresh, retry, expire, ttl)))}) c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.SOA)) } @@ -520,13 +217,13 @@ func TestNNSGetAllRecords(t *testing.T) { refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c.Invoke(t, true, "register", "testdomain.com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) c.Invoke(t, stackitem.Null{}, "addRecord", "testdomain.com", int64(nns.TXT), "first TXT record") c.Invoke(t, stackitem.Null{}, "addRecord", "testdomain.com", int64(nns.A), "1.2.3.4") b := c.TopBlock(t) - expSOA := fmt.Sprintf("testdomain.com myemail@frostfs.info %d %d %d %d %d", + expSOA := fmt.Sprintf("testdomain.com myemail@nspcc.ru %d %d %d %d %d", b.Timestamp, refresh, retry, expire, ttl) s, err := c.TestInvoke(t, "getAllRecords", "testdomain.com") @@ -554,13 +251,51 @@ func TestNNSGetAllRecords(t *testing.T) { require.False(t, iter.Next()) } +func TestExpiration(t *testing.T) { + c := newNNSInvoker(t, true) + + refresh, retry, expire, ttl := int64(101), int64(102), int64(msPerYear/1000*10), int64(104) + c.Invoke(t, true, "register", + "testdomain.com", c.CommitteeHash, + "myemail@nspcc.ru", refresh, retry, expire, ttl) + + checkProperties := func(t *testing.T, expiration uint64) { + expected := stackitem.NewMapWithValue([]stackitem.MapElement{ + {Key: stackitem.Make("name"), Value: stackitem.Make("testdomain.com")}, + {Key: stackitem.Make("expiration"), Value: stackitem.Make(expiration)}}) + s, err := c.TestInvoke(t, "properties", "testdomain.com") + require.NoError(t, err) + require.Equal(t, expected.Value(), s.Top().Item().Value()) + } + + top := c.TopBlock(t) + expiration := top.Timestamp + uint64(expire*1000) + checkProperties(t, expiration) + + b := c.NewUnsignedBlock(t) + b.Timestamp = expiration - 2 // test invoke is done with +1 timestamp + require.NoError(t, c.Chain.AddBlock(c.SignBlock(b))) + checkProperties(t, expiration) + + b = c.NewUnsignedBlock(t) + b.Timestamp = expiration - 1 + require.NoError(t, c.Chain.AddBlock(c.SignBlock(b))) + + _, err := c.TestInvoke(t, "properties", "testdomain.com") + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "name has expired")) + + c.InvokeFail(t, "name has expired", "getAllRecords", "testdomain.com") + c.InvokeFail(t, "name has expired", "ownerOf", "testdomain.com") +} + func TestNNSSetAdmin(t *testing.T) { c := newNNSInvoker(t, true) refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c.Invoke(t, true, "register", "testdomain.com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) acc := c.NewAccount(t) cAcc := c.WithSigners(acc) @@ -574,85 +309,50 @@ func TestNNSSetAdmin(t *testing.T) { "testdomain.com", int64(nns.TXT), "will be added") } -func TestNNS_Frostfsid(t *testing.T) { - nnsInv, f := newNNSInvokerWithFrostfsID(t, false) - - acc, err := wallet.NewAccount() - require.NoError(t, err) - nnsUserInv := nnsInv.NewInvoker(nnsInv.Hash, newSigner(t, nnsInv, acc)) - - nnsUserInv.InvokeFail(t, "not witnessed by committee", "register", - "ddd", acc.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - nnsUserInv.InvokeFail(t, "not witnessed by committee", "register", - "testdomain.kz", acc.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - f.Invoke(t, stackitem.Null{}, createSubjectMethod, "", acc.PrivateKey().PublicKey().Bytes()) - - nnsUserInv.InvokeFail(t, "not witnessed by committee", "register", - "testdomain.kz", acc.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - f.Invoke(t, stackitem.Null{}, setSubjectKVMethod, acc.ScriptHash(), nns.FrostfsIDNNSTLDPermissionKey, nns.FrostfsIDTLDRegistrationAllowed) - - nnsUserInv.Invoke(t, true, "register", - "testdomain.kz", acc.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - - f.Invoke(t, stackitem.Null{}, deleteSubjectKVMethod, acc.ScriptHash(), nns.FrostfsIDNNSTLDPermissionKey) - - nnsUserInv.InvokeFail(t, "not witnessed by committee", "register", - "testdomain.uz", acc.ScriptHash(), - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) -} - func TestNNSIsAvailable(t *testing.T) { c := newNNSInvoker(t, false) c.Invoke(t, true, "isAvailable", "com") + c.InvokeFail(t, "TLD not found", "isAvailable", "domain.com") refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c.Invoke(t, true, "register", "com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) c.Invoke(t, false, "isAvailable", "com") c.Invoke(t, true, "isAvailable", "domain.com") acc := c.NewAccount(t) c1 := c.WithSigners(c.Committee, acc) - c1.Invoke(t, true, "register", "domain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c1.Invoke(t, true, "register", - "globaldomain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) c.Invoke(t, false, "isAvailable", "domain.com") +} - c.Invoke(t, true, "isAvailable", "dom.domain.com") +func TestNNSRenew(t *testing.T) { + c := newNNSInvoker(t, true) + acc := c.NewAccount(t) + c1 := c.WithSigners(c.Committee, acc) + refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c1.Invoke(t, true, "register", - "dom.domain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - c.Invoke(t, false, "isAvailable", "dom.domain.com") - c.Invoke(t, true, "isAvailable", "dom.dom.domain.com") + "testdomain.com", c.CommitteeHash, + "myemail@nspcc.ru", refresh, retry, expire, ttl) - c1.Invoke(t, stackitem.Null{}, "addRecord", - "dom.domain.com", int64(nns.TXT), nns.Cnametgt+"=globaldomain.com") - c.Invoke(t, true, "isAvailable", "dom.dom.domain.com") + const msPerYear = 365 * 24 * time.Hour / time.Millisecond + b := c.TopBlock(t) + ts := b.Timestamp + uint64(expire*1000) + uint64(msPerYear) - c1.Invoke(t, true, "register", - "dom.globaldomain.com", acc.ScriptHash(), - "myemail@frostfs.info", refresh, retry, expire, ttl) - - c.InvokeFail(t, "global domain is already taken", "isAvailable", "dom.dom.domain.com") - - c.InvokeFail(t, "domain name too long", "isAvailable", getTooLongDomainName(255)) + cAcc := c.WithSigners(acc) + cAcc.InvokeFail(t, "not witnessed by admin", "renew", "testdomain.com") + c1.Invoke(t, ts, "renew", "testdomain.com") + expected := stackitem.NewMapWithValue([]stackitem.MapElement{ + {Key: stackitem.Make("name"), Value: stackitem.Make("testdomain.com")}, + {Key: stackitem.Make("expiration"), Value: stackitem.Make(ts)}}) + cAcc.Invoke(t, expected, "properties", "testdomain.com") } func TestNNSResolve(t *testing.T) { @@ -661,7 +361,7 @@ func TestNNSResolve(t *testing.T) { refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c.Invoke(t, true, "register", "test.com", c.CommitteeHash, - "myemail@frostfs.info", refresh, retry, expire, ttl) + "myemail@nspcc.ru", refresh, retry, expire, ttl) c.Invoke(t, stackitem.Null{}, "addRecord", "test.com", int64(nns.TXT), "expected result") @@ -671,42 +371,3 @@ func TestNNSResolve(t *testing.T) { c.Invoke(t, records, "resolve", "test.com.", int64(nns.TXT)) c.InvokeFail(t, "invalid domain name format", "resolve", "test.com..", int64(nns.TXT)) } - -func TestNNSAndProxy(t *testing.T) { - c := newNNSInvoker(t, false) - proxyHash := deployProxyContract(t, c.Executor) - proxySigner := neotest.NewContractSigner(proxyHash, func(*transaction.Transaction) []any { return nil }) - - g := c.NewInvoker(gas.Hash, c.Validator) - g.Invoke(t, true, "transfer", - c.Validator.ScriptHash(), proxyHash, 100_0000_0000, nil) - - cc := c.WithSigners(proxySigner, c.Committee) - cc.Invoke(t, true, "register", "ns", proxyHash, - "ops@frostfs.info", 100, 100, 100, 100) - - checkBalance := func(t *testing.T, owner util.Uint160, balance int64) { - s, err := cc.TestInvoke(t, "balanceOf", owner) - require.NoError(t, err) - require.Equal(t, 1, s.Len()) - require.Equal(t, int64(balance), s.Pop().BigInt().Int64()) - } - - checkBalance(t, proxyHash, 1) - checkBalance(t, c.CommitteeHash, 0) - - t.Run("ensure domain is not lost", func(t *testing.T) { - cc.Invoke(t, true, "transfer", c.CommitteeHash, "ns", nil) - - checkBalance(t, proxyHash, 0) - checkBalance(t, c.CommitteeHash, 1) - }) -} - -func getTooLongDomainName(max int) (res string) { - for len(res) < max { - res += "dom." - } - res += "com" - return res -} diff --git a/tests/policy_test.go b/tests/policy_test.go deleted file mode 100644 index 361d435..0000000 --- a/tests/policy_test.go +++ /dev/null @@ -1,268 +0,0 @@ -package tests - -import ( - "bytes" - "path" - "testing" - - "git.frostfs.info/TrueCloudLab/frostfs-contract/nns" - "git.frostfs.info/TrueCloudLab/frostfs-contract/policy" - "github.com/nspcc-dev/neo-go/pkg/core/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/encoding/address" - "github.com/nspcc-dev/neo-go/pkg/neotest" - "github.com/nspcc-dev/neo-go/pkg/vm" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/stretchr/testify/require" -) - -const policyPath = "../policy" - -type policyContracts struct { - policy *neotest.ContractInvoker - frostfsid *neotest.ContractInvoker -} - -func newPolicyInvokers(t *testing.T) *policyContracts { - e := newExecutor(t) - - n := deployNNSContract(t, e) - ffid := deployFrostfsid(t, e) - polic := deployPolicyContract(t, e) - - n.Invoke(t, true, "register", - nns.FrostfsIDNNSName, n.CommitteeHash, - "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) - n.Invoke(t, stackitem.Null{}, "addRecord", - nns.FrostfsIDNNSName, int64(nns.TXT), ffid.Hash.StringLE()) - n.Invoke(t, stackitem.Null{}, "addRecord", - nns.FrostfsIDNNSName, int64(nns.TXT), address.Uint160ToString(ffid.Hash)) - - return &policyContracts{ - policy: polic, - frostfsid: ffid, - } -} - -func deployNNSContract(t *testing.T, e *neotest.Executor) *neotest.ContractInvoker { - ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) - e.DeployContract(t, ctrNNS, nil) - - n := e.CommitteeInvoker(ctrNNS.Hash) - - return n -} - -func deployFrostfsid(t *testing.T, e *neotest.Executor) *neotest.ContractInvoker { - acc, err := wallet.NewAccount() - require.NoError(t, err) - args := make([]any, 5) - args[0] = acc.ScriptHash() - frostfsID := neotest.CompileFile(t, e.CommitteeHash, frostfsidPath, path.Join(frostfsidPath, "config.yml")) - e.DeployContract(t, frostfsID, args) - return e.CommitteeInvoker(frostfsID.Hash) -} - -func deployPolicyContract(t *testing.T, e *neotest.Executor) *neotest.ContractInvoker { - cfgPath := path.Join(policyPath, "config.yml") - c := neotest.CompileFile(t, e.CommitteeHash, policyPath, cfgPath) - e.DeployContract(t, c, []any{nil}) - return e.CommitteeInvoker(c.Hash) -} - -func TestPolicy(t *testing.T) { - c := newPolicyInvokers(t) - - checkChainsIteratorByPrefix(t, c.policy, policy.Namespace, "mynamespace", "ingress", [][]byte{}) - checkChainsIteratorByPrefix(t, c.policy, policy.Container, "cnr1", "ingress", [][]byte{}) - - // Policies are opaque to the contract and are just raw bytes to store. - p1 := []byte("chain1") - p2 := []byte("chain2") - p3 := []byte("chain3") - p33 := []byte("chain33") - - c.frostfsid.Invoke(t, stackitem.Null{}, "createNamespace", "mynamespace") - - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Namespace, "mynamespace", "ingress:123", p1) - checkTargets(t, c.policy, policy.Namespace, [][]byte{[]byte("mynamespace")}) - checkChains(t, c.policy, "mynamespace", "", "ingress", [][]byte{p1}) - checkChains(t, c.policy, "mynamespace", "", "all", nil) - - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Container, "cnr1", "ingress:myrule2", p2) - checkTargets(t, c.policy, policy.Namespace, [][]byte{[]byte("mynamespace")}) - checkTargets(t, c.policy, policy.Container, [][]byte{[]byte("cnr1")}) - checkChains(t, c.policy, "mynamespace", "", "ingress", [][]byte{p1}) // Only namespace chains. - checkChains(t, c.policy, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2}) - checkChains(t, c.policy, "mynamespace", "cnr1", "all", nil) // No chains attached to 'all'. - checkChains(t, c.policy, "mynamespace", "cnr2", "ingress", [][]byte{p1}) // Only namespace, no chains for the container. - - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Container, "cnr1", "ingress:myrule3", p3) - checkTargets(t, c.policy, policy.Namespace, [][]byte{[]byte("mynamespace")}) - checkTargets(t, c.policy, policy.Container, [][]byte{[]byte("cnr1")}) - checkChains(t, c.policy, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2, p3}) - - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Container, "cnr1", "ingress:myrule3", p33) - checkTargets(t, c.policy, policy.Namespace, [][]byte{[]byte("mynamespace")}) - checkTargets(t, c.policy, policy.Container, [][]byte{[]byte("cnr1")}) - checkChain(t, c.policy, policy.Container, "cnr1", "ingress:myrule3", p33) - checkChains(t, c.policy, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2, p33}) // Override chain. - checkChainsByPrefix(t, c.policy, policy.Container, "cnr1", "", [][]byte{p2, p33}) - checkChainsByPrefix(t, c.policy, policy.IAM, "", "", nil) - checkChainKeys(t, c.policy, policy.Container, "cnr1", []string{"ingress:myrule2", "ingress:myrule3"}) - - checkChainsIteratorByPrefix(t, c.policy, policy.Container, "cnr1", "ingress:myrule3", [][]byte{p33}) - checkChainsIteratorByPrefix(t, c.policy, policy.Container, "cnr1", "ingress", [][]byte{p2, p33}) - - t.Run("removal", func(t *testing.T) { - t.Run("wrong name", func(t *testing.T) { - c.policy.Invoke(t, stackitem.Null{}, "removeChain", policy.Namespace, "mynamespace", "ingress") - checkChains(t, c.policy, "mynamespace", "", "ingress", [][]byte{p1}) - }) - - c.policy.Invoke(t, stackitem.Null{}, "removeChain", policy.Namespace, "mynamespace", "ingress:123") - checkChains(t, c.policy, "mynamespace", "", "ingress", nil) - checkChains(t, c.policy, "mynamespace", "cnr1", "ingress", [][]byte{p2, p33}) // Container chains still exist. - - // Remove by prefix. - c.policy.Invoke(t, stackitem.Null{}, "removeChainsByPrefix", policy.Container, "cnr1", "ingress") - checkChains(t, c.policy, "mynamespace", "cnr1", "ingress", nil) - - // Remove by prefix. - c.policy.Invoke(t, stackitem.Null{}, "removeChainsByPrefix", policy.Container, "cnr1", "ingress") - checkChains(t, c.policy, "mynamespace", "cnr1", "ingress", nil) - - checkTargets(t, c.policy, policy.Namespace, [][]byte{}) - checkTargets(t, c.policy, policy.Container, [][]byte{}) - }) - - t.Run("add again after removal", func(t *testing.T) { - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Namespace, "mynamespace", "ingress:123", p1) - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Container, "cnr1", "ingress:myrule3", p33) - - checkTargets(t, c.policy, policy.Namespace, [][]byte{[]byte("mynamespace")}) - checkTargets(t, c.policy, policy.Container, [][]byte{[]byte("cnr1")}) - }) - - t.Run("add chain for non-active namespace", func(t *testing.T) { - c.frostfsid.Invoke(t, stackitem.Null{}, "createNamespace", "nsdisabled") - - c.frostfsid.Invoke(t, stackitem.Null{}, "updateNamespace", "nsdisabled", "frozen") - c.policy.InvokeFail(t, "namespace is non-active", "addChain", policy.Namespace, "nsdisabled", "ingress:3", p1) - - c.frostfsid.Invoke(t, stackitem.Null{}, "updateNamespace", "nsdisabled", "purge") - c.policy.InvokeFail(t, "namespace is non-active", "addChain", policy.Namespace, "nsdisabled", "ingress:3", p1) - - c.frostfsid.Invoke(t, stackitem.Null{}, "updateNamespace", "nsdisabled", "active") - c.policy.Invoke(t, stackitem.Null{}, "addChain", policy.Namespace, "nsdisabled", "ingress:3", p1) - }) -} - -func TestAutorization(t *testing.T) { - c := newPolicyInvokers(t) - - c.policy.Invoke(t, stackitem.Null{}, "getAdmin") - - s := c.policy.NewAccount(t, 1_0000_0000) - cs := c.policy.WithSigners(s) - - args := []any{policy.Container, "cnr1", "ingress:myrule3", []byte("opaque")} - cs.InvokeFail(t, policy.ErrNotAuthorized, "addChain", args...) - - c.policy.Invoke(t, stackitem.Null{}, "setAdmin", s.ScriptHash()) - c.policy.Invoke(t, stackitem.NewBuffer(s.ScriptHash().BytesBE()), "getAdmin") - - cs.Invoke(t, stackitem.Null{}, "addChain", args...) -} - -func checkChains(t *testing.T, e *neotest.ContractInvoker, namespace, container, name string, expected [][]byte) { - s, err := e.TestInvoke(t, "listChains", namespace, container, name) - require.NoError(t, err) - - checksChainsOnStack(t, s, expected) -} - -func checkChainsByPrefix(t *testing.T, e *neotest.ContractInvoker, kind byte, entityName, prefix string, expected [][]byte) { - s, err := e.TestInvoke(t, "listChainsByPrefix", kind, entityName, prefix) - require.NoError(t, err) - - checksChainsOnStack(t, s, expected) -} - -func checkChainsIteratorByPrefix(t *testing.T, e *neotest.ContractInvoker, kind byte, entityName, prefix string, expected [][]byte) { - s, err := e.TestInvoke(t, "iteratorChainsByPrefix", kind, entityName, prefix) - require.NoError(t, err) - - if s.Len() == 0 { - t.Fatal("Stack is empty") - } - - iteratorItem := s.Pop().Value().(*storage.Iterator) - policys := iteratorToArray(iteratorItem) - require.Equal(t, len(expected), len(policys)) - - for i := range expected { - bytesPolicy, err := policys[i].TryBytes() - require.NoError(t, err) - require.Equal(t, expected[i], bytesPolicy) - } -} - -func checkChainKeys(t *testing.T, e *neotest.ContractInvoker, kind byte, entityName string, expected []string) { - s, err := e.TestInvoke(t, "listChainNames", kind, entityName) - require.NoError(t, err) - - if s.Len() == 0 { - t.Fatal("Stack is empty") - } - - iteratorItem := s.Pop().Value().(*storage.Iterator) - policys := iteratorToArray(iteratorItem) - require.Equal(t, len(expected), len(policys)) - - for i := range expected { - bytesPolicy, err := policys[i].TryBytes() - require.NoError(t, err) - require.Equal(t, expected[i], string(bytesPolicy)) - } -} - -func checksChainsOnStack(t *testing.T, s *vm.Stack, expected [][]byte) { - require.Equal(t, 1, s.Len()) - - var actual [][]byte - arr := s.Pop().Array() - for i := range arr { - bs, err := arr[i].TryBytes() - - require.NoError(t, err) - actual = append(actual, bs) - } - - require.ElementsMatch(t, expected, actual) -} - -func checkChain(t *testing.T, e *neotest.ContractInvoker, kind byte, entityName, name string, expected []byte) { - s, err := e.TestInvoke(t, "getChain", kind, entityName, name) - require.NoError(t, err) - require.Equal(t, 1, s.Len()) - - require.True(t, bytes.Equal(expected, s.Pop().Bytes())) -} - -func checkTargets(t *testing.T, e *neotest.ContractInvoker, kind byte, expected [][]byte) { - s, err := e.TestInvoke(t, "listTargets", kind) - require.NoError(t, err) - - require.NotEqual(t, 0, s.Len(), "stack is empty") - - iteratorItem := s.Pop().Value().(*storage.Iterator) - targets := iteratorToArray(iteratorItem) - require.Equal(t, len(expected), len(targets)) - - for i := range expected { - bytesTargets, err := targets[i].TryBytes() - require.NoError(t, err) - require.Equal(t, expected[i], bytesTargets) - } -} diff --git a/tests/processing_test.go b/tests/processing_test.go index 6c16bb7..ac6c4e9 100644 --- a/tests/processing_test.go +++ b/tests/processing_test.go @@ -4,41 +4,28 @@ import ( "path" "testing" - "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/neotest" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/stretchr/testify/require" ) const processingPath = "../processing" -func deployProcessingContract(t *testing.T, e *neotest.Executor) util.Uint160 { +func deployProcessingContract(t *testing.T, e *neotest.Executor, addrFrostFS util.Uint160) util.Uint160 { c := neotest.CompileFile(t, e.CommitteeHash, processingPath, path.Join(processingPath, "config.yml")) - e.DeployContract(t, c, nil) + args := make([]interface{}, 1) + args[0] = addrFrostFS + + e.DeployContract(t, c, args) return c.Hash } -func newProcessingInvoker(t *testing.T) (*neotest.ContractInvoker, neotest.SingleSigner) { - e := newExecutor(t) +func newProcessingInvoker(t *testing.T) (*neotest.ContractInvoker, neotest.Signer) { + frostfsInvoker, irMultiAcc, _ := newFrostFSInvoker(t, 2) + hash := deployProcessingContract(t, frostfsInvoker.Executor, frostfsInvoker.Hash) - acc, err := wallet.NewAccount() - require.NoError(t, err) - - sig := neotest.NewSingleSigner(acc) - - gasHash, err := e.Chain.GetNativeContractScriptHash(nativenames.Gas) - require.NoError(t, err) - vc := e.CommitteeInvoker(gasHash).WithSigners(e.Validator) - vc.Invoke(t, true, "transfer", - e.Validator.ScriptHash(), sig.ScriptHash(), - int64(10_0000_0000), nil) - - hash := deployProcessingContract(t, e) - - return e.CommitteeInvoker(hash), sig + return frostfsInvoker.CommitteeInvoker(hash), irMultiAcc } func TestVerify_Processing(t *testing.T) { @@ -48,6 +35,6 @@ func TestVerify_Processing(t *testing.T) { cIR := c.WithSigners(irMultiAcc) - cIR.Invoke(t, stackitem.NewBool(false), method) - c.Invoke(t, stackitem.NewBool(true), method) + cIR.Invoke(t, stackitem.NewBool(true), method) + c.Invoke(t, stackitem.NewBool(false), method) } diff --git a/tests/proxy_test.go b/tests/proxy_test.go index f36754d..67b363c 100644 --- a/tests/proxy_test.go +++ b/tests/proxy_test.go @@ -4,52 +4,45 @@ import ( "path" "testing" - "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" - "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/neotest" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/stretchr/testify/require" ) const proxyPath = "../proxy" -func deployProxyContract(t *testing.T, e *neotest.Executor) util.Uint160 { +func deployProxyContract(t *testing.T, e *neotest.Executor, addrNetmap util.Uint160) util.Uint160 { + args := make([]interface{}, 1) + args[0] = addrNetmap + c := neotest.CompileFile(t, e.CommitteeHash, proxyPath, path.Join(proxyPath, "config.yml")) - e.DeployContract(t, c, []any{}) + e.DeployContract(t, c, args) return c.Hash } func newProxyInvoker(t *testing.T) *neotest.ContractInvoker { e := newExecutor(t) - proxyHash := deployProxyContract(t, e) + ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml")) + ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml")) + ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml")) + ctrProxy := neotest.CompileFile(t, e.CommitteeHash, proxyPath, path.Join(proxyPath, "config.yml")) - return e.CommitteeInvoker(proxyHash) + deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash) + deployProxyContract(t, e, ctrNetmap.Hash) + + return e.CommitteeInvoker(ctrProxy.Hash) } func TestVerify(t *testing.T) { e := newProxyInvoker(t) - acc := e.NewAccount(t) - gas := e.NewInvoker(e.NativeHash(t, nativenames.Gas), e.Validator) - gas.Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.Hash, 100_0000_0000, nil) + const method = "verify" - s := neotest.NewContractSigner(e.Hash, func(*transaction.Transaction) []any { return nil }) - t.Run("proxy + committee", func(t *testing.T) { - tx := e.PrepareInvocation(t, []byte{byte(opcode.RET)}, []neotest.Signer{s, e.Committee}) - require.NoError(t, e.Chain.VerifyTx(tx)) - }) - t.Run("proxy + custom account", func(t *testing.T) { - t.Run("bad, only proxy", func(t *testing.T) { - tx := e.PrepareInvocation(t, []byte{byte(opcode.RET)}, []neotest.Signer{s, acc}) - require.Error(t, e.Chain.VerifyTx(tx)) - }) + e.Invoke(t, stackitem.NewBool(true), method) - e.Invoke(t, stackitem.Null{}, "addAccount", acc.ScriptHash()) + notAlphabet := e.NewAccount(t) + cNotAlphabet := e.WithSigners(notAlphabet) - tx := e.PrepareInvocation(t, []byte{byte(opcode.RET)}, []neotest.Signer{s, acc}) - require.NoError(t, e.Chain.VerifyTx(tx)) - }) + cNotAlphabet.Invoke(t, stackitem.NewBool(false), method) } diff --git a/tests/reputation_test.go b/tests/reputation_test.go new file mode 100644 index 0000000..8b09a25 --- /dev/null +++ b/tests/reputation_test.go @@ -0,0 +1,80 @@ +package tests + +import ( + "path" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/neotest" + "github.com/nspcc-dev/neo-go/pkg/neotest/chain" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" +) + +const reputationPath = "../reputation" + +func deployReputationContract(t *testing.T, e *neotest.Executor) util.Uint160 { + c := neotest.CompileFile(t, e.CommitteeHash, reputationPath, + path.Join(reputationPath, "config.yml")) + + args := make([]interface{}, 1) + args[0] = false + + e.DeployContract(t, c, args) + return c.Hash +} + +func newReputationInvoker(t *testing.T) *neotest.ContractInvoker { + bc, acc := chain.NewSingle(t) + e := neotest.NewExecutor(t, bc, acc, acc) + h := deployReputationContract(t, e) + return e.CommitteeInvoker(h) +} + +func TestReputation_Put(t *testing.T) { + e := newReputationInvoker(t) + + peerID := []byte{1, 2, 3} + e.Invoke(t, stackitem.Null{}, "put", int64(1), peerID, []byte{4}) + + t.Run("concurrent invocations", func(t *testing.T) { + repValue1 := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + repValue2 := []byte{10, 20, 30, 40, 50, 60, 70, 80} + tx1 := e.PrepareInvoke(t, "put", int64(1), peerID, repValue1) + tx2 := e.PrepareInvoke(t, "put", int64(1), peerID, repValue2) + + e.AddNewBlock(t, tx1, tx2) + e.CheckHalt(t, tx1.Hash(), stackitem.Null{}) + e.CheckHalt(t, tx2.Hash(), stackitem.Null{}) + + t.Run("get all", func(t *testing.T) { + result := stackitem.NewArray([]stackitem.Item{ + stackitem.NewBuffer([]byte{4}), + stackitem.NewBuffer(repValue1), + stackitem.NewBuffer(repValue2), + }) + e.Invoke(t, result, "get", int64(1), peerID) + }) + }) +} + +func TestReputation_ListByEpoch(t *testing.T) { + e := newReputationInvoker(t) + + peerIDs := []string{"peer1", "peer2"} + e.Invoke(t, stackitem.Null{}, "put", int64(1), peerIDs[0], []byte{1}) + e.Invoke(t, stackitem.Null{}, "put", int64(1), peerIDs[0], []byte{2}) + e.Invoke(t, stackitem.Null{}, "put", int64(2), peerIDs[1], []byte{3}) + e.Invoke(t, stackitem.Null{}, "put", int64(2), peerIDs[0], []byte{4}) + e.Invoke(t, stackitem.Null{}, "put", int64(2), peerIDs[1], []byte{5}) + + result := stackitem.NewArray([]stackitem.Item{ + stackitem.NewBuffer(append([]byte{1}, peerIDs[0]...)), + }) + e.Invoke(t, result, "listByEpoch", int64(1)) + + result = stackitem.NewArray([]stackitem.Item{ + stackitem.NewBuffer(append([]byte{2}, peerIDs[0]...)), + stackitem.NewBuffer(append([]byte{2}, peerIDs[1]...)), + }) + e.Invoke(t, result, "listByEpoch", int64(2)) +} diff --git a/tests/testdata/config.yml b/tests/testdata/config.yml deleted file mode 100644 index 6294558..0000000 --- a/tests/testdata/config.yml +++ /dev/null @@ -1,2 +0,0 @@ -name: "TestContract" -safemethods: ["encodeDecode"] diff --git a/tests/testdata/encode.go b/tests/testdata/encode.go deleted file mode 100644 index 02d9b4e..0000000 --- a/tests/testdata/encode.go +++ /dev/null @@ -1,17 +0,0 @@ -package testdata - -import ( - "git.frostfs.info/TrueCloudLab/frostfs-contract/common" -) - -// EncodeDecode encodes x in fixed-width little-endian representation -// and deserializes it back. -func EncodeDecode(x int) int { - y := common.ToFixedWidth64(x) - return common.FromFixedWidth64(y) -} - -// Encode encodes x in fixed-width little-endian representation. -func Encode(x int) []byte { - return common.ToFixedWidth64(x) -} diff --git a/tests/util.go b/tests/util.go index ed7c119..48f5f5d 100644 --- a/tests/util.go +++ b/tests/util.go @@ -1,76 +1,14 @@ package tests import ( - "context" - "net/http" - "os" "testing" - "time" - "github.com/nspcc-dev/neo-go/pkg/config" - "github.com/nspcc-dev/neo-go/pkg/consensus" - "github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/core/state" - corestate "github.com/nspcc-dev/neo-go/pkg/core/stateroot" - "github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig" "github.com/nspcc-dev/neo-go/pkg/neotest" "github.com/nspcc-dev/neo-go/pkg/neotest/chain" - "github.com/nspcc-dev/neo-go/pkg/network" - "github.com/nspcc-dev/neo-go/pkg/rpcclient" - "github.com/nspcc-dev/neo-go/pkg/services/rpcsrv" - "github.com/nspcc-dev/neo-go/pkg/services/stateroot" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" - "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/stretchr/testify/require" - "go.uber.org/zap" ) -type awaiter struct { - ctx context.Context - t *testing.T - rpc *rpcclient.Client -} - -func (a awaiter) await(tx util.Uint256, vub uint32, err error) *state.AppExecResult { - require.NoError(a.t, err) - return await(a.ctx, a.t, a.rpc, tx, vub) -} - -const nodeWallet = ` -{ - "version": "3.0", - "accounts": [ - { - "address": "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn", - "key": "6PYM8VdX2BSm7BSXKzV4Fz6S3R9cDLLWNrD9nMjxW352jEv3fsC8N3wNLY", - "label": "", - "contract": { - "script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBVuezJw==", - "parameters": [ - { - "name": "parameter0", - "type": "Signature" - } - ], - "deployed": false - }, - "lock": false, - "isdefault": false - } - ], - "scrypt": { - "n": 16384, - "r": 8, - "p": 8 - }, - "extra": { - "Tokens": null - } -} -` - func iteratorToArray(iter *storage.Iterator) []stackitem.Item { stackItems := make([]stackitem.Item, 0) for iter.Next() { @@ -83,146 +21,3 @@ func newExecutor(t *testing.T) *neotest.Executor { bc, acc := chain.NewSingle(t) return neotest.NewExecutor(t, bc, acc, acc) } - -func initTmpWallet(t *testing.T) string { - f, err := os.CreateTemp("", "tmp-neo-go-wallet") - require.NoError(t, err) - - _, err = f.WriteString(nodeWallet) - require.NoError(t, err) - - err = f.Close() - require.NoError(t, err) - return f.Name() -} - -func await(ctx context.Context, t *testing.T, rpc *rpcclient.Client, tx util.Uint256, vub uint32) *state.AppExecResult { - waitCtx, waitCancel := context.WithTimeout(ctx, 5*time.Second) - defer waitCancel() - - for { - select { - case <-waitCtx.Done(): - require.NoError(t, waitCtx.Err()) - return nil - default: - bc, err := rpc.GetBlockCount() - require.NoError(t, err) - - tr := trigger.Application - if log, err := rpc.GetApplicationLog(tx, &tr); err == nil { - return &state.AppExecResult{ - Container: log.Container, - Execution: log.Executions[0], - } - } - - require.LessOrEqual(t, bc, vub, "vub is expired") - time.Sleep(100 * time.Millisecond) - } - } -} - -func neogoCfg() config.Config { - return config.Config{ - ProtocolConfiguration: config.ProtocolConfiguration{}, - ApplicationConfiguration: config.ApplicationConfiguration{ - RPC: config.RPC{ - BasicService: config.BasicService{ - Enabled: true, - // See how tests are done in the neo-go itself: - // https://github.com/nspcc-dev/neo-go/blob/5fc61be5f6c5349d8de8b61967380feee6b51c55/config/protocol.unit_testnet.single.yml#L61 - Addresses: []string{"localhost:0"}, - }, - MaxGasInvoke: 200_000_000, - SessionEnabled: true, - MaxIteratorResultItems: 100, - SessionPoolSize: 20, - SessionExpirationTime: 15, - }, - DBConfiguration: dbconfig.DBConfiguration{ - Type: dbconfig.InMemoryDB, - }, - }, - } -} - -func consensusCfg(chain *core.Blockchain, walletAddress string, srv *network.Server) consensus.Config { - return consensus.Config{ - Logger: zap.NewExample(), - Broadcast: srv.BroadcastExtensible, - BlockQueue: srv.GetBlockQueue(), - Chain: chain, - ProtocolConfiguration: chain.GetConfig().ProtocolConfiguration, - RequestTx: srv.RequestTx, - StopTxFlow: srv.StopTxFlow, - Wallet: config.Wallet{ - Path: walletAddress, - Password: "one", - }, - TimePerBlock: 100 * time.Millisecond, - } -} - -func runRPC(ctx context.Context, t *testing.T, chain *core.Blockchain, walletPath string) string { - log := zap.NewExample() - cfg := neogoCfg() - - srvCfg, err := network.NewServerConfig(cfg) - require.NoError(t, err) - srv, err := network.NewServer(srvCfg, chain, chain.GetStateSyncModule(), log) - require.NoError(t, err) - - t.Cleanup(srv.Shutdown) - - errCh := make(chan error) - go func() { - for err := range errCh { - require.NoError(t, err) - return - } - }() - - srMod := chain.GetStateModule().(*corestate.Module) - sr, err := stateroot.New(srvCfg.StateRootCfg, srMod, log, chain, srv.BroadcastExtensible) - require.NoError(t, err) - srv.AddExtensibleService(sr, stateroot.Category, sr.OnPayload) - - consens, err := consensus.NewService(consensusCfg(chain, walletPath, srv)) - require.NoError(t, err) - srv.AddConsensusService(consens, consens.OnPayload, consens.OnTransaction) - - rpcSrv := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, srv, nil, log, errCh) - srv.AddService(&rpcSrv) - - initialAddr := rpcSrv.Addresses()[0] - - go srv.Start() - - // wait until RPC server is started - startTimeout, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - ticker := time.NewTicker(time.Millisecond * 100) - defer ticker.Stop() - - var actualAddr string - for { - select { - case <-startTimeout.Done(): - t.Fatalf("Waiting for server start: %v", startTimeout.Err()) - case <-ticker.C: - if actualAddr == "" { - newAddr := rpcSrv.Addresses()[0] - if initialAddr == newAddr { - continue - } - actualAddr = newAddr - t.Logf("RPC server is listening at %s, checking health", actualAddr) - } - if _, err = http.Get("http://" + actualAddr); err == nil { - return actualAddr - } - } - } -}