From 5f326bffae6aef6f888a8f8d02b6ed7af1e897aa Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 26 Sep 2023 22:24:08 +0300 Subject: [PATCH] subnet: drop this contract It's no longer deployed and used. Signed-off-by: Roman Khimov --- CHANGELOG.md | 1 + Makefile | 2 +- README.md | 1 - cmd/dump/main.go | 1 - debian/control | 1 - rpc/subnet/rpcbinding.go | 1931 ------------------------------------- subnet/config.yml | 15 - subnet/doc.go | 72 -- subnet/migration_test.go | 67 -- subnet/subnet_contract.go | 609 ------------ tests/subnet_test.go | 330 ------- 11 files changed, 2 insertions(+), 3028 deletions(-) delete mode 100644 rpc/subnet/rpcbinding.go delete mode 100644 subnet/config.yml delete mode 100644 subnet/doc.go delete mode 100644 subnet/migration_test.go delete mode 100644 subnet/subnet_contract.go delete mode 100644 tests/subnet_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b177802..4841333b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Changelog for NeoFS Contract ### Updated ### Removed +- Obsolete subnet contract (#364) ### Fixed diff --git a/Makefile b/Makefile index daedc324..d332efda 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ all: sidechain mainnet sidechain: alphabet morph nns alphabet_sc = alphabet -morph_sc = audit balance container neofsid netmap proxy reputation subnet +morph_sc = audit balance container neofsid netmap proxy reputation mainnet_sc = neofs processing nns_sc = nns diff --git a/README.md b/README.md index 0c44fc89..c5c788aa 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ Sidechain contracts: - nns - proxy - reputation -- subnet # Getting started diff --git a/cmd/dump/main.go b/cmd/dump/main.go index ab4aff51..26f9f7da 100644 --- a/cmd/dump/main.go +++ b/cmd/dump/main.go @@ -77,7 +77,6 @@ func overtakeContracts(from *remoteBlockchain, to *dump.Creator) error { "neofsid", "netmap", "reputation", - "subnet", } { log.Printf("Processing contract '%s'...\n", name) diff --git a/debian/control b/debian/control index 4efdc9e5..d84b1c03 100644 --- a/debian/control +++ b/debian/control @@ -31,4 +31,3 @@ Description: NeoFS-Contract contains all NeoFS related contracts. - nns - proxy - reputation - - subnet diff --git a/rpc/subnet/rpcbinding.go b/rpc/subnet/rpcbinding.go deleted file mode 100644 index 9832e7f7..00000000 --- a/rpc/subnet/rpcbinding.go +++ /dev/null @@ -1,1931 +0,0 @@ -// Package subnet contains RPC wrappers for NeoFS Subnet contract. -package subnet - -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/smartcontract" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "math/big" - "unicode/utf8" -) - -// CommonBallot is a contract-specific common.Ballot type used by its methods. -type CommonBallot struct { - ID []byte - Voters keys.PublicKeys - Height *big.Int -} - -// LedgerBlock is a contract-specific ledger.Block type used by its methods. -type LedgerBlock struct { - Hash util.Uint256 - Version *big.Int - PrevHash util.Uint256 - MerkleRoot util.Uint256 - Timestamp *big.Int - Nonce *big.Int - Index *big.Int - NextConsensus util.Uint160 - TransactionsLength *big.Int -} - -// LedgerBlockSR is a contract-specific ledger.BlockSR type used by its methods. -type LedgerBlockSR struct { - Hash util.Uint256 - Version *big.Int - PrevHash util.Uint256 - MerkleRoot util.Uint256 - Timestamp *big.Int - Nonce *big.Int - Index *big.Int - NextConsensus util.Uint160 - TransactionsLength *big.Int - PrevStateRoot util.Uint256 -} - -// LedgerTransaction is a contract-specific ledger.Transaction type used by its methods. -type LedgerTransaction struct { - Hash util.Uint256 - Version *big.Int - Nonce *big.Int - Sender util.Uint160 - SysFee *big.Int - NetFee *big.Int - ValidUntilBlock *big.Int - Script []byte -} - -// LedgerTransactionSigner is a contract-specific ledger.TransactionSigner type used by its methods. -type LedgerTransactionSigner struct { - Account util.Uint160 - Scopes *big.Int - AllowedContracts []util.Uint160 - AllowedGroups keys.PublicKeys - Rules []*LedgerWitnessRule -} - -// LedgerWitnessCondition is a contract-specific ledger.WitnessCondition type used by its methods. -type LedgerWitnessCondition struct { - Type *big.Int - Value any -} - -// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods. -type LedgerWitnessRule struct { - Action *big.Int - Condition *LedgerWitnessCondition -} - -// ManagementABI is a contract-specific management.ABI type used by its methods. -type ManagementABI struct { - Methods []*ManagementMethod - Events []*ManagementEvent -} - -// ManagementContract is a contract-specific management.Contract type used by its methods. -type ManagementContract struct { - ID *big.Int - UpdateCounter *big.Int - Hash util.Uint160 - NEF []byte - Manifest *ManagementManifest -} - -// ManagementEvent is a contract-specific management.Event type used by its methods. -type ManagementEvent struct { - Name string - Params []*ManagementParameter -} - -// ManagementGroup is a contract-specific management.Group type used by its methods. -type ManagementGroup struct { - PublicKey *keys.PublicKey - Signature []byte -} - -// ManagementManifest is a contract-specific management.Manifest type used by its methods. -type ManagementManifest struct { - Name string - Groups []*ManagementGroup - Features map[string]string - SupportedStandards []string - ABI *ManagementABI - Permissions []*ManagementPermission - Trusts []util.Uint160 - Extra any -} - -// ManagementMethod is a contract-specific management.Method type used by its methods. -type ManagementMethod struct { - Name string - Params []*ManagementParameter - ReturnType *big.Int - Offset *big.Int - Safe bool -} - -// ManagementParameter is a contract-specific management.Parameter type used by its methods. -type ManagementParameter struct { - Name string - Type *big.Int -} - -// ManagementPermission is a contract-specific management.Permission type used by its methods. -type ManagementPermission struct { - Contract util.Uint160 - Methods []string -} - -// DeleteEvent represents "Delete" event emitted by the contract. -type DeleteEvent struct { - Id []byte -} - -// RemoveNodeEvent represents "RemoveNode" event emitted by the contract. -type RemoveNodeEvent struct { - SubnetID []byte - Node *keys.PublicKey -} - -// 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} -} - -// Version invokes `version` method of contract. -func (c *ContractReader) Version() (*big.Int, error) { - return unwrap.BigInt(c.invoker.Call(c.hash, "version")) -} - -// AddClientAdmin creates a transaction invoking `addClientAdmin` 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) AddClientAdmin(subnetID []byte, groupID []byte, adminPublicKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addClientAdmin", subnetID, groupID, adminPublicKey) -} - -// AddClientAdminTransaction creates a transaction invoking `addClientAdmin` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddClientAdminTransaction(subnetID []byte, groupID []byte, adminPublicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addClientAdmin", subnetID, groupID, adminPublicKey) -} - -// AddClientAdminUnsigned creates a transaction invoking `addClientAdmin` 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) AddClientAdminUnsigned(subnetID []byte, groupID []byte, adminPublicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addClientAdmin", nil, subnetID, groupID, adminPublicKey) -} - -// AddNode creates a transaction invoking `addNode` 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) AddNode(subnetID []byte, node *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addNode", subnetID, node) -} - -// AddNodeTransaction creates a transaction invoking `addNode` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddNodeTransaction(subnetID []byte, node *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addNode", subnetID, node) -} - -// AddNodeUnsigned creates a transaction invoking `addNode` 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) AddNodeUnsigned(subnetID []byte, node *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addNode", nil, subnetID, node) -} - -// AddNodeAdmin creates a transaction invoking `addNodeAdmin` 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) AddNodeAdmin(subnetID []byte, adminKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addNodeAdmin", subnetID, adminKey) -} - -// AddNodeAdminTransaction creates a transaction invoking `addNodeAdmin` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddNodeAdminTransaction(subnetID []byte, adminKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addNodeAdmin", subnetID, adminKey) -} - -// AddNodeAdminUnsigned creates a transaction invoking `addNodeAdmin` 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) AddNodeAdminUnsigned(subnetID []byte, adminKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addNodeAdmin", nil, subnetID, adminKey) -} - -// AddUser creates a transaction invoking `addUser` 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) AddUser(subnetID []byte, groupID []byte, userID []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "addUser", subnetID, groupID, userID) -} - -// AddUserTransaction creates a transaction invoking `addUser` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) AddUserTransaction(subnetID []byte, groupID []byte, userID []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "addUser", subnetID, groupID, userID) -} - -// AddUserUnsigned creates a transaction invoking `addUser` 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) AddUserUnsigned(subnetID []byte, groupID []byte, userID []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "addUser", nil, subnetID, groupID, userID) -} - -// 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(id []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "delete", id) -} - -// 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(id []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "delete", id) -} - -// 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(id []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "delete", nil, id) -} - -// Get creates a transaction invoking `get` 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) Get(id []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "get", id) -} - -// GetTransaction creates a transaction invoking `get` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) GetTransaction(id []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "get", id) -} - -// GetUnsigned creates a transaction invoking `get` 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) GetUnsigned(id []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "get", nil, id) -} - -func (c *Contract) scriptForNodeAllowed(subnetID []byte, node *keys.PublicKey) ([]byte, error) { - return smartcontract.CreateCallWithAssertScript(c.hash, "nodeAllowed", subnetID, node) -} - -// NodeAllowed creates a transaction invoking `nodeAllowed` 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) NodeAllowed(subnetID []byte, node *keys.PublicKey) (util.Uint256, uint32, error) { - script, err := c.scriptForNodeAllowed(subnetID, node) - if err != nil { - return util.Uint256{}, 0, err - } - return c.actor.SendRun(script) -} - -// NodeAllowedTransaction creates a transaction invoking `nodeAllowed` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) NodeAllowedTransaction(subnetID []byte, node *keys.PublicKey) (*transaction.Transaction, error) { - script, err := c.scriptForNodeAllowed(subnetID, node) - if err != nil { - return nil, err - } - return c.actor.MakeRun(script) -} - -// NodeAllowedUnsigned creates a transaction invoking `nodeAllowed` 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) NodeAllowedUnsigned(subnetID []byte, node *keys.PublicKey) (*transaction.Transaction, error) { - script, err := c.scriptForNodeAllowed(subnetID, node) - if err != nil { - return nil, err - } - return c.actor.MakeUnsignedRun(script, nil) -} - -// 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(id []byte, ownerKey *keys.PublicKey, info []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "put", id, ownerKey, info) -} - -// 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(id []byte, ownerKey *keys.PublicKey, info []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "put", id, ownerKey, info) -} - -// 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(id []byte, ownerKey *keys.PublicKey, info []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "put", nil, id, ownerKey, info) -} - -// RemoveClientAdmin creates a transaction invoking `removeClientAdmin` 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) RemoveClientAdmin(subnetID []byte, groupID []byte, adminPublicKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeClientAdmin", subnetID, groupID, adminPublicKey) -} - -// RemoveClientAdminTransaction creates a transaction invoking `removeClientAdmin` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveClientAdminTransaction(subnetID []byte, groupID []byte, adminPublicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeClientAdmin", subnetID, groupID, adminPublicKey) -} - -// RemoveClientAdminUnsigned creates a transaction invoking `removeClientAdmin` 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) RemoveClientAdminUnsigned(subnetID []byte, groupID []byte, adminPublicKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeClientAdmin", nil, subnetID, groupID, adminPublicKey) -} - -// RemoveNode creates a transaction invoking `removeNode` 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) RemoveNode(subnetID []byte, node *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeNode", subnetID, node) -} - -// RemoveNodeTransaction creates a transaction invoking `removeNode` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveNodeTransaction(subnetID []byte, node *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeNode", subnetID, node) -} - -// RemoveNodeUnsigned creates a transaction invoking `removeNode` 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) RemoveNodeUnsigned(subnetID []byte, node *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeNode", nil, subnetID, node) -} - -// RemoveNodeAdmin creates a transaction invoking `removeNodeAdmin` 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) RemoveNodeAdmin(subnetID []byte, adminKey *keys.PublicKey) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeNodeAdmin", subnetID, adminKey) -} - -// RemoveNodeAdminTransaction creates a transaction invoking `removeNodeAdmin` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveNodeAdminTransaction(subnetID []byte, adminKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeNodeAdmin", subnetID, adminKey) -} - -// RemoveNodeAdminUnsigned creates a transaction invoking `removeNodeAdmin` 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) RemoveNodeAdminUnsigned(subnetID []byte, adminKey *keys.PublicKey) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeNodeAdmin", nil, subnetID, adminKey) -} - -// RemoveUser creates a transaction invoking `removeUser` 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) RemoveUser(subnetID []byte, groupID []byte, userID []byte) (util.Uint256, uint32, error) { - return c.actor.SendCall(c.hash, "removeUser", subnetID, groupID, userID) -} - -// RemoveUserTransaction creates a transaction invoking `removeUser` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) RemoveUserTransaction(subnetID []byte, groupID []byte, userID []byte) (*transaction.Transaction, error) { - return c.actor.MakeCall(c.hash, "removeUser", subnetID, groupID, userID) -} - -// RemoveUserUnsigned creates a transaction invoking `removeUser` 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) RemoveUserUnsigned(subnetID []byte, groupID []byte, userID []byte) (*transaction.Transaction, error) { - return c.actor.MakeUnsignedCall(c.hash, "removeUser", nil, subnetID, groupID, userID) -} - -// 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) -} - -func (c *Contract) scriptForUserAllowed(subnetID []byte, user []byte) ([]byte, error) { - return smartcontract.CreateCallWithAssertScript(c.hash, "userAllowed", subnetID, user) -} - -// UserAllowed creates a transaction invoking `userAllowed` 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) UserAllowed(subnetID []byte, user []byte) (util.Uint256, uint32, error) { - script, err := c.scriptForUserAllowed(subnetID, user) - if err != nil { - return util.Uint256{}, 0, err - } - return c.actor.SendRun(script) -} - -// UserAllowedTransaction creates a transaction invoking `userAllowed` method of the contract. -// This transaction is signed, but not sent to the network, instead it's -// returned to the caller. -func (c *Contract) UserAllowedTransaction(subnetID []byte, user []byte) (*transaction.Transaction, error) { - script, err := c.scriptForUserAllowed(subnetID, user) - if err != nil { - return nil, err - } - return c.actor.MakeRun(script) -} - -// UserAllowedUnsigned creates a transaction invoking `userAllowed` 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) UserAllowedUnsigned(subnetID []byte, user []byte) (*transaction.Transaction, error) { - script, err := c.scriptForUserAllowed(subnetID, user) - if err != nil { - return nil, err - } - return c.actor.MakeUnsignedRun(script, nil) -} - -// itemToCommonBallot converts stack item into *CommonBallot. -func itemToCommonBallot(item stackitem.Item, err error) (*CommonBallot, error) { - if err != nil { - return nil, err - } - var res = new(CommonBallot) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of CommonBallot from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *CommonBallot) FromStackItem(item stackitem.Item) error { - 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++ - res.ID, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field ID: %w", err) - } - - index++ - res.Voters, err = func (item stackitem.Item) (keys.PublicKeys, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make(keys.PublicKeys, len(arr)) - for i := range res { - res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - } (arr[i]) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Voters: %w", err) - } - - index++ - res.Height, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Height: %w", err) - } - - return nil -} - -// itemToLedgerBlock converts stack item into *LedgerBlock. -func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) { - if err != nil { - return nil, err - } - var res = new(LedgerBlock) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of LedgerBlock from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *LedgerBlock) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 9 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Hash, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Hash: %w", err) - } - - index++ - res.Version, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Version: %w", err) - } - - index++ - res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field PrevHash: %w", err) - } - - index++ - res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field MerkleRoot: %w", err) - } - - index++ - res.Timestamp, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Timestamp: %w", err) - } - - index++ - res.Nonce, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Nonce: %w", err) - } - - index++ - res.Index, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Index: %w", err) - } - - index++ - res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint160{}, err - } - u, err := util.Uint160DecodeBytesBE(b) - if err != nil { - return util.Uint160{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field NextConsensus: %w", err) - } - - index++ - res.TransactionsLength, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field TransactionsLength: %w", err) - } - - return nil -} - -// itemToLedgerBlockSR converts stack item into *LedgerBlockSR. -func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) { - if err != nil { - return nil, err - } - var res = new(LedgerBlockSR) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of LedgerBlockSR from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *LedgerBlockSR) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 10 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Hash, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Hash: %w", err) - } - - index++ - res.Version, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Version: %w", err) - } - - index++ - res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field PrevHash: %w", err) - } - - index++ - res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field MerkleRoot: %w", err) - } - - index++ - res.Timestamp, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Timestamp: %w", err) - } - - index++ - res.Nonce, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Nonce: %w", err) - } - - index++ - res.Index, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Index: %w", err) - } - - index++ - res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint160{}, err - } - u, err := util.Uint160DecodeBytesBE(b) - if err != nil { - return util.Uint160{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field NextConsensus: %w", err) - } - - index++ - res.TransactionsLength, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field TransactionsLength: %w", err) - } - - index++ - res.PrevStateRoot, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field PrevStateRoot: %w", err) - } - - return nil -} - -// itemToLedgerTransaction converts stack item into *LedgerTransaction. -func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) { - if err != nil { - return nil, err - } - var res = new(LedgerTransaction) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of LedgerTransaction from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *LedgerTransaction) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 8 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Hash, err = func (item stackitem.Item) (util.Uint256, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint256{}, err - } - u, err := util.Uint256DecodeBytesBE(b) - if err != nil { - return util.Uint256{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Hash: %w", err) - } - - index++ - res.Version, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Version: %w", err) - } - - index++ - res.Nonce, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Nonce: %w", err) - } - - index++ - res.Sender, err = func (item stackitem.Item) (util.Uint160, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint160{}, err - } - u, err := util.Uint160DecodeBytesBE(b) - if err != nil { - return util.Uint160{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Sender: %w", err) - } - - index++ - res.SysFee, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field SysFee: %w", err) - } - - index++ - res.NetFee, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field NetFee: %w", err) - } - - index++ - res.ValidUntilBlock, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field ValidUntilBlock: %w", err) - } - - index++ - res.Script, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Script: %w", err) - } - - return nil -} - -// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner. -func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) { - if err != nil { - return nil, err - } - var res = new(LedgerTransactionSigner) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of LedgerTransactionSigner from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *LedgerTransactionSigner) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 5 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Account, err = func (item stackitem.Item) (util.Uint160, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint160{}, err - } - u, err := util.Uint160DecodeBytesBE(b) - if err != nil { - return util.Uint160{}, err - } - return u, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Account: %w", err) - } - - index++ - res.Scopes, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Scopes: %w", err) - } - - index++ - res.AllowedContracts, err = func (item stackitem.Item) ([]util.Uint160, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]util.Uint160, len(arr)) - for i := range res { - res[i], err = func (item stackitem.Item) (util.Uint160, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint160{}, err - } - u, err := util.Uint160DecodeBytesBE(b) - if err != nil { - return util.Uint160{}, err - } - return u, nil - } (arr[i]) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field AllowedContracts: %w", err) - } - - index++ - res.AllowedGroups, err = func (item stackitem.Item) (keys.PublicKeys, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make(keys.PublicKeys, len(arr)) - for i := range res { - res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) { - b, err := item.TryBytes() - if err != nil { - return nil, err - } - k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256()) - if err != nil { - return nil, err - } - return k, nil - } (arr[i]) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field AllowedGroups: %w", err) - } - - index++ - res.Rules, err = func (item stackitem.Item) ([]*LedgerWitnessRule, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*LedgerWitnessRule, len(arr)) - for i := range res { - res[i], err = itemToLedgerWitnessRule(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Rules: %w", err) - } - - return nil -} - -// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition. -func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) { - if err != nil { - return nil, err - } - var res = new(LedgerWitnessCondition) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of LedgerWitnessCondition from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *LedgerWitnessCondition) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Type, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Type: %w", err) - } - - index++ - res.Value, err = arr[index].Value(), error(nil) - if err != nil { - return fmt.Errorf("field Value: %w", err) - } - - return nil -} - -// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule. -func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) { - if err != nil { - return nil, err - } - var res = new(LedgerWitnessRule) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of LedgerWitnessRule from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *LedgerWitnessRule) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Action, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Action: %w", err) - } - - index++ - res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil) - if err != nil { - return fmt.Errorf("field Condition: %w", err) - } - - return nil -} - -// itemToManagementABI converts stack item into *ManagementABI. -func itemToManagementABI(item stackitem.Item, err error) (*ManagementABI, error) { - if err != nil { - return nil, err - } - var res = new(ManagementABI) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementABI from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementABI) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Methods, err = func (item stackitem.Item) ([]*ManagementMethod, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*ManagementMethod, len(arr)) - for i := range res { - res[i], err = itemToManagementMethod(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Methods: %w", err) - } - - index++ - res.Events, err = func (item stackitem.Item) ([]*ManagementEvent, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*ManagementEvent, len(arr)) - for i := range res { - res[i], err = itemToManagementEvent(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Events: %w", err) - } - - return nil -} - -// itemToManagementContract converts stack item into *ManagementContract. -func itemToManagementContract(item stackitem.Item, err error) (*ManagementContract, error) { - if err != nil { - return nil, err - } - var res = new(ManagementContract) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementContract from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementContract) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 5 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.ID, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field ID: %w", err) - } - - index++ - res.UpdateCounter, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field UpdateCounter: %w", err) - } - - index++ - res.Hash, 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 Hash: %w", err) - } - - index++ - res.NEF, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field NEF: %w", err) - } - - index++ - res.Manifest, err = itemToManagementManifest(arr[index], nil) - if err != nil { - return fmt.Errorf("field Manifest: %w", err) - } - - return nil -} - -// itemToManagementEvent converts stack item into *ManagementEvent. -func itemToManagementEvent(item stackitem.Item, err error) (*ManagementEvent, error) { - if err != nil { - return nil, err - } - var res = new(ManagementEvent) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementEvent from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementEvent) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.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++ - res.Params, err = func (item stackitem.Item) ([]*ManagementParameter, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*ManagementParameter, len(arr)) - for i := range res { - res[i], err = itemToManagementParameter(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Params: %w", err) - } - - return nil -} - -// itemToManagementGroup converts stack item into *ManagementGroup. -func itemToManagementGroup(item stackitem.Item, err error) (*ManagementGroup, error) { - if err != nil { - return nil, err - } - var res = new(ManagementGroup) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementGroup from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementGroup) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.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++ - res.Signature, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Signature: %w", err) - } - - return nil -} - -// itemToManagementManifest converts stack item into *ManagementManifest. -func itemToManagementManifest(item stackitem.Item, err error) (*ManagementManifest, error) { - if err != nil { - return nil, err - } - var res = new(ManagementManifest) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementManifest from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementManifest) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 8 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.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++ - res.Groups, err = func (item stackitem.Item) ([]*ManagementGroup, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*ManagementGroup, len(arr)) - for i := range res { - res[i], err = itemToManagementGroup(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Groups: %w", err) - } - - index++ - res.Features, err = func (item stackitem.Item) (map[string]string, error) { - m, ok := item.Value().([]stackitem.MapElement) - if !ok { - return nil, fmt.Errorf("%s is not a map", item.Type().String()) - } - res := make(map[string]string) - for i := range m { - k, err := func (item stackitem.Item) (string, error) { - b, err := item.TryBytes() - if err != nil { - return "", err - } - if !utf8.Valid(b) { - return "", errors.New("not a UTF-8 string") - } - return string(b), nil - } (m[i].Key) - if err != nil { - return nil, fmt.Errorf("key %d: %w", i, err) - } - v, err := func (item stackitem.Item) (string, error) { - b, err := item.TryBytes() - if err != nil { - return "", err - } - if !utf8.Valid(b) { - return "", errors.New("not a UTF-8 string") - } - return string(b), nil - } (m[i].Value) - if err != nil { - return nil, fmt.Errorf("value %d: %w", i, err) - } - res[k] = v - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Features: %w", err) - } - - index++ - res.SupportedStandards, err = func (item stackitem.Item) ([]string, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]string, len(arr)) - for i := range res { - res[i], err = func (item stackitem.Item) (string, error) { - b, err := item.TryBytes() - if err != nil { - return "", err - } - if !utf8.Valid(b) { - return "", errors.New("not a UTF-8 string") - } - return string(b), nil - } (arr[i]) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field SupportedStandards: %w", err) - } - - index++ - res.ABI, err = itemToManagementABI(arr[index], nil) - if err != nil { - return fmt.Errorf("field ABI: %w", err) - } - - index++ - res.Permissions, err = func (item stackitem.Item) ([]*ManagementPermission, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*ManagementPermission, len(arr)) - for i := range res { - res[i], err = itemToManagementPermission(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Permissions: %w", err) - } - - index++ - res.Trusts, err = func (item stackitem.Item) ([]util.Uint160, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]util.Uint160, len(arr)) - for i := range res { - res[i], err = func (item stackitem.Item) (util.Uint160, error) { - b, err := item.TryBytes() - if err != nil { - return util.Uint160{}, err - } - u, err := util.Uint160DecodeBytesBE(b) - if err != nil { - return util.Uint160{}, err - } - return u, nil - } (arr[i]) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Trusts: %w", err) - } - - index++ - res.Extra, err = arr[index].Value(), error(nil) - if err != nil { - return fmt.Errorf("field Extra: %w", err) - } - - return nil -} - -// itemToManagementMethod converts stack item into *ManagementMethod. -func itemToManagementMethod(item stackitem.Item, err error) (*ManagementMethod, error) { - if err != nil { - return nil, err - } - var res = new(ManagementMethod) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementMethod from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementMethod) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 5 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.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++ - res.Params, err = func (item stackitem.Item) ([]*ManagementParameter, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]*ManagementParameter, len(arr)) - for i := range res { - res[i], err = itemToManagementParameter(arr[i], nil) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Params: %w", err) - } - - index++ - res.ReturnType, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field ReturnType: %w", err) - } - - index++ - res.Offset, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Offset: %w", err) - } - - index++ - res.Safe, err = arr[index].TryBool() - if err != nil { - return fmt.Errorf("field Safe: %w", err) - } - - return nil -} - -// itemToManagementParameter converts stack item into *ManagementParameter. -func itemToManagementParameter(item stackitem.Item, err error) (*ManagementParameter, error) { - if err != nil { - return nil, err - } - var res = new(ManagementParameter) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementParameter from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementParameter) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.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++ - res.Type, err = arr[index].TryInteger() - if err != nil { - return fmt.Errorf("field Type: %w", err) - } - - return nil -} - -// itemToManagementPermission converts stack item into *ManagementPermission. -func itemToManagementPermission(item stackitem.Item, err error) (*ManagementPermission, error) { - if err != nil { - return nil, err - } - var res = new(ManagementPermission) - err = res.FromStackItem(item) - return res, err -} - -// FromStackItem retrieves fields of ManagementPermission from the given -// [stackitem.Item] or returns an error if it's not possible to do to so. -func (res *ManagementPermission) FromStackItem(item stackitem.Item) error { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return errors.New("not an array") - } - if len(arr) != 2 { - return errors.New("wrong number of structure elements") - } - - var ( - index = -1 - err error - ) - index++ - res.Contract, 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 Contract: %w", err) - } - - index++ - res.Methods, err = func (item stackitem.Item) ([]string, error) { - arr, ok := item.Value().([]stackitem.Item) - if !ok { - return nil, errors.New("not an array") - } - res := make([]string, len(arr)) - for i := range res { - res[i], err = func (item stackitem.Item) (string, error) { - b, err := item.TryBytes() - if err != nil { - return "", err - } - if !utf8.Valid(b) { - return "", errors.New("not a UTF-8 string") - } - return string(b), nil - } (arr[i]) - if err != nil { - return nil, fmt.Errorf("item %d: %w", i, err) - } - } - return res, nil - } (arr[index]) - if err != nil { - return fmt.Errorf("field Methods: %w", err) - } - - return nil -} - -// DeleteEventsFromApplicationLog retrieves a set of all emitted events -// with "Delete" name from the provided [result.ApplicationLog]. -func DeleteEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*DeleteEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "Delete" { - continue - } - event := new(DeleteEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize DeleteEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to DeleteEvent or -// returns an error if it's not possible to do to so. -func (e *DeleteEvent) 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.Id, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field Id: %w", err) - } - - return nil -} - -// RemoveNodeEventsFromApplicationLog retrieves a set of all emitted events -// with "RemoveNode" name from the provided [result.ApplicationLog]. -func RemoveNodeEventsFromApplicationLog(log *result.ApplicationLog) ([]*RemoveNodeEvent, error) { - if log == nil { - return nil, errors.New("nil application log") - } - - var res []*RemoveNodeEvent - for i, ex := range log.Executions { - for j, e := range ex.Events { - if e.Name != "RemoveNode" { - continue - } - event := new(RemoveNodeEvent) - err := event.FromStackItem(e.Item) - if err != nil { - return nil, fmt.Errorf("failed to deserialize RemoveNodeEvent from stackitem (execution #%d, event #%d): %w", i, j, err) - } - res = append(res, event) - } - } - - return res, nil -} - -// FromStackItem converts provided [stackitem.Array] to RemoveNodeEvent or -// returns an error if it's not possible to do to so. -func (e *RemoveNodeEvent) 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.SubnetID, err = arr[index].TryBytes() - if err != nil { - return fmt.Errorf("field SubnetID: %w", err) - } - - index++ - e.Node, 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 Node: %w", err) - } - - return nil -} diff --git a/subnet/config.yml b/subnet/config.yml deleted file mode 100644 index eae19734..00000000 --- a/subnet/config.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: "NeoFS Subnet" -safemethods: ["version"] -permissions: - - methods: ["update"] -events: - - name: Delete - parameters: - - name: id - type: ByteArray - - name: RemoveNode - parameters: - - name: subnetID - type: ByteArray - - name: node - type: PublicKey diff --git a/subnet/doc.go b/subnet/doc.go deleted file mode 100644 index d3471419..00000000 --- a/subnet/doc.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -Package subnet contains implementation of Subnet contract deployed in NeoFS -sidechain. - -Subnet contract stores and manages NeoFS subnetwork states. It allows registering -and deleting subnetworks, limiting access to them, and defining a list of the Storage -Nodes that can be included in them. - -# Contract notifications - -Put notification. This notification is produced when a new subnetwork is -registered by invoking Put method. - - Put - - name: id - type: ByteArray - - name: ownerKey - type: PublicKey - - name: info - type: ByteArray - -Delete notification. This notification is produced when some subnetwork is -deleted by invoking Delete method. - - Delete - - name: id - type: ByteArray - -RemoveNode notification. This notification is produced when some node is deleted -by invoking RemoveNode method. - - RemoveNode - - name: subnetID - type: ByteArray - - name: node - type: PublicKey -*/ -package subnet - -/* -Contract storage model. - -# Summary -Current conventions: - : binary-encoded unique identifier of the subnet - -Key-value storage format: - - 'o' -> interop.PublicKey - public keys of the subnet owners - - 'i' -> []byte - subnet descriptors encoded into NeoFS API binary protocol format - - 'n' + interop.PublicKey -> 1 - public keys of nodes forming the subnet cluster - - 'a' + interop.PublicKey -> 1 - public keys of administrators managing topology of the subnet cluster - - 'u' + interop.PublicKey -> 1 - public keys of clients using the subnet to store data - - 'm' + interop.PublicKey -> 1 - public keys of administrators managing clients of the subnet - -# Registration -Contract stores information about all subnets and their owners presented in the -NeoFS network for which the contract is deployed. - -# Topology management -Contract records the parties responsible for managing subnets' cluster -topology. - -# Client management -Contract records the parties responsible for managing subnet clients which store -data in the subnet cluster. -*/ diff --git a/subnet/migration_test.go b/subnet/migration_test.go deleted file mode 100644 index aa6d9ff1..00000000 --- a/subnet/migration_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package subnet_test - -import ( - "testing" - - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/nspcc-dev/neofs-contract/tests/dump" - "github.com/nspcc-dev/neofs-contract/tests/migration" - "github.com/stretchr/testify/require" -) - -const name = "subnet" - -func TestMigration(t *testing.T) { - err := dump.IterateDumps("../testdata", func(id dump.ID, r *dump.Reader) { - t.Run(id.String()+"/"+name, func(t *testing.T) { - testMigrationFromDump(t, r) - }) - }) - require.NoError(t, err) -} - -var notaryDisabledKey = []byte("notary") - -func testMigrationFromDump(t *testing.T, d *dump.Reader) { - // init test contract shell - c := migration.NewContract(t, d, "subnet", migration.ContractOptions{}) - - migration.SkipUnsupportedVersions(t, c) - - // gather values which can't be fetched via contract API - v := c.GetStorageItem(notaryDisabledKey) - notaryDisabled := len(v) == 1 && v[0] == 1 - - readPendingVotes := func() bool { - if v := c.GetStorageItem([]byte("ballots")); v != nil { - item, err := stackitem.Deserialize(v) - require.NoError(t, err) - arr, ok := item.Value().([]stackitem.Item) - if ok { - return len(arr) > 0 - } else { - require.Equal(t, stackitem.Null{}, item) - } - } - return false - } - - prevPendingVote := readPendingVotes() - - // try to update the contract - var notary bool - c.CheckUpdateFail(t, "update to non-notary mode is not supported anymore", !notary) - - if notaryDisabled && prevPendingVote { - c.CheckUpdateFail(t, "pending vote detected", notary) - return - } - - c.CheckUpdateSuccess(t, notary) - - // check that contract was updates as expected - newPendingVotes := readPendingVotes() - - require.False(t, newPendingVotes, "notary flag should be removed") - require.Nil(t, c.GetStorageItem(notaryDisabledKey), "notary flag should be removed") -} diff --git a/subnet/subnet_contract.go b/subnet/subnet_contract.go deleted file mode 100644 index dc24508d..00000000 --- a/subnet/subnet_contract.go +++ /dev/null @@ -1,609 +0,0 @@ -package subnet - -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/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" - "github.com/nspcc-dev/neofs-contract/common" -) - -const ( - // ErrInvalidSubnetID is thrown when subnet id is not a slice of 5 bytes. - ErrInvalidSubnetID = "invalid subnet ID" - // ErrInvalidGroupID is thrown when group id is not a slice of 5 bytes. - ErrInvalidGroupID = "invalid group ID" - // ErrInvalidOwner is thrown when owner has invalid format. - ErrInvalidOwner = "invalid owner" - // ErrInvalidAdmin is thrown when admin has invalid format. - ErrInvalidAdmin = "invalid administrator" - // ErrAlreadyExists is thrown when id already exists. - ErrAlreadyExists = "subnet id already exists" - // ErrNotExist is thrown when id doesn't exist. - ErrNotExist = "subnet id doesn't exist" - // ErrInvalidUser is thrown when user has invalid format. - ErrInvalidUser = "invalid user" - // ErrInvalidNode is thrown when node has invalid format. - ErrInvalidNode = "invalid node key" - // ErrNodeAdmNotExist is thrown when node admin is not found. - ErrNodeAdmNotExist = "node admin not found" - // ErrClientAdmNotExist is thrown when client admin is not found. - ErrClientAdmNotExist = "client admin not found" - // ErrNodeNotExist is thrown when node is not found. - ErrNodeNotExist = "node not found" - // ErrUserNotExist is thrown when user is not found. - ErrUserNotExist = "user not found" - // ErrAccessDenied is thrown when operation is denied for caller. - ErrAccessDenied = "access denied" -) - -const ( - nodeAdminPrefix = 'a' - infoPrefix = 'i' - clientAdminPrefix = 'm' - nodePrefix = 'n' - ownerPrefix = 'o' - userPrefix = 'u' -) - -const ( - userIDSize = 27 - subnetIDSize = 5 - groupIDSize = 5 -) - -// _deploy function sets up initial list of inner ring public keys. -// nolint:deadcode,unused -func _deploy(data interface{}, isUpdate bool) { - if isUpdate { - args := data.([]interface{}) - version := args[len(args)-1].(int) - - common.CheckVersion(version) - - if args[0].(bool) { - panic("update to non-notary mode is not supported anymore") - } - - // switch to notary mode if version of the current contract deployment is - // earlier than v0.17.0 (initial version when non-notary mode was taken out of - // use) - // TODO: avoid number magic, add function for version comparison to common package - if version < 17_000 { - switchToNotary(storage.GetContext()) - } - - return - } -} - -// re-initializes contract from non-notary to notary mode. Does nothing if -// action has already been done. The function is called on contract update with -// storage.Context from _deploy. -// -// If contract stores non-empty value by 'ballots' key, switchToNotary panics. -// Otherwise, existing value is removed. -// -// switchToNotary removes value stored by 'notary' key. -// -// nolint:unused -func switchToNotary(ctx storage.Context) { - const notaryDisabledKey = "notary" // non-notary legacy - - notaryVal := storage.Get(ctx, notaryDisabledKey) - if notaryVal == nil { - runtime.Log("contract is already notarized") - return - } else if notaryVal.(bool) && !common.TryPurgeVotes(ctx) { - panic("pending vote detected") - } - - storage.Delete(ctx, notaryDisabledKey) - - if notaryVal.(bool) { - runtime.Log("contract successfully notarized") - } -} - -// 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("subnet contract updated") -} - -// Put creates a new subnet with the specified owner and info. -func Put(id []byte, ownerKey interop.PublicKey, info []byte) { - // V2 format - if len(id) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - if len(ownerKey) != interop.PublicKeyCompressedLen { - panic(ErrInvalidOwner) - } - - ctx := storage.GetContext() - stKey := append([]byte{ownerPrefix}, id...) - if storage.Get(ctx, stKey) != nil { - panic(ErrAlreadyExists) - } - - common.CheckOwnerWitness(ownerKey) - - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - - storage.Put(ctx, stKey, ownerKey) - stKey[0] = infoPrefix - storage.Put(ctx, stKey, info) -} - -// Get returns info about the subnet with the specified id. -func Get(id []byte) []byte { - // V2 format - if len(id) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - ctx := storage.GetReadOnlyContext() - key := append([]byte{infoPrefix}, id...) - raw := storage.Get(ctx, key) - if raw == nil { - panic(ErrNotExist) - } - return raw.([]byte) -} - -// Delete deletes the subnet with the specified id. -func Delete(id []byte) { - // V2 format - if len(id) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - ctx := storage.GetContext() - key := append([]byte{ownerPrefix}, id...) - raw := storage.Get(ctx, key) - if raw == nil { - return - } - - owner := raw.([]byte) - common.CheckOwnerWitness(owner) - - storage.Delete(ctx, key) - - key[0] = infoPrefix - storage.Delete(ctx, key) - - key[0] = nodeAdminPrefix - deleteByPrefix(ctx, key) - - key[0] = nodePrefix - deleteByPrefix(ctx, key) - - key[0] = clientAdminPrefix - deleteByPrefix(ctx, key) - - key[0] = userPrefix - deleteByPrefix(ctx, key) - - runtime.Notify("Delete", id) -} - -// AddNodeAdmin adds a new node administrator to the specified subnetwork. -func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - if len(adminKey) != interop.PublicKeyCompressedLen { - panic(ErrInvalidAdmin) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - owner := rawOwner.([]byte) - common.CheckOwnerWitness(owner) - - stKey[0] = nodeAdminPrefix - - if keyInList(ctx, adminKey, stKey) { - return - } - - putKeyInList(ctx, adminKey, stKey) -} - -// RemoveNodeAdmin removes node administrator from the specified subnetwork. -// Must be called by the subnet owner only. -func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - if len(adminKey) != interop.PublicKeyCompressedLen { - panic(ErrInvalidAdmin) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - owner := rawOwner.([]byte) - common.CheckOwnerWitness(owner) - - stKey[0] = nodeAdminPrefix - - if !keyInList(ctx, adminKey, stKey) { - return - } - - deleteKeyFromList(ctx, adminKey, stKey) -} - -// AddNode adds a node to the specified subnetwork. -// Must be called by the subnet's owner or the node administrator -// only. -func AddNode(subnetID []byte, node interop.PublicKey) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - if len(node) != interop.PublicKeyCompressedLen { - panic(ErrInvalidNode) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - stKey[0] = nodeAdminPrefix - - owner := rawOwner.([]byte) - - if !calledByOwnerOrAdmin(ctx, owner, stKey) { - panic(ErrAccessDenied) - } - - stKey[0] = nodePrefix - - if keyInList(ctx, node, stKey) { - return - } - - putKeyInList(ctx, node, stKey) -} - -// RemoveNode removes a node from the specified subnetwork. -// Must be called by the subnet's owner or the node administrator -// only. -func RemoveNode(subnetID []byte, node interop.PublicKey) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - if len(node) != interop.PublicKeyCompressedLen { - panic(ErrInvalidNode) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - stKey[0] = nodeAdminPrefix - - owner := rawOwner.([]byte) - - if !calledByOwnerOrAdmin(ctx, owner, stKey) { - panic(ErrAccessDenied) - } - - stKey[0] = nodePrefix - - if !keyInList(ctx, node, stKey) { - return - } - - storage.Delete(ctx, append(stKey, node...)) - - runtime.Notify("RemoveNode", subnetID, node) -} - -// NodeAllowed checks if a node is included in the -// specified subnet. -func NodeAllowed(subnetID []byte, node interop.PublicKey) bool { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - if len(node) != interop.PublicKeyCompressedLen { - panic(ErrInvalidNode) - } - - ctx := storage.GetReadOnlyContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - stKey[0] = nodePrefix - - return storage.Get(ctx, append(stKey, node...)) != nil -} - -// AddClientAdmin adds a new client administrator of the specified group in the specified subnetwork. -// Must be called by the owner only. -func AddClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - // V2 format - if len(groupID) != groupIDSize { - panic(ErrInvalidGroupID) - } - - if len(adminPublicKey) != interop.PublicKeyCompressedLen { - panic(ErrInvalidAdmin) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - owner := rawOwner.([]byte) - common.CheckOwnerWitness(owner) - - stKey[0] = clientAdminPrefix - stKey = append(stKey, groupID...) - - if keyInList(ctx, adminPublicKey, stKey) { - return - } - - putKeyInList(ctx, adminPublicKey, stKey) -} - -// RemoveClientAdmin removes client administrator from the -// specified group in the specified subnetwork. -// Must be called by the owner only. -func RemoveClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - // V2 format - if len(groupID) != groupIDSize { - panic(ErrInvalidGroupID) - } - - if len(adminPublicKey) != interop.PublicKeyCompressedLen { - panic(ErrInvalidAdmin) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - owner := rawOwner.([]byte) - common.CheckOwnerWitness(owner) - - stKey[0] = clientAdminPrefix - stKey = append(stKey, groupID...) - - if !keyInList(ctx, adminPublicKey, stKey) { - return - } - - deleteKeyFromList(ctx, adminPublicKey, stKey) -} - -// AddUser adds user to the specified subnetwork and group. -// Must be called by the owner or the group's admin only. -func AddUser(subnetID []byte, groupID []byte, userID []byte) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - // V2 format - if len(userID) != userIDSize { - panic(ErrInvalidUser) - } - - // V2 format - if len(groupID) != groupIDSize { - panic(ErrInvalidGroupID) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - stKey[0] = clientAdminPrefix - stKey = append(stKey, groupID...) - - owner := rawOwner.([]byte) - - if !calledByOwnerOrAdmin(ctx, owner, stKey) { - panic(ErrAccessDenied) - } - - stKey[0] = userPrefix - - if keyInList(ctx, userID, stKey) { - return - } - - putKeyInList(ctx, userID, stKey) -} - -// RemoveUser removes a user from the specified subnetwork and group. -// Must be called by the owner or the group's admin only. -func RemoveUser(subnetID []byte, groupID []byte, userID []byte) { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - // V2 format - if len(groupID) != groupIDSize { - panic(ErrInvalidGroupID) - } - - // V2 format - if len(userID) != userIDSize { - panic(ErrInvalidUser) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - - rawOwner := storage.Get(ctx, stKey) - if rawOwner == nil { - panic(ErrNotExist) - } - - stKey[0] = clientAdminPrefix - stKey = append(stKey, groupID...) - - owner := rawOwner.([]byte) - - if !calledByOwnerOrAdmin(ctx, owner, stKey) { - panic(ErrAccessDenied) - } - - stKey[0] = userPrefix - - if !keyInList(ctx, userID, stKey) { - return - } - - deleteKeyFromList(ctx, userID, stKey) -} - -// UserAllowed returns bool that indicates if a node is included in the -// specified subnet. -func UserAllowed(subnetID []byte, user []byte) bool { - // V2 format - if len(subnetID) != subnetIDSize { - panic(ErrInvalidSubnetID) - } - - ctx := storage.GetContext() - - stKey := append([]byte{ownerPrefix}, subnetID...) - if storage.Get(ctx, stKey) == nil { - panic(ErrNotExist) - } - - stKey[0] = userPrefix - prefixLen := len(stKey) + groupIDSize - - iter := storage.Find(ctx, stKey, storage.KeysOnly) - for iterator.Next(iter) { - key := iterator.Value(iter).([]byte) - if common.BytesEqual(user, key[prefixLen:]) { - return true - } - } - - return false -} - -// Version returns the version of the contract. -func Version() int { - return common.Version -} - -func keyInList(ctx storage.Context, searchedKey interop.PublicKey, prefix []byte) bool { - return storage.Get(ctx, append(prefix, searchedKey...)) != nil -} - -func putKeyInList(ctx storage.Context, keyToPut interop.PublicKey, prefix []byte) { - storage.Put(ctx, append(prefix, keyToPut...), []byte{1}) -} - -func deleteKeyFromList(ctx storage.Context, keyToDelete interop.PublicKey, prefix []byte) { - storage.Delete(ctx, append(prefix, keyToDelete...)) -} - -func deleteByPrefix(ctx storage.Context, prefix []byte) { - iter := storage.Find(ctx, prefix, storage.KeysOnly) - for iterator.Next(iter) { - k := iterator.Value(iter).([]byte) - storage.Delete(ctx, k) - } -} - -func calledByOwnerOrAdmin(ctx storage.Context, owner []byte, adminPrefix []byte) bool { - if runtime.CheckWitness(owner) { - return true - } - - iter := storage.Find(ctx, adminPrefix, storage.KeysOnly|storage.RemovePrefix) - for iterator.Next(iter) { - key := iterator.Value(iter).([]byte) - if runtime.CheckWitness(key) { - return true - } - } - - return false -} diff --git a/tests/subnet_test.go b/tests/subnet_test.go deleted file mode 100644 index fa4d6a3f..00000000 --- a/tests/subnet_test.go +++ /dev/null @@ -1,330 +0,0 @@ -package tests - -import ( - "encoding/binary" - "path" - "testing" - - "github.com/nspcc-dev/neo-go/pkg/neotest" - "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/neofs-contract/common" - "github.com/nspcc-dev/neofs-contract/subnet" - "github.com/stretchr/testify/require" -) - -const subnetPath = "../subnet" - -func deploySubnetContract(t *testing.T, e *neotest.Executor) util.Uint160 { - c := neotest.CompileFile(t, e.CommitteeHash, subnetPath, path.Join(subnetPath, "config.yml")) - args := []interface{}{false} - e.DeployContract(t, c, args) - return c.Hash -} - -func newSubnetInvoker(t *testing.T) *neotest.ContractInvoker { - e := newExecutor(t) - h := deploySubnetContract(t, e) - return e.CommitteeInvoker(h) -} - -func TestSubnet_Version(t *testing.T) { - e := newSubnetInvoker(t) - e.Invoke(t, common.Version, "version") -} - -func TestSubnet_Put(t *testing.T) { - e := newSubnetInvoker(t) - - acc := e.NewAccount(t) - pub, ok := vm.ParseSignatureContract(acc.Script()) - require.True(t, ok) - - id := make([]byte, 5) - binary.LittleEndian.PutUint32(id, 123) - info := randomBytes(10) - - e.InvokeFail(t, common.ErrWitnessFailed, "put", id, pub, info) - - cAcc := e.WithSigners(acc) - cAcc.InvokeFail(t, common.ErrAlphabetWitnessFailed, "put", id, pub, info) - - cBoth := e.WithSigners(e.Committee, acc) - cBoth.InvokeFail(t, subnet.ErrInvalidSubnetID, "put", []byte{1, 2, 3}, pub, info) - cBoth.InvokeFail(t, subnet.ErrInvalidOwner, "put", id, pub[10:], info) - cBoth.Invoke(t, stackitem.Null{}, "put", id, pub, info) - cAcc.Invoke(t, stackitem.NewBuffer(info), "get", id) - cBoth.InvokeFail(t, subnet.ErrAlreadyExists, "put", id, pub, info) -} - -func TestSubnet_Delete(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - e.InvokeFail(t, common.ErrWitnessFailed, "delete", id) - - cAcc := e.WithSigners(owner) - cAcc.InvokeFail(t, subnet.ErrInvalidSubnetID, "delete", []byte{1, 1, 1, 1}) - cAcc.Invoke(t, stackitem.Null{}, "delete", []byte{1, 1, 1, 1, 1}) - cAcc.Invoke(t, stackitem.Null{}, "delete", id) - cAcc.InvokeFail(t, subnet.ErrNotExist, "get", id) -} - -func TestSubnet_AddNodeAdmin(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - const method = "addNodeAdmin" - - e.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, admPub) - e.InvokeFail(t, subnet.ErrInvalidAdmin, method, id, admPub[1:]) - e.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, admPub) - - cAdm := e.WithSigners(adm) - cAdm.InvokeFail(t, common.ErrOwnerWitnessFailed, method, id, admPub) - - cOwner := e.WithSigners(owner) - cOwner.Invoke(t, stackitem.Null{}, method, id, admPub) - - cOwner.Invoke(t, stackitem.Null{}, method, id, admPub) -} - -func TestSubnet_RemoveNodeAdmin(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - const method = "removeNodeAdmin" - - e.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, admPub) - e.InvokeFail(t, subnet.ErrInvalidAdmin, method, id, admPub[1:]) - e.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, admPub) - - cAdm := e.WithSigners(adm) - cAdm.InvokeFail(t, common.ErrOwnerWitnessFailed, method, id, admPub) - - cOwner := e.WithSigners(owner) - - cOwner.Invoke(t, stackitem.Null{}, method, id, admPub) - cOwner.Invoke(t, stackitem.Null{}, "addNodeAdmin", id, admPub) - cOwner.Invoke(t, stackitem.Null{}, method, id, admPub) - cOwner.Invoke(t, stackitem.Null{}, method, id, admPub) -} - -func TestSubnet_AddNode(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - node := e.NewAccount(t) - nodePub, ok := vm.ParseSignatureContract(node.Script()) - require.True(t, ok) - - const method = "addNode" - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, nodePub) - cOwn.InvokeFail(t, subnet.ErrInvalidNode, method, id, nodePub[1:]) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, nodePub) - - cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub) - cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub) -} - -func TestSubnet_RemoveNode(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - node := e.NewAccount(t) - nodePub, ok := vm.ParseSignatureContract(node.Script()) - require.True(t, ok) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - const method = "removeNode" - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, nodePub) - cOwn.InvokeFail(t, subnet.ErrInvalidNode, method, id, nodePub[1:]) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, nodePub) - cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub) - - cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub) - cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub) - - cAdm := cOwn.WithSigners(adm) - - cOwn.Invoke(t, stackitem.Null{}, "addNodeAdmin", id, admPub) - cAdm.Invoke(t, stackitem.Null{}, method, id, nodePub) -} - -func TestSubnet_NodeAllowed(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - node := e.NewAccount(t) - nodePub, ok := vm.ParseSignatureContract(node.Script()) - require.True(t, ok) - - const method = "nodeAllowed" - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, nodePub) - cOwn.InvokeFail(t, subnet.ErrInvalidNode, method, id, nodePub[1:]) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, nodePub) - cOwn.Invoke(t, stackitem.NewBool(false), method, id, nodePub) - - cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub) - cOwn.Invoke(t, stackitem.NewBool(true), method, id, nodePub) -} - -func TestSubnet_AddClientAdmin(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - const method = "addClientAdmin" - - groupId := randomBytes(5) - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, groupId, admPub) - cOwn.InvokeFail(t, subnet.ErrInvalidAdmin, method, id, groupId, admPub[1:]) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, groupId, admPub) - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, admPub) - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, admPub) -} - -func TestSubnet_RemoveClientAdmin(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - const method = "removeClientAdmin" - - groupId := randomBytes(5) - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, groupId, admPub) - cOwn.InvokeFail(t, subnet.ErrInvalidAdmin, method, id, groupId, admPub[1:]) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, groupId, admPub) - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, admPub) - cOwn.Invoke(t, stackitem.Null{}, "addClientAdmin", id, groupId, admPub) - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, admPub) -} - -func TestSubnet_AddUser(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - user := randomBytes(27) - - groupId := randomBytes(5) - - const method = "addUser" - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, groupId, user) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, groupId, user) - - cOwn.Invoke(t, stackitem.Null{}, "addClientAdmin", id, groupId, admPub) - - cAdm := e.WithSigners(adm) - cAdm.Invoke(t, stackitem.Null{}, method, id, groupId, user) - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, user) -} - -func TestSubnet_RemoveUser(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - groupId := randomBytes(5) - user := randomBytes(27) - - adm := e.NewAccount(t) - admPub, ok := vm.ParseSignatureContract(adm.Script()) - require.True(t, ok) - - const method = "removeUser" - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrInvalidSubnetID, method, []byte{0, 0, 0, 0}, groupId, user) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, groupId, user) - - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, user) - cOwn.Invoke(t, stackitem.Null{}, "addUser", id, groupId, user) - cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, user) - - cAdm := cOwn.WithSigners(adm) - - cOwn.Invoke(t, stackitem.Null{}, "addClientAdmin", id, groupId, admPub) - cAdm.Invoke(t, stackitem.Null{}, method, id, groupId, user) -} - -func TestSubnet_UserAllowed(t *testing.T) { - e := newSubnetInvoker(t) - - id, owner := createSubnet(t, e) - - groupId := randomBytes(5) - - user := randomBytes(27) - - const method = "userAllowed" - - cOwn := e.WithSigners(owner) - cOwn.InvokeFail(t, subnet.ErrNotExist, method, []byte{0, 0, 0, 0, 0}, user) - - cOwn.Invoke(t, stackitem.NewBool(false), method, id, user) - cOwn.Invoke(t, stackitem.Null{}, "addUser", id, groupId, user) - cOwn.Invoke(t, stackitem.NewBool(true), method, id, user) -} - -func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) { - var ( - ok bool - pub []byte - ) - - owner = e.NewAccount(t) - pub, ok = vm.ParseSignatureContract(owner.Script()) - require.True(t, ok) - - id = make([]byte, 5) - binary.LittleEndian.PutUint32(id, 123) - info := randomBytes(10) - - cBoth := e.WithSigners(e.Committee, owner) - cBoth.Invoke(t, stackitem.Null{}, "put", id, pub, info) - - return -}