[#240] English Check

Signed-off-by: Elizaveta Chichindaeva <elizaveta@nspcc.ru>
This commit is contained in:
Elizaveta Chichindaeva 2022-04-14 14:56:51 +03:00 committed by Alex Vanin
parent c75315808b
commit 335b04d9a6
30 changed files with 425 additions and 425 deletions

View file

@ -11,14 +11,14 @@
NeoFS-Contract contains all NeoFS related contracts written for NeoFS-Contract contains all NeoFS related contracts written for
[neo-go](https://github.com/nspcc-dev/neo-go) compiler. These contracts [neo-go](https://github.com/nspcc-dev/neo-go) compiler. These contracts
are deployed both in main chain and side chain. are deployed both in the mainchain and the sidechain.
Main chain contracts: Mainchain contracts:
- neofs - neofs
- processing - processing
Side chain contracts: Sidechain contracts:
- alphabet - alphabet
- audit - audit
@ -41,7 +41,7 @@ To compile smart contracts you need:
## Compilation ## Compilation
To build and compile smart contract run `make all` command. Compiled contracts To build and compile smart contract, run `make all` command. Compiled contracts
`*_contract.nef` and manifest `config.json` files are placed in the `*_contract.nef` and manifest `config.json` files are placed in the
corresponding directories. corresponding directories.
@ -71,7 +71,7 @@ Remove compiled files with `make clean` or `make mr_proper` command.
# Testing # Testing
Smartcontract tests reside in `tests/` directory. To execute test suite Smartcontract tests reside in `tests/` directory. To execute test suite
after applying changes simply run `make test`. after applying changes, simply run `make test`.
``` ```
$ make test $ make test
ok github.com/nspcc-dev/neofs-contract/tests 0.462s ok github.com/nspcc-dev/neofs-contract/tests 0.462s

View file

@ -69,7 +69,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log(args.name + " contract initialized") runtime.Log(args.name + " contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -81,12 +81,12 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("alphabet contract updated") runtime.Log("alphabet contract updated")
} }
// GAS returns amount of side chain GAS stored in contract account. // GAS returns the amount of the sidechain GAS stored in the contract account.
func Gas() int { func Gas() int {
return gas.BalanceOf(runtime.GetExecutingScriptHash()) return gas.BalanceOf(runtime.GetExecutingScriptHash())
} }
// NEO returns amount of side chain NEO stored in contract account. // NEO returns the amount of sidechain NEO stored in the contract account.
func Neo() int { func Neo() int {
return neo.BalanceOf(runtime.GetExecutingScriptHash()) return neo.BalanceOf(runtime.GetExecutingScriptHash())
} }
@ -116,16 +116,16 @@ func checkPermission(ir []interop.PublicKey) bool {
return runtime.CheckWitness(node) return runtime.CheckWitness(node)
} }
// Emit method produces side chain GAS and distributes it among Inner Ring nodes // Emit method produces sidechain GAS and distributes it among Inner Ring nodes
// and proxy contract. Can be invoked only by Alphabet node of the Inner Ring. // and proxy contract. It can be invoked only by an Alphabet node of the Inner Ring.
// //
// To produce GAS, alphabet contract transfers all available NEO from contract // To produce GAS, an alphabet contract transfers all available NEO from the contract
// account to itself. If notary enabled, then 50% of the GAS in the contract account // account to itself. If notary is enabled, 50% of the GAS in the contract account
// transferred to proxy contract. 43.75% of the GAS are equally distributed // are transferred to proxy contract. 43.75% of the GAS are equally distributed
// among all Inner Ring nodes. Remaining 6.25% of the GAS stays in the contract. // among all Inner Ring nodes. Remaining 6.25% of the GAS stay in the contract.
// //
// If notary disabled, then 87.5% of the GAS are equally distributed among all // If notary is disabled, 87.5% of the GAS are equally distributed among all
// Inner Ring nodes. Remaining 12.5% of the GAS stays in the contract. // Inner Ring nodes. Remaining 12.5% of the GAS stay in the contract.
func Emit() { func Emit() {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -183,13 +183,13 @@ func Emit() {
} }
} }
// Vote method votes for side chain committee. Requires multisignature from // Vote method votes for the sidechain committee. It requires multisignature from
// Alphabet nodes of the Inner Ring. // Alphabet nodes of the Inner Ring.
// //
// This method is used when governance changes list of Alphabet nodes of the // This method is used when governance changes the list of Alphabet nodes of the
// Inner Ring. Alphabet nodes share keys with side chain validators, therefore // Inner Ring. Alphabet nodes share keys with sidechain validators, therefore
// it is required to change them as well. To do that NEO holders, which are // it is required to change them as well. To do that, NEO holders (which are
// alphabet contracts, should vote for new committee. // alphabet contracts) should vote for a new committee.
func Vote(epoch int, candidates []interop.PublicKey) { func Vote(epoch int, candidates []interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -255,13 +255,13 @@ func voteID(epoch interface{}, args []interop.PublicKey) []byte {
return crypto.Sha256(result) return crypto.Sha256(result)
} }
// Name returns Glagolitic name of the contract. // Name returns the Glagolitic name of the contract.
func Name() string { func Name() string {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return name(ctx) return name(ctx)
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -1,17 +1,17 @@
/* /*
Alphabet contract is a contract deployed in NeoFS side chain. Alphabet contract is a contract deployed in NeoFS sidechain.
Alphabet contract is designed to support GAS producing and voting for new Alphabet contract is designed to support GAS production and vote for new
validators in the side chain. NEO token is required to produce GAS and vote for validators in the sidechain. NEO token is required to produce GAS and vote for
a new committee. If can be distributed among alphabet nodes of Inner Ring. a new committee. It can be distributed among alphabet nodes of the Inner Ring.
However, some of them may be malicious and some NEO can be lost. It will lead However, some of them may be malicious, and some NEO can be lost. It will destabilize
to side chain economic destabilization. To avoid it, all 100 000 000 NEO are the economic of the sidechain. To avoid it, all 100,000,000 NEO are
distributed among all alphabet contracts. distributed among all alphabet contracts.
To identify alphabet contracts, they are named with letters of the Glagolitic. To identify alphabet contracts, they are named with letters of the Glagolitic alphabet.
Names are set at contract deploy. Alphabet nodes of Inner Ring communicate with Names are set at contract deploy. Alphabet nodes of the Inner Ring communicate with
one of the alphabetical contracts to emit GAS. To vote for a new list of side one of the alphabetical contracts to emit GAS. To vote for a new list of side
chain committee, alphabet nodes of Inner Ring create multisignature transactions chain committee, alphabet nodes of the Inner Ring create multisignature transactions
for each alphabet contract. for each alphabet contract.
Contract notifications Contract notifications

View file

@ -19,8 +19,8 @@ type (
} }
) )
// Audit key is a combination of epoch, container ID and public key of node that // Audit key is a combination of the epoch, the container ID and the public key of the node that
// executed audit. Together it should be no more than 64 bytes. We can't shrink // 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 // epoch and container ID since we iterate over these values. But we can shrink
// public key by using first bytes of the hashed value. // public key by using first bytes of the hashed value.
@ -70,7 +70,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("audit contract initialized") runtime.Log("audit contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -82,11 +82,11 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("audit contract updated") runtime.Log("audit contract updated")
} }
// Put method stores stable marshalled `DataAuditResult` structure. Can be // Put method stores a stable marshalled `DataAuditResult` structure. It can be
// invoked only by Inner Ring nodes. // invoked only by Inner Ring nodes.
// //
// Inner Ring nodes perform audit of the containers and produce `DataAuditResult` // Inner Ring nodes perform audit of containers and produce `DataAuditResult`
// structures. They are being stored in audit contract and used for settlements // structures. They are stored in audit contract and used for settlements
// in later epochs. // in later epochs.
func Put(rawAuditResult []byte) { func Put(rawAuditResult []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -122,16 +122,16 @@ func Put(rawAuditResult []byte) {
runtime.Log("audit: result has been saved") runtime.Log("audit: result has been saved")
} }
// Get method returns stable marshaled DataAuditResult structure. // Get method returns a stable marshaled DataAuditResult structure.
// //
// ID of the DataAuditResult can be obtained from listing methods. // The ID of the DataAuditResult can be obtained from listing methods.
func Get(id []byte) []byte { func Get(id []byte) []byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return storage.Get(ctx, id).([]byte) return storage.Get(ctx, id).([]byte)
} }
// List method returns list of all available DataAuditResult IDs from // List method returns a list of all available DataAuditResult IDs from
// contract storage. // the contract storage.
func List() [][]byte { func List() [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
it := storage.Find(ctx, []byte{}, storage.KeysOnly) it := storage.Find(ctx, []byte{}, storage.KeysOnly)
@ -139,8 +139,8 @@ func List() [][]byte {
return list(it) return list(it)
} }
// ListByEpoch method returns list of DataAuditResult IDs generated in // ListByEpoch method returns a list of DataAuditResult IDs generated during
// specified epoch. // the specified epoch.
func ListByEpoch(epoch int) [][]byte { func ListByEpoch(epoch int) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
var buf interface{} = epoch var buf interface{} = epoch
@ -149,8 +149,8 @@ func ListByEpoch(epoch int) [][]byte {
return list(it) return list(it)
} }
// ListByCID method returns list of DataAuditResult IDs generated in // ListByCID method returns a list of DataAuditResult IDs generated during
// specified epoch for specified container. // the specified epoch for the specified container.
func ListByCID(epoch int, cid []byte) [][]byte { func ListByCID(epoch int, cid []byte) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -162,8 +162,8 @@ func ListByCID(epoch int, cid []byte) [][]byte {
return list(it) return list(it)
} }
// ListByNode method returns list of DataAuditResult IDs generated in // ListByNode method returns a list of DataAuditResult IDs generated in
// specified epoch for specified container by specified Inner Ring node. // the specified epoch for the specified container by the specified Inner Ring node.
func ListByNode(epoch int, cid []byte, key interop.PublicKey) [][]byte { func ListByNode(epoch int, cid []byte, key interop.PublicKey) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
hdr := auditHeader{ hdr := auditHeader{
@ -200,12 +200,12 @@ loop:
return result return result
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }
// readNext reads length from first byte and then reads data (max 127 bytes). // readNext reads the length from the first byte, and then reads data (max 127 bytes).
func readNext(input []byte) ([]byte, int) { func readNext(input []byte) ([]byte, int) {
var buf interface{} = input[0] var buf interface{} = input[0]
ln := buf.(int) ln := buf.(int)

View file

@ -1,22 +1,22 @@
/* /*
Audit contract is a contract deployed in NeoFS side chain. Audit contract is a contract deployed in NeoFS sidechain.
Inner Ring nodes perform an audit of the registered containers in every epoch. Inner Ring nodes perform audit of the registered containers during every epoch.
If container contains StorageGroup objects, then the Inner Ring node initializes 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 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 node creates a DataAuditResult structure for the container. The content of this
structure makes it possible to determine which storage nodes were examined and structure makes it possible to determine which storage nodes have been examined and
the status of these checks. Based on this information, container owner is see the status of these checks. Regarding this information, the container owner is
charged for data storage. charged for data storage.
Audit contract is used as reliable and verifiable storage for all Audit contract is used as a reliable and verifiable storage for all
DataAuditResult structures. At the end of the data audit routine, the Inner Ring DataAuditResult structures. At the end of data audit routine, Inner Ring
nodes send a stable marshaled version of the DataAuditResult structure to the nodes send a stable marshaled version of the DataAuditResult structure to the
contract. When Alphabet nodes of the Inner Ring perform settlement operations, contract. When Alphabet nodes of the Inner Ring perform settlement operations,
they list and get these AuditResultStructures from the audit contract. they make a list and get these AuditResultStructures from the audit contract.
Contract notifications Contract notifications
Alphabet contract does not produce notifications to process. Audit contract does not produce notifications to process.
*/ */
package audit package audit

View file

@ -24,7 +24,7 @@ type (
// Account structure stores metadata of each NeoFS balance account. // Account structure stores metadata of each NeoFS balance account.
Account struct { Account struct {
// Active balance // Active balance
Balance int Balance int
// Until valid for lock accounts // Until valid for lock accounts
Until int Until int
@ -89,7 +89,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("balance contract initialized") runtime.Log("balance contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -113,13 +113,13 @@ func Decimals() int {
} }
// TotalSupply is a NEP-17 standard method that returns total amount of main // TotalSupply is a NEP-17 standard method that returns total amount of main
// chain GAS in the NeoFS network. // chain GAS in NeoFS network.
func TotalSupply() int { func TotalSupply() int {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return token.getSupply(ctx) return token.getSupply(ctx)
} }
// BalanceOf is a NEP-17 standard method that returns NeoFS balance of specified // BalanceOf is a NEP-17 standard method that returns NeoFS balance of the specified
// account. // account.
func BalanceOf(account interop.Hash160) int { func BalanceOf(account interop.Hash160) int {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -127,23 +127,23 @@ func BalanceOf(account interop.Hash160) int {
} }
// Transfer is a NEP-17 standard method that transfers NeoFS balance from one // Transfer is a NEP-17 standard method that transfers NeoFS balance from one
// account to other. Can be invoked only by account owner. // account to another. It can be invoked only by the account owner.
// //
// Produces Transfer and TransferX notifications. TransferX notification // It produces Transfer and TransferX notifications. TransferX notification
// will have empty details field. // will have empty details field.
func Transfer(from, to interop.Hash160, amount int, data interface{}) bool { func Transfer(from, to interop.Hash160, amount int, data interface{}) bool {
ctx := storage.GetContext() ctx := storage.GetContext()
return token.transfer(ctx, from, to, amount, false, nil) return token.transfer(ctx, from, to, amount, false, nil)
} }
// TransferX is a method for NeoFS balance transfers from one account to // TransferX is a method for NeoFS balance to be transferred from one account to
// another. Can be invoked by account owner or by Alphabet nodes. // another. It can be invoked by the account owner or by Alphabet nodes.
// //
// Produces Transfer and TransferX notifications. // It produces Transfer and TransferX notifications.
// //
// TransferX method expands Transfer method by having extra details argument. // TransferX method expands Transfer method by having extra details argument.
// Also TransferX method allows to transfer assets by Alphabet nodes of the // TransferX method also allows to transfer assets by Alphabet nodes of the
// Inner Ring with multi signature. // Inner Ring with multisignature.
func TransferX(from, to interop.Hash160, amount int, details []byte) { func TransferX(from, to interop.Hash160, amount int, details []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -191,14 +191,14 @@ func TransferX(from, to interop.Hash160, amount int, details []byte) {
runtime.Log("successfully transferred assets") runtime.Log("successfully transferred assets")
} }
// Lock is a method that transfers assets from user account to lock account // Lock is a method that transfers assets from a user account to the lock account
// related to the user. Can be invoked only by Alphabet nodes of the Inner Ring. // related to the user. It can be invoked only by Alphabet nodes of the Inner Ring.
// //
// Produces Lock, Transfer and TransferX notifications. // It produces Lock, Transfer and TransferX notifications.
// //
// Lock method invoked by Alphabet nodes of the Inner Ring when they process // Lock method is invoked by Alphabet nodes of the Inner Ring when they process
// Withdraw notification from NeoFS contract. This should transfer assets // Withdraw notification from NeoFS contract. This should transfer assets
// to new lock account that won't be used for anything besides Unlock and Burn. // to a new lock account that won't be used for anything beside Unlock and Burn.
func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) { func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -251,11 +251,11 @@ func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) {
runtime.Notify("Lock", txDetails, from, to, amount, until) runtime.Notify("Lock", txDetails, from, to, amount, until)
} }
// NewEpoch is a method that checks timeout on lock accounts and return assets // NewEpoch is a method that checks timeout on lock accounts and returns assets
// if lock is not available anymore. Can be invoked only by NewEpoch method // if lock is not available anymore. It can be invoked only by NewEpoch method
// of Netmap contract. // of Netmap contract.
// //
// Produces Transfer and TransferX notifications. // It produces Transfer and TransferX notifications.
func NewEpoch(epochNum int) { func NewEpoch(epochNum int) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -294,14 +294,14 @@ func NewEpoch(epochNum int) {
} }
} }
// Mint is a method that transfers assets to user account from empty account. // Mint is a method that transfers assets to a user account from an empty account.
// Can be invoked only by Alphabet nodes of the Inner Ring. // It can be invoked only by Alphabet nodes of the Inner Ring.
// //
// Produces Mint, Transfer and TransferX notifications. // It produces Mint, Transfer and TransferX notifications.
// //
// Mint method invoked by Alphabet nodes of the Inner Ring when they process // Mint method is invoked by Alphabet nodes of the Inner Ring when they process
// Deposit notification from NeoFS contract. Before that Alphabet nodes should // Deposit notification from NeoFS contract. Before that, Alphabet nodes should
// synchronize precision of main chain GAS contract and Balance contract. // synchronize precision of mainchain GAS contract and Balance contract.
// Mint increases total supply of NEP-17 compatible NeoFS token. // Mint increases total supply of NEP-17 compatible NeoFS token.
func Mint(to interop.Hash160, amount int, txDetails []byte) { func Mint(to interop.Hash160, amount int, txDetails []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -349,15 +349,15 @@ func Mint(to interop.Hash160, amount int, txDetails []byte) {
runtime.Notify("Mint", to, amount) runtime.Notify("Mint", to, amount)
} }
// Burn is a method that transfers assets from user account to empty account. // Burn is a method that transfers assets from a user account to an empty account.
// Can be invoked only by Alphabet nodes of the Inner Ring. // It can be invoked only by Alphabet nodes of the Inner Ring.
// //
// Produces Burn, Transfer and TransferX notifications. // It produces Burn, Transfer and TransferX notifications.
// //
// Burn method invoked by Alphabet nodes of the Inner Ring when they process // Burn method is invoked by Alphabet nodes of the Inner Ring when they process
// Cheque notification from NeoFS contract. It means that locked assets were // Cheque notification from NeoFS contract. It means that locked assets have been
// transferred to user in main chain, therefore lock account should be destroyed. // transferred to the user in the mainchain, therefore the lock account should be destroyed.
// Before that Alphabet nodes should synchronize precision of main chain GAS // Before that, Alphabet nodes should synchronize precision of mainchain GAS
// contract and Balance contract. Burn decreases total supply of NEP-17 // contract and Balance contract. Burn decreases total supply of NEP-17
// compatible NeoFS token. // compatible NeoFS token.
func Burn(from interop.Hash160, amount int, txDetails []byte) { func Burn(from interop.Hash160, amount int, txDetails []byte) {
@ -410,7 +410,7 @@ func Burn(from interop.Hash160, amount int, txDetails []byte) {
runtime.Notify("Burn", from, amount) runtime.Notify("Burn", from, amount)
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }
@ -484,7 +484,7 @@ func (t Token) canTransfer(ctx storage.Context, from, to interop.Hash160, amount
return amountFrom, true return amountFrom, true
} }
// isUsableAddress checks if the sender is either the correct NEO address or SC address. // isUsableAddress checks if the sender is either a correct NEO address or SC address.
func isUsableAddress(addr interop.Hash160) bool { func isUsableAddress(addr interop.Hash160) bool {
if len(addr) == 20 { if len(addr) == 20 {
if runtime.CheckWitness(addr) { if runtime.CheckWitness(addr) {

View file

@ -1,23 +1,23 @@
/* /*
Balance contract is a contract deployed in NeoFS side chain. Balance contract is a contract deployed in NeoFS sidechain.
Balance contract stores all NeoFS account balances. It is NEP-17 compatible Balance contract stores all NeoFS account balances. It is a NEP-17 compatible
contract so in can be tracked and controlled by N3 compatible network contract, so it can be tracked and controlled by N3 compatible network
monitors and wallet software. monitors and wallet software.
This contract is used to store all micro transactions in the sidechain, such as This contract is used to store all micro transactions in the sidechain, such as
data audit settlements or container fee payments. It is inefficient to make such data audit settlements or container fee payments. It is inefficient to make such
small payment transactions in main chain. To process small transfers, balance small payment transactions in the mainchain. To process small transfers, balance
contract has higher (12) decimal precision than native GAS contract. contract has higher (12) decimal precision than native GAS contract.
NeoFS balances are synchronized with main chain operations. Deposit produce NeoFS balances are synchronized with mainchain operations. Deposit produces
minting of NEOFS tokens in Balance contract. Withdraw locks some NEOFS tokens minting of NEOFS tokens in Balance contract. Withdraw locks some NEOFS tokens
in special lock account. When NeoFS contract transfers GAS assets back to the in a special lock account. When NeoFS contract transfers GAS assets back to the
user, lock account is destroyed with burn operation. user, the lock account is destroyed with burn operation.
Contract notifications Contract notifications
Transfer notification. This is NEP-17 standard notification. Transfer notification. This is a NEP-17 standard notification.
Transfer: Transfer:
- name: from - name: from
@ -27,7 +27,7 @@ Transfer notification. This is NEP-17 standard notification.
- name: amount - name: amount
type: Integer type: Integer
TransferX notification. This is enhanced transfer notification with details. TransferX notification. This is an enhanced transfer notification with details.
TransferX: TransferX:
- name: from - name: from
@ -39,11 +39,11 @@ TransferX notification. This is enhanced transfer notification with details.
- name: details - name: details
type: ByteArray type: ByteArray
Lock notification. This notification is produced when Lock account has been Lock notification. This notification is produced when a lock account is
created. It contains information about main chain transaction that produced created. It contains information about the mainchain transaction that has produced
asset lock, address of lock account and NeoFS epoch number until lock account the asset lock, the address of the lock account and the NeoFS epoch number until which the
is valid. Alphabet nodes of the Inner Ring catch notification and initialize lock account is valid. Alphabet nodes of the Inner Ring catch notification and initialize
Cheque method invocation of the NeoFS contract. Cheque method invocation of NeoFS contract.
Lock: Lock:
- name: txID - name: txID
@ -58,7 +58,7 @@ Cheque method invocation of the NeoFS contract.
type: Integer type: Integer
Mint notification. This notification is produced when user balance is Mint notification. This notification is produced when user balance is
replenished from deposit in the main chain. replenished from deposit in the mainchain.
Mint: Mint:
- name: to - name: to
@ -68,7 +68,7 @@ replenished from deposit in the main chain.
Burn notification. This notification is produced after user balance is reduced Burn notification. This notification is produced after user balance is reduced
when NeoFS contract transferred GAS assets back to the user. when NeoFS contract has transferred GAS assets back to the user.
Burn: Burn:
- name: from - name: from

View file

@ -15,7 +15,7 @@ type IRNode struct {
const irListMethod = "innerRingList" const irListMethod = "innerRingList"
// InnerRingInvoker returns public key of inner ring node that invoked contract. // InnerRingInvoker returns the public key of the inner ring node that has invoked the contract.
// Work around for environments without notary support. // Work around for environments without notary support.
func InnerRingInvoker(ir []interop.PublicKey) interop.PublicKey { func InnerRingInvoker(ir []interop.PublicKey) interop.PublicKey {
for i := 0; i < len(ir); i++ { for i := 0; i < len(ir); i++ {
@ -28,14 +28,14 @@ func InnerRingInvoker(ir []interop.PublicKey) interop.PublicKey {
return nil return nil
} }
// InnerRingNodes return list of inner ring nodes from state validator role // InnerRingNodes return a list of inner ring nodes from state validator role
// in side chain. // in the sidechain.
func InnerRingNodes() []interop.PublicKey { func InnerRingNodes() []interop.PublicKey {
blockHeight := ledger.CurrentIndex() blockHeight := ledger.CurrentIndex()
return roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1)) return roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1))
} }
// InnerRingNodesFromNetmap gets list of inner ring through // InnerRingNodesFromNetmap gets a list of inner ring nodes through
// calling "innerRingList" method of smart contract. // calling "innerRingList" method of smart contract.
// Work around for environments without notary support. // Work around for environments without notary support.
func InnerRingNodesFromNetmap(sc interop.Hash160) []interop.PublicKey { func InnerRingNodesFromNetmap(sc interop.Hash160) []interop.PublicKey {
@ -47,7 +47,7 @@ func InnerRingNodesFromNetmap(sc interop.Hash160) []interop.PublicKey {
return pubs return pubs
} }
// AlphabetNodes return list of alphabet nodes from committee in side chain. // AlphabetNodes returns a list of alphabet nodes from committee in the sidechain.
func AlphabetNodes() []interop.PublicKey { func AlphabetNodes() []interop.PublicKey {
return neo.GetCommittee() return neo.GetCommittee()
} }
@ -64,8 +64,8 @@ func CommitteeAddress() []byte {
return Multiaddress(committee, true) return Multiaddress(committee, true)
} }
// Multiaddress returns default multi signature account address for N keys. // Multiaddress returns default multisignature account address for N keys.
// If committee set to true, then it is `M = N/2+1` committee account. // If committee set to true, it is `M = N/2+1` committee account.
func Multiaddress(n []interop.PublicKey, committee bool) []byte { func Multiaddress(n []interop.PublicKey, committee bool) []byte {
threshold := len(n)*2/3 + 1 threshold := len(n)*2/3 + 1
if committee { if committee {

View file

@ -39,7 +39,7 @@ func ContainerFeeTransferDetails(cid []byte) []byte {
return append(containerFeePrefix, cid...) return append(containerFeePrefix, cid...)
} }
// AbortWithMessage calls `runtime.Log` with passed message // AbortWithMessage calls `runtime.Log` with the passed message
// and calls `ABORT` opcode. // and calls `ABORT` opcode.
func AbortWithMessage(msg string) { func AbortWithMessage(msg string) {
runtime.Log(msg) runtime.Log(msg)

View file

@ -13,7 +13,7 @@ type Ballot struct {
// ID of the voting decision. // ID of the voting decision.
ID []byte ID []byte
// Public keys of already voted inner ring nodes. // Public keys of the already voted inner ring nodes.
Voters []interop.PublicKey Voters []interop.PublicKey
// Height of block with the last vote. // Height of block with the last vote.
@ -28,8 +28,8 @@ func InitVote(ctx storage.Context) {
SetSerialized(ctx, voteKey, []Ballot{}) SetSerialized(ctx, voteKey, []Ballot{})
} }
// Vote adds ballot for the decision with specific 'id' and returns amount // Vote adds ballot for the decision with a specific 'id' and returns the amount
// on unique voters for that decision. // of unique voters for that decision.
func Vote(ctx storage.Context, id, from []byte) int { func Vote(ctx storage.Context, id, from []byte) int {
var ( var (
newCandidates []Ballot newCandidates []Ballot
@ -96,7 +96,7 @@ func RemoveVotes(ctx storage.Context, id []byte) {
SetSerialized(ctx, voteKey, candidates) SetSerialized(ctx, voteKey, candidates)
} }
// getBallots returns deserialized slice of vote ballots. // getBallots returns a deserialized slice of vote ballots.
func getBallots(ctx storage.Context) []Ballot { func getBallots(ctx storage.Context) []Ballot {
data := storage.Get(ctx, voteKey) data := storage.Get(ctx, voteKey)
if data != nil { if data != nil {
@ -106,13 +106,13 @@ func getBallots(ctx storage.Context) []Ballot {
return []Ballot{} return []Ballot{}
} }
// BytesEqual compares two slice of bytes by wrapping them into strings, // BytesEqual compares two slices of bytes by wrapping them into strings,
// which is necessary with new util.Equal interop behaviour, see neo-go#1176. // which is necessary with new util.Equals interop behaviour, see neo-go#1176.
func BytesEqual(a []byte, b []byte) bool { func BytesEqual(a []byte, b []byte) bool {
return util.Equals(string(a), string(b)) return util.Equals(string(a), string(b))
} }
// InvokeID returns hashed value of prefix and args concatenation. Used to // InvokeID returns hashed value of prefix and args concatenation. Iy is used to
// identify different ballots. // identify different ballots.
func InvokeID(args []interface{}, prefix []byte) []byte { func InvokeID(args []interface{}, prefix []byte) []byte {
for i := range args { for i := range args {
@ -124,22 +124,22 @@ func InvokeID(args []interface{}, prefix []byte) []byte {
} }
/* /*
Check if invocation made from known container or audit contracts. Check if the invocation is made from known container or audit contracts.
This is necessary because calls from these contracts require to do transfer This is necessary because calls from these contracts require to do transfer
without signature collection (1 invoke transfer). without signature collection (1 invoke transfer).
IR1, IR2, IR3, IR4 -(4 invokes)-> [ Container Contract ] -(1 invoke)-> [ Balance Contract ] IR1, IR2, IR3, IR4 -(4 invokes)-> [ Container Contract ] -(1 invoke)-> [ Balance Contract ]
We can do 1 invoke transfer if: We can do 1 invoke transfer if:
- invoke happened from inner ring node, - invokation has happened from inner ring node,
- it is indirect invocation from other smart-contract. - it is indirect invocation from another smart-contract.
However there is a possible attack, when malicious inner ring node creates However, there is a possible attack, when a malicious inner ring node creates
malicious smart-contract in morph chain to do indirect call. a malicious smart-contract in the morph chain to do indirect call.
MaliciousIR -(1 invoke)-> [ Malicious Contract ] -(1 invoke) -> [ Balance Contract ] MaliciousIR -(1 invoke)-> [ Malicious Contract ] -(1 invoke)-> [ Balance Contract ]
To prevent that, we have to allow 1 invoke transfer from authorised well known To prevent that, we have to allow 1 invoke transfer from authorised well-known
smart-contracts, that will be set up at `Init` method. smart-contracts, that will be set up at `Init` method.
*/ */

View file

@ -3,31 +3,31 @@ package common
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime" import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
var ( var (
// ErrAlphabetWitnessFailed appears when method must be // ErrAlphabetWitnessFailed appears when the method must be
// called by Alphabet but was not. // called by the Alphabet but was not.
ErrAlphabetWitnessFailed = "alphabet witness check failed" ErrAlphabetWitnessFailed = "alphabet witness check failed"
// ErrOwnerWitnessFailed appears when method must be called // ErrOwnerWitnessFailed appears when the method must be called
// by owner of some assets but was not. // by an owner of some assets but was not.
ErrOwnerWitnessFailed = "owner witness check failed" ErrOwnerWitnessFailed = "owner witness check failed"
// ErrWitnessFailed appears when method must be called // ErrWitnessFailed appears when the method must be called
// using certain public key but was not. // using certain public key but was not.
ErrWitnessFailed = "witness check failed" ErrWitnessFailed = "witness check failed"
) )
// CheckAlphabetWitness checks witness of the passed caller. // CheckAlphabetWitness checks witness of the passed caller.
// Panics with ErrAlphabetWitnessFailed message on fail. // It panics with ErrAlphabetWitnessFailed message on fail.
func CheckAlphabetWitness(caller []byte) { func CheckAlphabetWitness(caller []byte) {
checkWitnessWithPanic(caller, ErrAlphabetWitnessFailed) checkWitnessWithPanic(caller, ErrAlphabetWitnessFailed)
} }
// CheckOwnerWitness checks witness of the passed caller. // CheckOwnerWitness checks witness of the passed caller.
// Panics with ErrOwnerWitnessFailed message on fail. // It panics with ErrOwnerWitnessFailed message on fail.
func CheckOwnerWitness(caller []byte) { func CheckOwnerWitness(caller []byte) {
checkWitnessWithPanic(caller, ErrOwnerWitnessFailed) checkWitnessWithPanic(caller, ErrOwnerWitnessFailed)
} }
// CheckWitness checks witness of the passed caller. // CheckWitness checks witness of the passed caller.
// Panics with ErrWitnessFailed message on fail. // It panics with ErrWitnessFailed message on fail.
func CheckWitness(caller []byte) { func CheckWitness(caller []byte) {
checkWitnessWithPanic(caller, ErrWitnessFailed) checkWitnessWithPanic(caller, ErrWitnessFailed)
} }

View file

@ -63,11 +63,11 @@ const (
singleEstimatePrefix = "est" singleEstimatePrefix = "est"
estimateKeyPrefix = "cnr" estimateKeyPrefix = "cnr"
estimatePostfixSize = 10 estimatePostfixSize = 10
// CleanupDelta contains number of last epochs for which container estimations are present. // CleanupDelta contains the number of the last epochs for which container estimations are present.
CleanupDelta = 3 CleanupDelta = 3
// TotalCleanupDelta contains number of epochs after which estimation // TotalCleanupDelta contains the number of the epochs after which estimation
// will be removed by epoch tick cleanup if any node didn't updated // will be removed by epoch tick cleanup if any of the nodes hasn't updated
// container size and/or container was removed. Must be greater than CleanupDelta. // container size and/or container has been removed. It must be greater than CleanupDelta.
TotalCleanupDelta = CleanupDelta + 1 TotalCleanupDelta = CleanupDelta + 1
// NotFoundError is returned if container is missing. // NotFoundError is returned if container is missing.
@ -84,7 +84,7 @@ var (
eACLPrefix = []byte("eACL") eACLPrefix = []byte("eACL")
) )
// OnNEP11Payment is needed for registration with contract as owner to work. // OnNEP11Payment is needed for registration with contract as the owner to work.
func OnNEP11Payment(a interop.Hash160, b int, c []byte, d interface{}) { func OnNEP11Payment(a interop.Hash160, b int, c []byte, d interface{}) {
} }
@ -145,8 +145,8 @@ func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) {
} }
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // by committee only.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
panic("only committee can update contract") panic("only committee can update contract")
@ -157,13 +157,13 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("container contract updated") runtime.Log("container contract updated")
} }
// Put method creates new container if it was invoked by Alphabet nodes // Put method creates a new container if it has been invoked by Alphabet nodes
// of the Inner Ring. Otherwise it produces containerPut notification. // of the Inner Ring. Otherwise, it produces containerPut notification.
// //
// Container should be stable marshaled Container structure from API. // Container should be a stable marshaled Container structure from API.
// Signature is a RFC6979 signature of Container. // Signature is a RFC6979 signature of the Container.
// PublicKey contains public key of the signer. // PublicKey contains the public key of the signer.
// Token is optional and should be stable marshaled SessionToken structure from // Token is optional and should be a stable marshaled SessionToken structure from
// API. // API.
func Put(container []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) { func Put(container []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) {
PutNamed(container, signature, publicKey, token, "", "") PutNamed(container, signature, publicKey, token, "", "")
@ -279,7 +279,7 @@ func PutNamed(container []byte, signature interop.Signature,
runtime.Notify("PutSuccess", containerID, publicKey) runtime.Notify("PutSuccess", containerID, publicKey)
} }
// checkNiceNameAvailable checks if nice name is available for the container. // checkNiceNameAvailable checks if the nice name is available for the container.
// It panics if the name is taken. Returned value specifies if new domain registration is needed. // It panics if the name is taken. Returned value specifies if new domain registration is needed.
func checkNiceNameAvailable(nnsContractAddr interop.Hash160, domain string) bool { func checkNiceNameAvailable(nnsContractAddr interop.Hash160, domain string) bool {
isAvail := contract.Call(nnsContractAddr, "isAvailable", isAvail := contract.Call(nnsContractAddr, "isAvailable",
@ -303,15 +303,15 @@ func checkNiceNameAvailable(nnsContractAddr interop.Hash160, domain string) bool
return false return false
} }
// Delete method removes container from contract storage if it was // Delete method removes a container from the contract storage if it has been
// invoked by Alphabet nodes of the Inner Ring. Otherwise it produces // invoked by Alphabet nodes of the Inner Ring. Otherwise, it produces
// containerDelete notification. // containerDelete notification.
// //
// Signature is a RFC6979 signature of container ID. // Signature is a RFC6979 signature of the container ID.
// Token is optional and should be stable marshaled SessionToken structure from // Token is optional and should be a stable marshaled SessionToken structure from
// API. // API.
// //
// If a container doesn't exist it panics with NotFoundError. // If the container doesn't exist, it panics with NotFoundError.
func Delete(containerID []byte, signature interop.Signature, token []byte) { func Delete(containerID []byte, signature interop.Signature, token []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -348,8 +348,8 @@ func Delete(containerID []byte, signature interop.Signature, token []byte) {
if len(domain) != 0 { if len(domain) != 0 {
storage.Delete(ctx, key) storage.Delete(ctx, key)
// We should do `getRecord` first because NNS record could be deleted // We should do `getRecord` first because NNS record could be deleted
// by other means (expiration, manual) thus leading to failing `deleteRecord` // by other means (expiration, manual), thus leading to failing `deleteRecord`
// and inability to delete container. We should also check that we own the record in case. // and inability to delete a container. We should also check if we own the record in case.
nnsContractAddr := storage.Get(ctx, nnsContractKey).(interop.Hash160) nnsContractAddr := storage.Get(ctx, nnsContractKey).(interop.Hash160)
res := contract.Call(nnsContractAddr, "getRecords", contract.ReadStates|contract.AllowCall, domain, 16 /* TXT */) res := contract.Call(nnsContractAddr, "getRecords", contract.ReadStates|contract.AllowCall, domain, 16 /* TXT */)
if res != nil && std.Base58Encode(containerID) == string(res.([]interface{})[0].(string)) { if res != nil && std.Base58Encode(containerID) == string(res.([]interface{})[0].(string)) {
@ -361,11 +361,11 @@ func Delete(containerID []byte, signature interop.Signature, token []byte) {
runtime.Notify("DeleteSuccess", containerID) runtime.Notify("DeleteSuccess", containerID)
} }
// Get method returns structure that contains stable marshaled Container structure, // Get method returns a structure that contains a stable marshaled Container structure,
// signature, public key of the container creator and stable marshaled SessionToken // the signature, the public key of the container creator and a stable marshaled SessionToken
// structure if it was provided. // structure if it was provided.
// //
// If a container doesn't exist it panics with NotFoundError. // If the container doesn't exist, it panics with NotFoundError.
func Get(containerID []byte) Container { func Get(containerID []byte) Container {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
cnt := getContainer(ctx, containerID) cnt := getContainer(ctx, containerID)
@ -375,9 +375,9 @@ func Get(containerID []byte) Container {
return cnt return cnt
} }
// Owner method returns 25 byte Owner ID of the container. // Owner method returns a 25 byte Owner ID of the container.
// //
// If a container doesn't exist it panics with NotFoundError. // If the container doesn't exist, it panics with NotFoundError.
func Owner(containerID []byte) []byte { func Owner(containerID []byte) []byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
owner := getOwnerByID(ctx, containerID) owner := getOwnerByID(ctx, containerID)
@ -387,7 +387,7 @@ func Owner(containerID []byte) []byte {
return owner return owner
} }
// List method returns list of all container IDs owned by specified owner. // List method returns a list of all container IDs owned by the specified owner.
func List(owner []byte) [][]byte { func List(owner []byte) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -406,17 +406,17 @@ func List(owner []byte) [][]byte {
return list return list
} }
// SetEACL method sets new extended ACL table related to the contract // SetEACL method sets a new extended ACL table related to the contract
// if it was invoked by Alphabet nodes of the Inner Ring. Otherwise it produces // if it was invoked by Alphabet nodes of the Inner Ring. Otherwise, it produces
// setEACL notification. // setEACL notification.
// //
// EACL should be stable marshaled EACLTable structure from API. // EACL should be a stable marshaled EACLTable structure from API.
// Signature is a RFC6979 signature of Container. // Signature is a RFC6979 signature of the Container.
// PublicKey contains public key of the signer. // PublicKey contains the public key of the signer.
// Token is optional and should be stable marshaled SessionToken structure from // Token is optional and should be a stable marshaled SessionToken structure from
// API. // API.
// //
// If a container doesn't exist it panics with NotFoundError. // If the container doesn't exist, it panics with NotFoundError.
func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) { func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -469,11 +469,11 @@ func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicK
runtime.Notify("SetEACLSuccess", containerID, publicKey) runtime.Notify("SetEACLSuccess", containerID, publicKey)
} }
// EACL method returns structure that contains stable marshaled EACLTable structure, // EACL method returns a structure that contains a stable marshaled EACLTable structure,
// signature, public key of the extended ACL setter and stable marshaled SessionToken // the signature, the public key of the extended ACL setter and a stable marshaled SessionToken
// structure if it was provided. // structure if it was provided.
// //
// If a container doesn't exist it panics with NotFoundError. // If the container doesn't exist, it panics with NotFoundError.
func EACL(containerID []byte) ExtendedACL { func EACL(containerID []byte) ExtendedACL {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -486,10 +486,10 @@ func EACL(containerID []byte) ExtendedACL {
} }
// PutContainerSize method saves container size estimation in contract // PutContainerSize method saves container size estimation in contract
// memory. Can be invoked only by Storage nodes from the network map. Method // memory. It can be invoked only by Storage nodes from the network map. This method
// checks witness based on the provided public key of the Storage node. // checks witness based on the provided public key of the Storage node.
// //
// If a container doesn't exist it panics with NotFoundError. // If the container doesn't exist, it panics with NotFoundError.
func PutContainerSize(epoch int, cid []byte, usedSize int, pubKey interop.PublicKey) { func PutContainerSize(epoch int, cid []byte, usedSize int, pubKey interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -516,13 +516,13 @@ func PutContainerSize(epoch int, cid []byte, usedSize int, pubKey interop.Public
runtime.Log("saved container size estimation") runtime.Log("saved container size estimation")
} }
// GetContainerSize method returns container ID and slice of container // GetContainerSize method returns the container ID and a slice of container
// estimations. Container estimation includes public key of the Storage Node // estimations. Container estimation includes the public key of the Storage Node
// that registered estimation and value of estimation. // that registered estimation and value of estimation.
// //
// Use ID obtained from ListContainerSizes method. Estimations are removed // Use the ID obtained from ListContainerSizes method. Estimations are removed
// from contract storage every epoch, see NewEpoch method, therefore method // from contract storage every epoch, see NewEpoch method; therefore, this method
// can return different results in different epochs. // can return different results during different epochs.
func GetContainerSize(id []byte) containerSizes { func GetContainerSize(id []byte) containerSizes {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -535,8 +535,8 @@ func GetContainerSize(id []byte) containerSizes {
return getContainerSizeEstimation(ctx, id, cid) return getContainerSizeEstimation(ctx, id, cid)
} }
// ListContainerSizes method returns IDs of container size estimations // ListContainerSizes method returns the IDs of container size estimations
// that has been registered for specified epoch. // that has been registered for the specified epoch.
func ListContainerSizes(epoch int) [][]byte { func ListContainerSizes(epoch int) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -568,7 +568,7 @@ func ListContainerSizes(epoch int) [][]byte {
} }
// NewEpoch method removes all container size estimations from epoch older than // NewEpoch method removes all container size estimations from epoch older than
// epochNum + 3. Can be invoked only by NewEpoch method of the Netmap contract. // epochNum + 3. It can be invoked only by NewEpoch method of the Netmap contract.
func NewEpoch(epochNum int) { func NewEpoch(epochNum int) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -591,7 +591,7 @@ func NewEpoch(epochNum int) {
} }
// StartContainerEstimation method produces StartEstimation notification. // StartContainerEstimation method produces StartEstimation notification.
// Can be invoked only by Alphabet nodes of the Inner Ring. // It can be invoked only by Alphabet nodes of the Inner Ring.
func StartContainerEstimation(epoch int) { func StartContainerEstimation(epoch int) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -629,7 +629,7 @@ func StartContainerEstimation(epoch int) {
} }
// StopContainerEstimation method produces StopEstimation notification. // StopContainerEstimation method produces StopEstimation notification.
// Can be invoked only by Alphabet nodes of the Inner Ring. // It can be invoked only by Alphabet nodes of the Inner Ring.
func StopContainerEstimation(epoch int) { func StopContainerEstimation(epoch int) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -666,7 +666,7 @@ func StopContainerEstimation(epoch int) {
runtime.Log("notification has been produced") runtime.Log("notification has been produced")
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }
@ -763,7 +763,7 @@ func getContainerSizeEstimation(ctx storage.Context, key, cid []byte) containerS
} }
// isStorageNode looks into _previous_ epoch network map, because storage node // isStorageNode looks into _previous_ epoch network map, because storage node
// announce container size estimation of previous epoch. // announces container size estimation of the previous epoch.
func isStorageNode(ctx storage.Context, key interop.PublicKey) bool { func isStorageNode(ctx storage.Context, key interop.PublicKey) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).(interop.Hash160) netmapContractAddr := storage.Get(ctx, netmapContractKey).(interop.Hash160)
snapshot := contract.Call(netmapContractAddr, "snapshot", contract.ReadOnly, 1).([]storageNode) snapshot := contract.Call(netmapContractAddr, "snapshot", contract.ReadOnly, 1).([]storageNode)

View file

@ -1,17 +1,17 @@
/* /*
Container contract is a contract deployed in NeoFS side chain. Container contract is a contract deployed in NeoFS sidechain.
Container contract stores and manages containers, extended ACLs and container Container contract stores and manages containers, extended ACLs and container
size estimations. Contract does not perform sanity or signature checks of the size estimations. Contract does not perform sanity or signature checks of
containers or extended ACLs, it is done by Alphabet nodes of the Inner Ring. containers or extended ACLs, it is done by Alphabet nodes of the Inner Ring.
Alphabet nodes approve it by invoking the same Put or SetEACL methods with Alphabet nodes approve it by invoking the same Put or SetEACL methods with
the same arguments. the same arguments.
Contract notifications Contract notifications
containerPut notification. This notification is produced when user wants to containerPut notification. This notification is produced when a user wants to
create new container. Alphabet nodes of the Inner Ring catch notification and create a new container. Alphabet nodes of the Inner Ring catch the notification and
validate container data, signature and token if it is present. validate container data, signature and token if present.
containerPut: containerPut:
- name: container - name: container
@ -23,9 +23,9 @@ validate container data, signature and token if it is present.
- name: token - name: token
type: ByteArray type: ByteArray
containerDelete notification. This notification is produced when container owner containerDelete notification. This notification is produced when a container owner
wants to delete container. Alphabet nodes of the Inner Ring catch notification wants to delete a container. Alphabet nodes of the Inner Ring catch the notification
and validate container ownership, signature and token if it is present. and validate container ownership, signature and token if present.
containerDelete: containerDelete:
- name: containerID - name: containerID
@ -35,9 +35,9 @@ and validate container ownership, signature and token if it is present.
- name: token - name: token
type: ByteArray type: ByteArray
setEACL notification. This notification is produced when container owner wants setEACL notification. This notification is produced when a container owner wants
to update extended ACL of the container. Alphabet nodes of the Inner Ring catch to update an extended ACL of a container. Alphabet nodes of the Inner Ring catch
notification and validate container ownership, signature and token if it is the notification and validate container ownership, signature and token if
present. present.
setEACL: setEACL:

View file

@ -1,22 +1,22 @@
/* /*
NeoFS contract is a contract deployed in NeoFS main chain. NeoFS contract is a contract deployed in NeoFS mainchain.
NeoFS contract is an entry point to NeoFS users. This contract stores all NeoFS NeoFS contract is an entry point to NeoFS users. This contract stores all NeoFS
related GAS, registers new Inner Ring candidates and produces notifications related GAS, registers new Inner Ring candidates and produces notifications
to control side chain. to control the sidechain.
While main chain committee controls list of Alphabet nodes in native While mainchain committee controls the list of Alphabet nodes in native
RoleManagement contract, NeoFS can't change more than 1\3 keys at a time. RoleManagement contract, NeoFS can't change more than 1\3 keys at a time.
NeoFS contract contains actual list of Alphabet nodes in the side chain. NeoFS contract contains the actual list of Alphabet nodes in the sidechain.
Network configuration also stored in NeoFS contract. All the changes in Network configuration is also stored in NeoFS contract. All changes in
configuration are mirrored in side chain with notifications. configuration are mirrored in the sidechain with notifications.
Contract notifications Contract notifications
Deposit notification. This notification is produced when user transfers native Deposit notification. This notification is produced when user transfers native
GAS to the NeoFS contract address. The same amount of NEOFS token will be GAS to the NeoFS contract address. The same amount of NEOFS token will be
minted in Balance contract in the side chain. minted in Balance contract in the sidechain.
Deposit: Deposit:
- name: from - name: from
@ -28,8 +28,8 @@ minted in Balance contract in the side chain.
- name: txHash - name: txHash
type: Hash256 type: Hash256
Withdraw notification. This notification is produced when user wants to Withdraw notification. This notification is produced when a user wants to
withdraw GAS from internal NeoFS balance and has payed fee for that. withdraw GAS from the internal NeoFS balance and has paid fee for that.
Withdraw: Withdraw:
- name: user - name: user
@ -41,7 +41,7 @@ withdraw GAS from internal NeoFS balance and has payed fee for that.
Cheque notification. This notification is produced when NeoFS contract Cheque notification. This notification is produced when NeoFS contract
successfully transferred assets back to the user after withdraw. has successfully transferred assets back to the user after withdraw.
Cheque: Cheque:
- name: id - name: id
@ -53,8 +53,8 @@ successfully transferred assets back to the user after withdraw.
- name: lockAccount - name: lockAccount
type: ByteArray type: ByteArray
Bind notification. This notification is produced when user wants to bind Bind notification. This notification is produced when a user wants to bind
public keys with user account (OwnerID). Keys argument is array of ByteArray. public keys with the user account (OwnerID). Keys argument is an array of ByteArray.
Bind: Bind:
- name: user - name: user
@ -62,8 +62,8 @@ public keys with user account (OwnerID). Keys argument is array of ByteArray.
- name: keys - name: keys
type: Array type: Array
Unbind notification. This notification is produced when user wants to unbind Unbind notification. This notification is produced when a user wants to unbind
public keys with user account (OwnerID). Keys argument is an array of ByteArray. public keys with the user account (OwnerID). Keys argument is an array of ByteArray.
Unbind: Unbind:
- name: user - name: user
@ -72,7 +72,7 @@ public keys with user account (OwnerID). Keys argument is an array of ByteArray.
type: Array type: Array
AlphabetUpdate notification. This notification is produced when Alphabet nodes AlphabetUpdate notification. This notification is produced when Alphabet nodes
updated it's list in the contract. Alphabet argument is an array of ByteArray. It have updated their lists in the contract. Alphabet argument is an array of ByteArray. It
contains public keys of new alphabet nodes. contains public keys of new alphabet nodes.
AlphabetUpdate: AlphabetUpdate:

View file

@ -103,8 +103,8 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("neofs: contract initialized") runtime.Log("neofs: contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by side chain committee. // only by sidechain committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
blockHeight := ledger.CurrentIndex() blockHeight := ledger.CurrentIndex()
alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1)) alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1))
@ -117,7 +117,7 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("neofs contract updated") runtime.Log("neofs contract updated")
} }
// AlphabetList returns array of alphabet node keys. Use in side chain notary // AlphabetList returns an array of alphabet node keys. It is used in sidechain notary
// disabled environment. // disabled environment.
func AlphabetList() []common.IRNode { func AlphabetList() []common.IRNode {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -129,14 +129,14 @@ func AlphabetList() []common.IRNode {
return nodes return nodes
} }
// AlphabetAddress returns 2\3n+1 multi signature address of alphabet nodes. // AlphabetAddress returns 2\3n+1 multisignature address of alphabet nodes.
// Used in side chain notary disabled environment. // It is used in sidechain notary disabled environment.
func AlphabetAddress() interop.Hash160 { func AlphabetAddress() interop.Hash160 {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return multiaddress(getAlphabetNodes(ctx)) return multiaddress(getAlphabetNodes(ctx))
} }
// InnerRingCandidates returns array of structures that contain Inner Ring // InnerRingCandidates returns an array of structures that contain an Inner Ring
// candidate node key. // candidate node key.
func InnerRingCandidates() []common.IRNode { func InnerRingCandidates() []common.IRNode {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -150,10 +150,10 @@ func InnerRingCandidates() []common.IRNode {
return nodes return nodes
} }
// InnerRingCandidateRemove removes key from the list of Inner Ring candidates. // InnerRingCandidateRemove removes a key from a list of Inner Ring candidates.
// Can be invoked by Alphabet nodes or candidate itself. // It can be invoked by Alphabet nodes or the candidate itself.
// //
// Method does not return fee back to the candidate. // This method does not return fee back to the candidate.
func InnerRingCandidateRemove(key interop.PublicKey) { func InnerRingCandidateRemove(key interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -201,11 +201,11 @@ func InnerRingCandidateRemove(key interop.PublicKey) {
} }
} }
// InnerRingCandidateAdd adds key to the list of Inner Ring candidates. // InnerRingCandidateAdd adds a key to a list of Inner Ring candidates.
// Can be invoked only by candidate itself. // It can be invoked only by the candidate itself.
// //
// This method transfers fee from candidate to contract account. // This method transfers fee from a candidate to the contract account.
// Fee value specified in NeoFS network config with the key InnerRingCandidateFee. // Fee value is specified in NeoFS network config with the key InnerRingCandidateFee.
func InnerRingCandidateAdd(key interop.PublicKey) { func InnerRingCandidateAdd(key interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -230,7 +230,7 @@ func InnerRingCandidateAdd(key interop.PublicKey) {
} }
// OnNEP17Payment is a callback for NEP-17 compatible native GAS contract. // OnNEP17Payment is a callback for NEP-17 compatible native GAS contract.
// It takes no more than 9000.0 GAS. Native GAS has precision 8 and // It takes no more than 9000.0 GAS. Native GAS has precision 8, and
// NeoFS balance contract has precision 12. Values bigger than 9000.0 can // NeoFS balance contract has precision 12. Values bigger than 9000.0 can
// break JSON limits for integers when precision is converted. // break JSON limits for integers when precision is converted.
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
@ -264,13 +264,13 @@ func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
runtime.Notify("Deposit", from, amount, rcv, tx.Hash) runtime.Notify("Deposit", from, amount, rcv, tx.Hash)
} }
// Withdraw initialize gas asset withdraw from NeoFS. Can be invoked only // Withdraw initializes gas asset withdraw from NeoFS. It can be invoked only
// by the specified user. // by the specified user.
// //
// This method produces Withdraw notification to lock assets in side chain and // This method produces Withdraw notification to lock assets in the sidechain and
// transfers withdraw fee from user account to each Alphabet node. If notary // transfers withdraw fee from a user account to each Alphabet node. If notary
// is enabled in main chain, fee is transferred to Processing contract. // is enabled in the mainchain, fee is transferred to Processing contract.
// Fee value specified in NeoFS network config with the key WithdrawFee. // Fee value is specified in NeoFS network config with the key WithdrawFee.
func Withdraw(user interop.Hash160, amount int) { func Withdraw(user interop.Hash160, amount int) {
if !runtime.CheckWitness(user) { if !runtime.CheckWitness(user) {
panic("you should be the owner of the wallet") panic("you should be the owner of the wallet")
@ -316,11 +316,11 @@ func Withdraw(user interop.Hash160, amount int) {
runtime.Notify("Withdraw", user, amount, tx.Hash) runtime.Notify("Withdraw", user, amount, tx.Hash)
} }
// Cheque transfers GAS back to the user from contract account, if assets were // Cheque transfers GAS back to the user from the contract account, if assets were
// successfully locked in NeoFS balance contract. Can be invoked only by // successfully locked in NeoFS balance contract. It can be invoked only by
// Alphabet nodes. // Alphabet nodes.
// //
// This method produces Cheque notification to burn assets in side chain. // This method produces Cheque notification to burn assets in sidechain.
func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) { func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -363,11 +363,11 @@ func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) {
runtime.Notify("Cheque", id, user, amount, lockAcc) runtime.Notify("Cheque", id, user, amount, lockAcc)
} }
// Bind method produces notification to bind specified public keys in NeoFSID // Bind method produces notification to bind the specified public keys in NeoFSID
// contract in side chain. Can be invoked only by specified user. // contract in the sidechain. It can be invoked only by specified user.
// //
// This method produces Bind notification. Method panics if keys are not // This method produces Bind notification. This method panics if keys are not
// 33 byte long. User argument must be valid 20 byte script hash. // 33 byte long. User argument must be a valid 20 byte script hash.
func Bind(user []byte, keys []interop.PublicKey) { func Bind(user []byte, keys []interop.PublicKey) {
if !runtime.CheckWitness(user) { if !runtime.CheckWitness(user) {
panic("you should be the owner of the wallet") panic("you should be the owner of the wallet")
@ -383,11 +383,11 @@ func Bind(user []byte, keys []interop.PublicKey) {
runtime.Notify("Bind", user, keys) runtime.Notify("Bind", user, keys)
} }
// Unbind method produces notification to unbind specified public keys in NeoFSID // Unbind method produces notification to unbind the specified public keys in NeoFSID
// contract in side chain. Can be invoked only by specified user. // contract in the sidechain. It can be invoked only by the specified user.
// //
// This method produces Unbind notification. Method panics if keys are not // This method produces Unbind notification. This method panics if keys are not
// 33 byte long. User argument must be valid 20 byte script hash. // 33 byte long. User argument must be a valid 20 byte script hash.
func Unbind(user []byte, keys []interop.PublicKey) { func Unbind(user []byte, keys []interop.PublicKey) {
if !runtime.CheckWitness(user) { if !runtime.CheckWitness(user) {
panic("you should be the owner of the wallet") panic("you should be the owner of the wallet")
@ -403,11 +403,11 @@ func Unbind(user []byte, keys []interop.PublicKey) {
runtime.Notify("Unbind", user, keys) runtime.Notify("Unbind", user, keys)
} }
// AlphabetUpdate updates list of alphabet nodes with provided list of // AlphabetUpdate updates a list of alphabet nodes with the provided list of
// public keys. Can be invoked only by alphabet nodes. // public keys. It can be invoked only by alphabet nodes.
// //
// This method used in notary disabled side chain environment. In this case // This method is used in notary disabled sidechain environment. In this case,
// actual alphabet list should be stored in the NeoFS contract. // the actual alphabet list should be stored in the NeoFS contract.
func AlphabetUpdate(id []byte, args []interop.PublicKey) { func AlphabetUpdate(id []byte, args []interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -460,14 +460,14 @@ func AlphabetUpdate(id []byte, args []interop.PublicKey) {
runtime.Log("alphabet list has been updated") runtime.Log("alphabet list has been updated")
} }
// Config returns configuration value of NeoFS configuration. If key does // Config returns configuration value of NeoFS configuration. If the key does
// not exists, returns nil. // not exists, returns nil.
func Config(key []byte) interface{} { func Config(key []byte) interface{} {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return getConfig(ctx, key) return getConfig(ctx, key)
} }
// SetConfig key-value pair as a NeoFS runtime configuration value. Can be invoked // SetConfig key-value pair as a NeoFS runtime configuration value. It can be invoked
// only by Alphabet nodes. // only by Alphabet nodes.
func SetConfig(id, key, val []byte) { func SetConfig(id, key, val []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -506,7 +506,7 @@ func SetConfig(id, key, val []byte) {
runtime.Log("configuration has been updated") runtime.Log("configuration has been updated")
} }
// ListConfig returns array of structures that contain key and value of all // ListConfig returns an array of structures that contain a key and a value of all
// NeoFS configuration records. Key and value are both byte arrays. // NeoFS configuration records. Key and value are both byte arrays.
func ListConfig() []record { func ListConfig() []record {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -532,7 +532,7 @@ func Version() int {
return common.Version return common.Version
} }
// getAlphabetNodes returns deserialized slice of nodes from storage. // getAlphabetNodes returns a deserialized slice of nodes from storage.
func getAlphabetNodes(ctx storage.Context) []interop.PublicKey { func getAlphabetNodes(ctx storage.Context) []interop.PublicKey {
data := storage.Get(ctx, alphabetKey) data := storage.Get(ctx, alphabetKey)
if data != nil { if data != nil {
@ -542,7 +542,7 @@ func getAlphabetNodes(ctx storage.Context) []interop.PublicKey {
return []interop.PublicKey{} return []interop.PublicKey{}
} }
// getConfig returns installed neofs configuration value or nil if it is not set. // getConfig returns the installed neofs configuration value or nil if it is not set.
func getConfig(ctx storage.Context, key interface{}) interface{} { func getConfig(ctx storage.Context, key interface{}) interface{} {
postfix := key.([]byte) postfix := key.([]byte)
storageKey := append(configPrefix, postfix...) storageKey := append(configPrefix, postfix...)
@ -550,7 +550,7 @@ func getConfig(ctx storage.Context, key interface{}) interface{} {
return storage.Get(ctx, storageKey) return storage.Get(ctx, storageKey)
} }
// setConfig sets neofs configuration value in the contract storage. // setConfig sets a neofs configuration value in the contract storage.
func setConfig(ctx storage.Context, key, val interface{}) { func setConfig(ctx storage.Context, key, val interface{}) {
postfix := key.([]byte) postfix := key.([]byte)
storageKey := append(configPrefix, postfix...) storageKey := append(configPrefix, postfix...)
@ -558,7 +558,7 @@ func setConfig(ctx storage.Context, key, val interface{}) {
storage.Put(ctx, storageKey, val) storage.Put(ctx, storageKey, val)
} }
// multiaddress returns multi signature address from list of IRNode structures // multiaddress returns a multisignature address from the list of IRNode structures
// with m = 2/3n+1. // with m = 2/3n+1.
func multiaddress(keys []interop.PublicKey) []byte { func multiaddress(keys []interop.PublicKey) []byte {
threshold := len(keys)*2/3 + 1 threshold := len(keys)*2/3 + 1

View file

@ -1,16 +1,16 @@
/* /*
NeoFSID contract is a contract deployed in NeoFS side chain. NeoFSID contract is a contract deployed in NeoFS sidechain.
NeoFSID contract used to store connection between OwnerID and it's public keys. NeoFSID 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 public key. OwnerID is a 25-byte N3 wallet address that can be produced from a public key.
It is one-way conversion. In simple cases NeoFS verifies ownership by checking It is one-way conversion. In simple cases, NeoFS verifies ownership by checking
signature and relation between public key and OwnerID. signature and relation between a public key and an OwnerID.
In more complex cases, user can use public keys unrelated to OwnerID to maintain In more complex cases, a user can use public keys unrelated to the OwnerID to maintain
secure access to the data. NeoFSID contract stores relation between OwnerID and secure access to the data. NeoFSID contract stores relation between an OwnerID and
arbitrary public keys. Data owner can bind or unbind public key with it's account arbitrary public keys. Data owner can bind a public key with its account or unbind it
by invoking Bind or Unbind methods of NeoFS contract in main chain. After that, by invoking Bind or Unbind methods of NeoFS contract in the mainchain. After that,
Alphabet nodes produce multi signed AddKey and RemoveKey invocations of NeoFSID Alphabet nodes produce multisigned AddKey and RemoveKey invocations of NeoFSID
contract. contract.
Contract notifications Contract notifications

View file

@ -60,7 +60,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("neofsid contract initialized") runtime.Log("neofsid contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -72,11 +72,11 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("neofsid contract updated") runtime.Log("neofsid contract updated")
} }
// AddKey binds list of provided public keys to OwnerID. Can be invoked only by // AddKey binds a list of the provided public keys to the OwnerID. It can be invoked only by
// Alphabet nodes. // Alphabet nodes.
// //
// This method panics if OwnerID is not ownerSize byte or public key is not 33 byte long. // This method panics if the OwnerID is not an ownerSize byte or the public key is not 33 byte long.
// If key is already bound, ignores it. // If the key is already bound, the method ignores it.
func AddKey(owner []byte, keys []interop.PublicKey) { func AddKey(owner []byte, keys []interop.PublicKey) {
// V2 format // V2 format
if len(owner) != ownerSize { if len(owner) != ownerSize {
@ -135,11 +135,11 @@ func AddKey(owner []byte, keys []interop.PublicKey) {
runtime.Log("key bound to the owner") runtime.Log("key bound to the owner")
} }
// RemoveKey unbinds provided public keys from OwnerID. Can be invoked only by // RemoveKey unbinds the provided public keys from the OwnerID. It can be invoked only by
// Alphabet nodes. // Alphabet nodes.
// //
// This method panics if OwnerID is not ownerSize byte or public key is not 33 byte long. // This method panics if the OwnerID is not an ownerSize byte or the public key is not 33 byte long.
// If key is already unbound, ignores it. // If the key is already unbound, the method ignores it.
func RemoveKey(owner []byte, keys []interop.PublicKey) { func RemoveKey(owner []byte, keys []interop.PublicKey) {
// V2 format // V2 format
if len(owner) != ownerSize { if len(owner) != ownerSize {
@ -190,9 +190,9 @@ func RemoveKey(owner []byte, keys []interop.PublicKey) {
} }
} }
// Key method returns list of 33-byte public keys bound with OwnerID. // Key method returns a list of 33-byte public keys bound with the OwnerID.
// //
// This method panics if owner is not ownerSize byte long. // This method panics if the owner is not ownerSize byte long.
func Key(owner []byte) [][]byte { func Key(owner []byte) [][]byte {
// V2 format // V2 format
if len(owner) != ownerSize { if len(owner) != ownerSize {
@ -207,7 +207,7 @@ func Key(owner []byte) [][]byte {
return info.Keys return info.Keys
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -1,21 +1,21 @@
/* /*
Netmap contract is a contract deployed in NeoFS side chain. Netmap contract is a contract deployed in NeoFS sidechain.
Netmap contract stores and manages NeoFS network map, Storage node candidates Netmap contract stores and manages NeoFS network map, Storage node candidates
and epoch number counter. In notary disabled environment, contract also stores and epoch number counter. In notary disabled environment, contract also stores
list of Inner Ring node keys. a list of Inner Ring node keys.
Contract notifications Contract notifications
AddPeer notification. This notification is produced when Storage node sends AddPeer notification. This notification is produced when a Storage node sends
bootstrap request by invoking AddPeer method. a bootstrap request by invoking AddPeer method.
AddPeer AddPeer
- name: nodeInfo - name: nodeInfo
type: ByteArray type: ByteArray
UpdateState notification. This notification is produced when Storage node wants UpdateState notification. This notification is produced when a Storage node wants
to change it's state (go offline) by invoking UpdateState method. Supported to change its state (go offline) by invoking UpdateState method. Supported
states: (2) -- offline. states: (2) -- offline.
UpdateState UpdateState
@ -24,7 +24,7 @@ states: (2) -- offline.
- name: publicKey - name: publicKey
type: PublicKey type: PublicKey
NewEpoch notification. This notification is produced when new epoch is applied NewEpoch notification. This notification is produced when a new epoch is applied
in the network by invoking NewEpoch method. in the network by invoking NewEpoch method.
NewEpoch NewEpoch

View file

@ -122,7 +122,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("netmap contract initialized") runtime.Log("netmap contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -134,11 +134,11 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("netmap contract updated") runtime.Log("netmap contract updated")
} }
// InnerRingList method returns slice of structures that contains public key of // InnerRingList method returns a slice of structures that contains the public key of
// Inner Ring node. Should be used only in notary disabled environment. // an Inner Ring node. It should be used in notary disabled environment only.
// //
// If notary enabled, then look to NeoFSAlphabet role in native RoleManagement // If notary is enabled, look to NeoFSAlphabet role in native RoleManagement
// contract of the side chain. // contract of the sidechain.
func InnerRingList() []common.IRNode { func InnerRingList() []common.IRNode {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
pubs := getIRNodes(ctx) pubs := getIRNodes(ctx)
@ -149,11 +149,11 @@ func InnerRingList() []common.IRNode {
return nodes return nodes
} }
// UpdateInnerRing method updates list of Inner Ring node keys. Should be used // UpdateInnerRing method updates a list of Inner Ring node keys. It should be used
// only in notary disabled environment. Can be invoked only by Alphabet nodes. // only in notary disabled environment. It can be invoked only by Alphabet nodes.
// //
// If notary enabled, then update NeoFSAlphabet role in native RoleManagement // If notary is enabled, update NeoFSAlphabet role in native RoleManagement
// contract of the side chain. Use notary service to collect multi signature. // contract of the sidechain. Use notary service to collect multisignature.
func UpdateInnerRing(keys []interop.PublicKey) { func UpdateInnerRing(keys []interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -190,8 +190,8 @@ func UpdateInnerRing(keys []interop.PublicKey) {
common.SetSerialized(ctx, innerRingKey, keys) common.SetSerialized(ctx, innerRingKey, keys)
} }
// AddPeerIR method tries to add new candidate to the network map. // AddPeerIR method tries to add a new candidate to the network map.
// Should only be invoked in notary-enabled environment by the alphabet. // It should only be invoked in notary-enabled environment by the alphabet.
func AddPeerIR(nodeInfo []byte) { func AddPeerIR(nodeInfo []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -207,12 +207,12 @@ func AddPeerIR(nodeInfo []byte) {
runtime.Notify("AddPeerSuccess", interop.PublicKey(publicKey)) runtime.Notify("AddPeerSuccess", interop.PublicKey(publicKey))
} }
// AddPeer method adds new candidate to the next network map if it was invoked // AddPeer method adds a new candidate to the next network map if it was invoked
// by Alphabet node. If it was invoked by node candidate, it produces AddPeer // by Alphabet node. If it was invoked by a node candidate, it produces AddPeer
// notification. Otherwise method throws panic. // notification. Otherwise, the method throws panic.
// //
// If the candidate already exists, it's info is updated. // If the candidate already exists, its info is updated.
// NodeInfo argument contains stable marshaled version of netmap.NodeInfo // NodeInfo argument contains a stable marshaled version of netmap.NodeInfo
// structure. // structure.
func AddPeer(nodeInfo []byte) { func AddPeer(nodeInfo []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -262,11 +262,11 @@ func AddPeer(nodeInfo []byte) {
runtime.Notify("AddPeerSuccess", interop.PublicKey(publicKey)) runtime.Notify("AddPeerSuccess", interop.PublicKey(publicKey))
} }
// UpdateState method updates state of node from the network map candidate list. // UpdateState method updates the state of a node from the network map candidate list.
// For notary-ENABLED environment tx must be signed by both storage node and the alphabet. // For notary-ENABLED environment, tx must be signed by both storage node and alphabet.
// To force update without storage node signature, see `UpdateStateIR`. // To force update without storage node signature, see `UpdateStateIR`.
// //
// For notary-DISABLED environment the behaviour depends on who signed the transaction: // For notary-DISABLED environment, the behaviour depends on who signed the transaction:
// 1. If it was signed by alphabet, go into voting. // 1. If it was signed by alphabet, go into voting.
// 2. If it was signed by a storage node, emit `UpdateState` notification. // 2. If it was signed by a storage node, emit `UpdateState` notification.
// 2. Fail in any other case. // 2. Fail in any other case.
@ -276,7 +276,7 @@ func AddPeer(nodeInfo []byte) {
// | ENABLED | FAIL | FAIL | OK | // | ENABLED | FAIL | FAIL | OK |
// | DISABLED | NOTIFICATION | OK | OK (same as alphabet) | // | DISABLED | NOTIFICATION | OK | OK (same as alphabet) |
// State argument defines node state. The only supported state now is (2) -- // State argument defines node state. The only supported state now is (2) --
// offline state. Node is removed from network map candidate list. // offline state. Node is removed from the network map candidate list.
// //
// Method panics when invoked with unsupported states. // Method panics when invoked with unsupported states.
func UpdateState(state int, publicKey interop.PublicKey) { func UpdateState(state int, publicKey interop.PublicKey) {
@ -324,8 +324,8 @@ func UpdateState(state int, publicKey interop.PublicKey) {
runtime.Notify("UpdateStateSuccess", publicKey, state) runtime.Notify("UpdateStateSuccess", publicKey, state)
} }
// UpdateStateIR method tries to change node state in the network map. // UpdateStateIR method tries to change the node state in the network map.
// Should only be invoked in notary-enabled environment by the alphabet. // Should only be invoked in notary-enabled environment by alphabet.
func UpdateStateIR(state nodeState, publicKey interop.PublicKey) { func UpdateStateIR(state nodeState, publicKey interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -344,15 +344,15 @@ func UpdateStateIR(state nodeState, publicKey interop.PublicKey) {
runtime.Notify("UpdateStateSuccess", publicKey, state) runtime.Notify("UpdateStateSuccess", publicKey, state)
} }
// NewEpoch method changes epoch number up to provided epochNum argument. Can // NewEpoch method changes the epoch number up to the provided epochNum argument. It can
// be invoked only by Alphabet nodes. If provided epoch number is less or equal // be invoked only by Alphabet nodes. If provided epoch number is less than the
// current epoch number, method throws panic. // current epoch number or equals it, the method throws panic.
// //
// When epoch number updated, contract sets storage node candidates as current // When epoch number is updated, the contract sets storage node candidates as the current
// network map. Also contract invokes NewEpoch method on Balance and Container // network map. The contract also invokes NewEpoch method on Balance and Container
// contracts. // contracts.
// //
// Produces NewEpoch notification. // It produces NewEpoch notification.
func NewEpoch(epochNum int) { func NewEpoch(epochNum int) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -411,41 +411,41 @@ func NewEpoch(epochNum int) {
runtime.Notify("NewEpoch", epochNum) runtime.Notify("NewEpoch", epochNum)
} }
// Epoch method returns current epoch number. // Epoch method returns the current epoch number.
func Epoch() int { func Epoch() int {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return storage.Get(ctx, snapshotEpoch).(int) return storage.Get(ctx, snapshotEpoch).(int)
} }
// LastEpochBlock method returns block number when current epoch was applied. // LastEpochBlock method returns the block number when the current epoch was applied.
func LastEpochBlock() int { func LastEpochBlock() int {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return storage.Get(ctx, snapshotBlockKey).(int) return storage.Get(ctx, snapshotBlockKey).(int)
} }
// Netmap method returns list of structures that contain byte array of stable // Netmap method returns a list of structures that contain a byte array of a stable
// marshalled netmap.NodeInfo structure. These structure contain Storage nodes // marshalled netmap.NodeInfo structure. These structures contain Storage nodes
// of current epoch. // of the current epoch.
func Netmap() []storageNode { func Netmap() []storageNode {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
id := storage.Get(ctx, snapshotCurrentIDKey).(int) id := storage.Get(ctx, snapshotCurrentIDKey).(int)
return getSnapshot(ctx, snapshotKeyPrefix+string([]byte{byte(id)})) return getSnapshot(ctx, snapshotKeyPrefix+string([]byte{byte(id)}))
} }
// NetmapCandidates method returns list of structures that contain node state // NetmapCandidates method returns a list of structures that contain the node state
// and byte array of stable marshalled netmap.NodeInfo structure. // and a byte array of a stable marshalled netmap.NodeInfo structure.
// These structure contain Storage node candidates for next epoch. // These structures contain Storage node candidates for the next epoch.
func NetmapCandidates() []netmapNode { func NetmapCandidates() []netmapNode {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return getNetmapNodes(ctx) return getNetmapNodes(ctx)
} }
// Snapshot method returns list of structures that contain node state // Snapshot method returns a list of structures that contain the node state
// (online: 1) and byte array of stable marshalled netmap.NodeInfo structure. // (online: 1) and a byte array of a stable marshalled netmap.NodeInfo structure.
// These structure contain Storage nodes of specified epoch. // These structures contain Storage nodes of the specified epoch.
// //
// Netmap contract contains only two recent network map snapshot: current and // Netmap contract contains only two recent network map snapshots: current and
// previous epoch. For diff bigger than 1 or less than 0 method throws panic. // previous epoch. For diff bigger than 1 or less than 0, the method throws panic.
func Snapshot(diff int) []storageNode { func Snapshot(diff int) []storageNode {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
count := getSnapshotCount(ctx) count := getSnapshotCount(ctx)
@ -463,9 +463,9 @@ func getSnapshotCount(ctx storage.Context) int {
return storage.Get(ctx, snapshotCountKey).(int) return storage.Get(ctx, snapshotCountKey).(int)
} }
// UpdateSnapshotCount updates number of stored snapshots. // UpdateSnapshotCount updates the number of the stored snapshots.
// If new number is less than the old one, old snapshots are removed. // If a new number is less than the old one, old snapshots are removed.
// Otherwise, history is extended to with empty snapshots, so // Otherwise, history is extended with empty snapshots, so
// `Snapshot` method can return invalid results for `diff = new-old` epochs // `Snapshot` method can return invalid results for `diff = new-old` epochs
// until `diff` epochs have passed. // until `diff` epochs have passed.
func UpdateSnapshotCount(count int) { func UpdateSnapshotCount(count int) {
@ -545,9 +545,9 @@ func moveSnapshot(ctx storage.Context, from, to int) {
storage.Put(ctx, keyTo, data) storage.Put(ctx, keyTo, data)
} }
// SnapshotByEpoch method returns list of structures that contain node state // SnapshotByEpoch method returns a list of structures that contain the node state
// (online: 1) and byte array of stable marshalled netmap.NodeInfo structure. // (online: 1) and a byte array of a stable marshalled netmap.NodeInfo structure.
// These structure contain Storage nodes of specified epoch. // These structures contain Storage nodes of the specified epoch.
// //
// Netmap contract contains only two recent network map snapshot: current and // Netmap contract contains only two recent network map snapshot: current and
// previous epoch. For all others epoch method throws panic. // previous epoch. For all others epoch method throws panic.
@ -565,7 +565,7 @@ func Config(key []byte) interface{} {
return getConfig(ctx, key) return getConfig(ctx, key)
} }
// SetConfig key-value pair as a NeoFS runtime configuration value. Can be invoked // SetConfig key-value pair as a NeoFS runtime configuration value. It can be invoked
// only by Alphabet nodes. // only by Alphabet nodes.
func SetConfig(id, key, val []byte) { func SetConfig(id, key, val []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -603,7 +603,7 @@ func SetConfig(id, key, val []byte) {
runtime.Log("configuration has been updated") runtime.Log("configuration has been updated")
} }
// ListConfig returns array of structures that contain key and value of all // ListConfig returns an array of structures that contain key and value of all
// NeoFS configuration records. Key and value are both byte arrays. // NeoFS configuration records. Key and value are both byte arrays.
func ListConfig() []record { func ListConfig() []record {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -624,7 +624,7 @@ func ListConfig() []record {
return config return config
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -4,7 +4,7 @@ implementation. This token is a compatible analogue of C# Neo Name Service
token and is aimed to serve as a domain name service for Neo smart-contracts, token and is aimed to serve as a domain name service for Neo smart-contracts,
thus it's NeoNameService. This token can be minted with new domain name thus it's NeoNameService. This token can be minted with new domain name
registration, the domain name itself is your NFT. Corresponding domain root registration, the domain name itself is your NFT. Corresponding domain root
must be added by the committee before new domain name can be registered. must be added by committee before a new domain name can be registered.
*/ */
package nns package nns
@ -26,7 +26,7 @@ import (
const ( const (
// prefixTotalSupply contains total supply of minted domains. // prefixTotalSupply contains total supply of minted domains.
prefixTotalSupply byte = 0x00 prefixTotalSupply byte = 0x00
// prefixBalance contains map from owner to his balance. // prefixBalance contains map from the owner to their balance.
prefixBalance byte = 0x01 prefixBalance byte = 0x01
// prefixAccountToken contains map from (owner + token key) to token ID, // prefixAccountToken contains map from (owner + token key) to token ID,
// where token key = hash160(token ID) and token ID = domain name. // where token key = hash160(token ID) and token ID = domain name.
@ -110,25 +110,25 @@ func Decimals() int {
return 0 return 0
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }
// TotalSupply returns overall number of domains minted by the NeoNameService contract. // TotalSupply returns the overall number of domains minted by NeoNameService contract.
func TotalSupply() int { func TotalSupply() int {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
return getTotalSupply(ctx) return getTotalSupply(ctx)
} }
// OwnerOf returns owner of the specified domain. // OwnerOf returns the owner of the specified domain.
func OwnerOf(tokenID []byte) interop.Hash160 { func OwnerOf(tokenID []byte) interop.Hash160 {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
ns := getNameState(ctx, tokenID) ns := getNameState(ctx, tokenID)
return ns.Owner return ns.Owner
} }
// Properties returns domain name and expiration date of the specified domain. // Properties returns a domain name and an expiration date of the specified domain.
func Properties(tokenID []byte) map[string]interface{} { func Properties(tokenID []byte) map[string]interface{} {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
ns := getNameState(ctx, tokenID) ns := getNameState(ctx, tokenID)
@ -138,7 +138,7 @@ func Properties(tokenID []byte) map[string]interface{} {
} }
} }
// BalanceOf returns overall number of domains owned by the specified owner. // BalanceOf returns the overall number of domains owned by the specified owner.
func BalanceOf(owner interop.Hash160) int { func BalanceOf(owner interop.Hash160) int {
if !isValid(owner) { if !isValid(owner) {
panic(`invalid owner`) panic(`invalid owner`)
@ -166,7 +166,7 @@ func TokensOf(owner interop.Hash160) iterator.Iterator {
return storage.Find(ctx, append([]byte{prefixAccountToken}, owner...), storage.ValuesOnly) return storage.Find(ctx, append([]byte{prefixAccountToken}, owner...), storage.ValuesOnly)
} }
// Transfer transfers domain with the specified name to new owner. // Transfer transfers the domain with the specified name to a new owner.
func Transfer(to interop.Hash160, tokenID []byte, data interface{}) bool { func Transfer(to interop.Hash160, tokenID []byte, data interface{}) bool {
if !isValid(to) { if !isValid(to) {
panic(`invalid receiver`) panic(`invalid receiver`)
@ -218,7 +218,7 @@ func GetPrice() int {
return storage.Get(ctx, []byte{prefixRegisterPrice}).(int) return storage.Get(ctx, []byte{prefixRegisterPrice}).(int)
} }
// IsAvailable checks whether provided domain name is available. // IsAvailable checks whether the provided domain name is available.
func IsAvailable(name string) bool { func IsAvailable(name string) bool {
fragments := splitAndCheck(name, false) fragments := splitAndCheck(name, false)
if fragments == nil { if fragments == nil {
@ -235,7 +235,7 @@ func IsAvailable(name string) bool {
return parentExpired(ctx, 0, fragments) return parentExpired(ctx, 0, fragments)
} }
// parentExpired returns true if any domain from fragments doesn't exist or expired. // parentExpired returns true if any domain from fragments doesn't exist or is expired.
// first denotes the deepest subdomain to check. // first denotes the deepest subdomain to check.
func parentExpired(ctx storage.Context, first int, fragments []string) bool { func parentExpired(ctx storage.Context, first int, fragments []string) bool {
now := runtime.GetTime() now := runtime.GetTime()
@ -257,7 +257,7 @@ func parentExpired(ctx storage.Context, first int, fragments []string) bool {
return false return false
} }
// Register registers new domain with the specified owner and name if it's available. // 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 { func Register(name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool {
fragments := splitAndCheck(name, true) fragments := splitAndCheck(name, true)
if fragments == nil { if fragments == nil {
@ -343,7 +343,7 @@ func Renew(name string) int {
return ns.Expiration return ns.Expiration
} }
// UpdateSOA update soa record. // UpdateSOA updates soa record.
func UpdateSOA(name, email string, refresh, retry, expire, ttl int) { func UpdateSOA(name, email string, refresh, retry, expire, ttl int) {
if len(name) > maxDomainNameLength { if len(name) > maxDomainNameLength {
panic("invalid domain name format") panic("invalid domain name format")
@ -369,7 +369,7 @@ func SetAdmin(name string, admin interop.Hash160) {
putNameState(ctx, ns) putNameState(ctx, ns)
} }
// SetRecord adds new record of the specified type to the provided domain. // SetRecord adds a new record of the specified type to the provided domain.
func SetRecord(name string, typ RecordType, id byte, data string) { func SetRecord(name string, typ RecordType, id byte, data string) {
tokenID := []byte(tokenIDFromName(name)) tokenID := []byte(tokenIDFromName(name))
if !checkBaseRecords(typ, data) { if !checkBaseRecords(typ, data) {
@ -397,7 +397,7 @@ func checkBaseRecords(typ RecordType, data string) bool {
} }
} }
// AddRecord adds new record of the specified type to the provided domain. // AddRecord adds a new record of the specified type to the provided domain.
func AddRecord(name string, typ RecordType, data string) { func AddRecord(name string, typ RecordType, data string) {
tokenID := []byte(tokenIDFromName(name)) tokenID := []byte(tokenIDFromName(name))
if !checkBaseRecords(typ, data) { if !checkBaseRecords(typ, data) {
@ -443,7 +443,7 @@ func Resolve(name string, typ RecordType) []string {
return resolve(ctx, nil, name, typ, 2) return resolve(ctx, nil, name, typ, 2)
} }
// GetAllRecords returns an Iterator with RecordState items for given name. // GetAllRecords returns an Iterator with RecordState items for the given name.
func GetAllRecords(name string) iterator.Iterator { func GetAllRecords(name string) iterator.Iterator {
tokenID := []byte(tokenIDFromName(name)) tokenID := []byte(tokenIDFromName(name))
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -490,7 +490,7 @@ func getTotalSupply(ctx storage.Context) int {
return val.(int) return val.(int)
} }
// updateTotalSupply adds specified diff to the total supply. // updateTotalSupply adds the specified diff to the total supply.
func updateTotalSupply(ctx storage.Context, diff int) { func updateTotalSupply(ctx storage.Context, diff int) {
tsKey := []byte{prefixTotalSupply} tsKey := []byte{prefixTotalSupply}
ts := getTotalSupply(ctx) ts := getTotalSupply(ctx)
@ -587,7 +587,7 @@ func addRecord(ctx storage.Context, tokenId []byte, name string, typ RecordType,
storeRecord(ctx, recordKey, name, typ, id, data) storeRecord(ctx, recordKey, name, typ, id, data)
} }
// storeRecord put record to storage. // storeRecord puts record to storage.
func storeRecord(ctx storage.Context, recordKey []byte, name string, typ RecordType, id byte, data string) { func storeRecord(ctx storage.Context, recordKey []byte, name string, typ RecordType, id byte, data string) {
rs := RecordState{ rs := RecordState{
Name: name, Name: name,
@ -644,19 +644,19 @@ func updateSoaSerial(ctx storage.Context, tokenId []byte) {
storage.Put(ctx, recordKey, recBytes) storage.Put(ctx, recordKey, recBytes)
} }
// getRecordsKey returns prefix used to store domain records of different types. // getRecordsKey returns the prefix used to store domain records of different types.
func getRecordsKey(tokenId []byte, name string) []byte { func getRecordsKey(tokenId []byte, name string) []byte {
recordKey := append([]byte{prefixRecord}, getTokenKey(tokenId)...) recordKey := append([]byte{prefixRecord}, getTokenKey(tokenId)...)
return append(recordKey, getTokenKey([]byte(name))...) return append(recordKey, getTokenKey([]byte(name))...)
} }
// getRecordsKeyByType returns key used to store domain records. // getRecordsKeyByType returns the key used to store domain records.
func getRecordsKeyByType(tokenId []byte, name string, typ RecordType) []byte { func getRecordsKeyByType(tokenId []byte, name string, typ RecordType) []byte {
recordKey := getRecordsKey(tokenId, name) recordKey := getRecordsKey(tokenId, name)
return append(recordKey, byte(typ)) return append(recordKey, byte(typ))
} }
// getIdRecordKey returns key used to store domain records. // getIdRecordKey returns the key used to store domain records.
func getIdRecordKey(tokenId []byte, name string, typ RecordType, id byte) []byte { func getIdRecordKey(tokenId []byte, name string, typ RecordType, id byte) []byte {
recordKey := getRecordsKey(tokenId, name) recordKey := getRecordsKey(tokenId, name)
return append(recordKey, byte(typ), id) return append(recordKey, byte(typ), id)
@ -682,7 +682,7 @@ func checkCommittee() {
// checkFragment validates root or a part of domain name. // checkFragment validates root or a part of domain name.
// 1. Root domain must start with a letter. // 1. Root domain must start with a letter.
// 2. All other fragments must start and end in a letter or a digit. // 2. All other fragments must start and end with a letter or a digit.
func checkFragment(v string, isRoot bool) bool { func checkFragment(v string, isRoot bool) bool {
maxLength := maxDomainNameFragmentLength maxLength := maxDomainNameFragmentLength
if isRoot { if isRoot {
@ -843,7 +843,7 @@ func checkIPv6(data string) bool {
return true return true
} }
// tokenIDFromName returns token ID (domain.root) from provided name. // tokenIDFromName returns token ID (domain.root) from the provided name.
func tokenIDFromName(name string) string { func tokenIDFromName(name string) string {
fragments := splitAndCheck(name, true) fragments := splitAndCheck(name, true)
if fragments == nil { if fragments == nil {
@ -868,7 +868,7 @@ func tokenIDFromName(name string) string {
return name return name
} }
// resolve resolves provided name using record with the specified type and given // resolve resolves the provided name using record with the specified type and given
// maximum redirections constraint. // maximum redirections constraint.
func resolve(ctx storage.Context, res []string, name string, typ RecordType, redirect int) []string { func resolve(ctx storage.Context, res []string, name string, typ RecordType, redirect int) []string {
if redirect < 0 { if redirect < 0 {

View file

@ -3,7 +3,7 @@ package nns
// RecordType is domain name service record types. // RecordType is domain name service record types.
type RecordType byte type RecordType byte
// Record types defined in [RFC 1035](https://tools.ietf.org/html/rfc1035) // Record types are defined in [RFC 1035](https://tools.ietf.org/html/rfc1035)
const ( const (
// A represents address record type. // A represents address record type.
A RecordType = 1 A RecordType = 1
@ -15,7 +15,7 @@ const (
TXT RecordType = 16 TXT RecordType = 16
) )
// Record types defined in [RFC 3596](https://tools.ietf.org/html/rfc3596) // Record types are defined in [RFC 3596](https://tools.ietf.org/html/rfc3596)
const ( const (
// AAAA represents IPv6 address record type. // AAAA represents IPv6 address record type.
AAAA RecordType = 28 AAAA RecordType = 28

View file

@ -1,18 +1,18 @@
/* /*
Processing contract is a contract deployed in NeoFS main chain. Processing contract is a contract deployed in NeoFS mainchain.
Processing contract pays for all multi signature transaction executions when notary Processing contract pays for all multisignature transaction executions when notary
service enabled in main chain. Notary service prepares multi signed transaction, service is enabled in the mainchain. Notary service prepares multisigned transactions,
however they should contain side chain GAS to be executed. It is inconvenient to however they should contain sidechain GAS to be executed. It is inconvenient to
ask Alphabet nodes to pay for these transactions: nodes can change over time, ask Alphabet nodes to pay for these transactions: nodes can change over time,
some nodes will spend side chain GAS faster, it creates economic instability. some nodes will spend sidechain GAS faster. It leads to economic instability.
Processing contract exists to solve this issue. At the Withdraw invocation of Processing contract exists to solve this issue. At the Withdraw invocation of
NeoFS contract, user pays fee directly to this contract. This fee is used to NeoFS contract, a user pays fee directly to this contract. This fee is used to
pay for Cheque invocation of NeoFS contract that returns main chain GAS back pay for Cheque invocation of NeoFS contract that returns mainchain GAS back
to the user. Address of the Processing contract is uses as the first signer in to the user. The address of the Processing contract is used as the first signer in
the multi signature transaction. Therefore NeoVM executes Verify method of the the multisignature transaction. Therefore, NeoVM executes Verify method of the
contract and if invocation is verified, then Processing contract pays for the contract and if invocation is verified, Processing contract pays for the
execution. execution.
Contract notifications Contract notifications

View file

@ -48,8 +48,8 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("processing contract initialized") runtime.Log("processing contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by side chain committee. // only by the sidechain committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
blockHeight := ledger.CurrentIndex() blockHeight := ledger.CurrentIndex()
alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1)) alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1))
@ -64,7 +64,7 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("processing contract updated") runtime.Log("processing contract updated")
} }
// Verify method returns true if transaction contains valid multi signature of // Verify method returns true if transaction contains valid multisignature of
// Alphabet nodes of the Inner Ring. // Alphabet nodes of the Inner Ring.
func Verify() bool { func Verify() bool {
ctx := storage.GetContext() ctx := storage.GetContext()
@ -74,7 +74,7 @@ func Verify() bool {
return runtime.CheckWitness(multiaddr) return runtime.CheckWitness(multiaddr)
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -1,18 +1,18 @@
/* /*
Proxy contract is a contract deployed in NeoFS side chain. Proxy contract is a contract deployed in NeoFS sidechain.
Proxy contract pays for all multi signature transaction executions when notary Proxy contract pays for all multisignature transaction executions when notary
service enabled in side chain. Notary service prepares multi signed transaction, service is enabled in the sidechain. Notary service prepares multisigned transactions,
however they should contain side chain GAS to be executed. It is inconvenient to however they should contain sidechain GAS to be executed. It is inconvenient to
ask Alphabet nodes to pay for these transactions: nodes can change over time, ask Alphabet nodes to pay for these transactions: nodes can change over time,
some nodes will spend side chain GAS faster, it creates economic instability. some nodes will spend sidechain GAS faster. It leads to economic instability.
Proxy contract exists to solve this issue. While Alphabet contracts hold all Proxy contract exists to solve this issue. While Alphabet contracts hold all
side chain NEO, proxy contract holds most of the side chain GAS. Alphabet sidechain NEO, proxy contract holds most of the sidechain GAS. Alphabet
contracts emits half of the available GAS to the proxy contract. Address of the contracts emit half of the available GAS to the proxy contract. The address of the
Proxy contract is used as the first signer in the multi signature transaction. Proxy contract is used as the first signer in a multisignature transaction.
Therefore NeoVM executes Verify method of the contract and if invocation is Therefore, NeoVM executes Verify method of the contract; and if invocation is
verified, then Proxy contract pays for the execution. verified, Proxy contract pays for the execution.
Contract notifications Contract notifications

View file

@ -28,7 +28,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("proxy contract initialized") runtime.Log("proxy contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -40,7 +40,7 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("proxy contract updated") runtime.Log("proxy contract updated")
} }
// Verify method returns true if transaction contains valid multi signature of // Verify method returns true if transaction contains valid multisignature of
// Alphabet nodes of the Inner Ring. // Alphabet nodes of the Inner Ring.
func Verify() bool { func Verify() bool {
alphabet := neo.GetCommittee() alphabet := neo.GetCommittee()
@ -54,7 +54,7 @@ func Verify() bool {
return true return true
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -1,14 +1,14 @@
/* /*
Reputation contract is a contract deployed in NeoFS side chain. Reputation contract is a contract deployed in NeoFS sidechain.
Inner Ring nodes produce data audit for each container in each epoch. In the end Inner Ring nodes produce data audit for each container during each epoch. In the end,
nodes produce DataAuditResult structure that contains information about audit nodes produce DataAuditResult structure that contains information about audit
progress. Reputation contract provides storage for such structures and simple progress. Reputation contract provides storage for such structures and simple
interface to iterate over available DataAuditResults on specified epoch. interface to iterate over available DataAuditResults on specified epoch.
During settlement process, Alphabet nodes fetch all DataAuditResult structures During settlement process, Alphabet nodes fetch all DataAuditResult structures
from the epoch and execute balance transfers from data owners to Storage and from the epoch and execute balance transfers from data owners to Storage and
Inner Ring nodes, if data audit succeed. Inner Ring nodes if data audit succeeds.
Contract notifications Contract notifications

View file

@ -40,7 +40,7 @@ func _deploy(data interface{}, isUpdate bool) {
runtime.Log("reputation contract initialized") runtime.Log("reputation contract initialized")
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -52,12 +52,12 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("reputation contract updated") runtime.Log("reputation contract updated")
} }
// Put method saves DataAuditResult in contract storage. Can be invoked only by // Put method saves DataAuditResult in contract storage. It can be invoked only by
// Inner Ring nodes. Does not require multi signature invocations. // Inner Ring nodes. It does not require multisignature invocations.
// //
// Epoch is an epoch number when DataAuditResult structure was generated. // Epoch is the epoch number when DataAuditResult structure was generated.
// PeerID contains public keys of Inner Ring node that produced DataAuditResult. // PeerID contains public keys of the Inner Ring node that has produced DataAuditResult.
// Value contains stable marshaled structure of DataAuditResult. // Value contains a stable marshaled structure of DataAuditResult.
func Put(epoch int, peerID []byte, value []byte) { func Put(epoch int, peerID []byte, value []byte) {
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
@ -108,15 +108,15 @@ func Put(epoch int, peerID []byte, value []byte) {
storage.Put(ctx, key, value) storage.Put(ctx, key, value)
} }
// Get method returns list of all stable marshaled DataAuditResult structures // Get method returns a list of all stable marshaled DataAuditResult structures
// produced by specified Inner Ring node in specified epoch. // produced by the specified Inner Ring node during the specified epoch.
func Get(epoch int, peerID []byte) [][]byte { func Get(epoch int, peerID []byte) [][]byte {
id := storageID(epoch, peerID) id := storageID(epoch, peerID)
return GetByID(id) return GetByID(id)
} }
// GetByID method returns list of all stable marshaled DataAuditResult with // GetByID method returns a list of all stable marshaled DataAuditResult with
// specified id. Use ListByEpoch method to obtain id. // the specified id. Use ListByEpoch method to obtain the id.
func GetByID(id []byte) [][]byte { func GetByID(id []byte) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -133,7 +133,7 @@ func getReputationKey(prefix byte, id []byte) []byte {
return append([]byte{prefix}, id...) return append([]byte{prefix}, id...)
} }
// ListByEpoch returns list of IDs that may be used to get reputation data // ListByEpoch returns a list of IDs that may be used to get reputation data
// with GetByID method. // with GetByID method.
func ListByEpoch(epoch int) [][]byte { func ListByEpoch(epoch int) [][]byte {
ctx := storage.GetReadOnlyContext() ctx := storage.GetReadOnlyContext()
@ -150,7 +150,7 @@ func ListByEpoch(epoch int) [][]byte {
return result return result
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -1,13 +1,13 @@
/* /*
Subnet contract is a contract deployed in NeoFS side chain. Subnet contract is a contract deployed in NeoFS sidechain.
Subnet contract stores and manages NeoFS subnetwork states. It allows registering 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 and deleting subnetworks, limiting access to them, and defining a list of the Storage
Nodes that can be included in them. Nodes that can be included in them.
Contract notifications Contract notifications
Put notification. This notification is produced when new subnetwork is Put notification. This notification is produced when a new subnetwork is
registered by invoking Put method. registered by invoking Put method.
Put Put

View file

@ -71,7 +71,7 @@ func _deploy(data interface{}, isUpdate bool) {
storage.Put(ctx, []byte{notaryDisabledKey}, args.notaryDisabled) storage.Put(ctx, []byte{notaryDisabledKey}, args.notaryDisabled)
} }
// Update method updates contract source code and manifest. Can be invoked // Update method updates contract source code and manifest. It can be invoked
// only by committee. // only by committee.
func Update(script []byte, manifest []byte, data interface{}) { func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() { if !common.HasUpdateAccess() {
@ -83,7 +83,7 @@ func Update(script []byte, manifest []byte, data interface{}) {
runtime.Log("subnet contract updated") runtime.Log("subnet contract updated")
} }
// Put creates new subnet with the specified owner and info. // Put creates a new subnet with the specified owner and info.
func Put(id []byte, ownerKey interop.PublicKey, info []byte) { func Put(id []byte, ownerKey interop.PublicKey, info []byte) {
// V2 format // V2 format
if len(id) != subnetIDSize { if len(id) != subnetIDSize {
@ -129,7 +129,7 @@ func Put(id []byte, ownerKey interop.PublicKey, info []byte) {
storage.Put(ctx, stKey, info) storage.Put(ctx, stKey, info)
} }
// Get returns info about subnet with the specified id. // Get returns info about the subnet with the specified id.
func Get(id []byte) []byte { func Get(id []byte) []byte {
// V2 format // V2 format
if len(id) != subnetIDSize { if len(id) != subnetIDSize {
@ -145,7 +145,7 @@ func Get(id []byte) []byte {
return raw.([]byte) return raw.([]byte)
} }
// Delete deletes subnet with the specified id. // Delete deletes the subnet with the specified id.
func Delete(id []byte) { func Delete(id []byte) {
// V2 format // V2 format
if len(id) != subnetIDSize { if len(id) != subnetIDSize {
@ -182,7 +182,7 @@ func Delete(id []byte) {
runtime.Notify("Delete", id) runtime.Notify("Delete", id)
} }
// AddNodeAdmin adds new node administrator to the specified subnetwork. // AddNodeAdmin adds a new node administrator to the specified subnetwork.
func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) { func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
// V2 format // V2 format
if len(subnetID) != subnetIDSize { if len(subnetID) != subnetIDSize {
@ -215,7 +215,7 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
} }
// RemoveNodeAdmin removes node administrator from the specified subnetwork. // RemoveNodeAdmin removes node administrator from the specified subnetwork.
// Must be called by subnet owner only. // Must be called by the subnet owner only.
func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) { func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
// V2 format // V2 format
if len(subnetID) != subnetIDSize { if len(subnetID) != subnetIDSize {
@ -247,8 +247,8 @@ func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
deleteKeyFromList(ctx, adminKey, stKey) deleteKeyFromList(ctx, adminKey, stKey)
} }
// AddNode adds node to the specified subnetwork. // AddNode adds a node to the specified subnetwork.
// Must be called by subnet's owner or node administrator // Must be called by the subnet's owner or the node administrator
// only. // only.
func AddNode(subnetID []byte, node interop.PublicKey) { func AddNode(subnetID []byte, node interop.PublicKey) {
// V2 format // V2 format
@ -286,8 +286,8 @@ func AddNode(subnetID []byte, node interop.PublicKey) {
putKeyInList(ctx, node, stKey) putKeyInList(ctx, node, stKey)
} }
// RemoveNode removes node from the specified subnetwork. // RemoveNode removes a node from the specified subnetwork.
// Must be called by subnet's owner or node administrator // Must be called by the subnet's owner or the node administrator
// only. // only.
func RemoveNode(subnetID []byte, node interop.PublicKey) { func RemoveNode(subnetID []byte, node interop.PublicKey) {
// V2 format // V2 format
@ -327,8 +327,8 @@ func RemoveNode(subnetID []byte, node interop.PublicKey) {
runtime.Notify("RemoveNode", subnetID, node) runtime.Notify("RemoveNode", subnetID, node)
} }
// NodeAllowed checks if node is included in the // NodeAllowed checks if a node is included in the
// specified subnet or not. // specified subnet.
func NodeAllowed(subnetID []byte, node interop.PublicKey) bool { func NodeAllowed(subnetID []byte, node interop.PublicKey) bool {
// V2 format // V2 format
if len(subnetID) != subnetIDSize { if len(subnetID) != subnetIDSize {
@ -353,8 +353,8 @@ func NodeAllowed(subnetID []byte, node interop.PublicKey) bool {
return storage.Get(ctx, append(stKey, node...)) != nil return storage.Get(ctx, append(stKey, node...)) != nil
} }
// AddClientAdmin adds new client administrator of the specified group in the specified subnetwork. // AddClientAdmin adds a new client administrator of the specified group in the specified subnetwork.
// Must be called by owner only. // Must be called by the owner only.
func AddClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) { func AddClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) {
// V2 format // V2 format
if len(subnetID) != subnetIDSize { if len(subnetID) != subnetIDSize {
@ -394,7 +394,7 @@ func AddClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.Publ
// RemoveClientAdmin removes client administrator from the // RemoveClientAdmin removes client administrator from the
// specified group in the specified subnetwork. // specified group in the specified subnetwork.
// Must be called by owner only. // Must be called by the owner only.
func RemoveClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) { func RemoveClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) {
// V2 format // V2 format
if len(subnetID) != subnetIDSize { if len(subnetID) != subnetIDSize {
@ -477,7 +477,7 @@ func AddUser(subnetID []byte, groupID []byte, userID []byte) {
putKeyInList(ctx, userID, stKey) putKeyInList(ctx, userID, stKey)
} }
// RemoveUser removes user from the specified subnetwork and group. // RemoveUser removes a user from the specified subnetwork and group.
// Must be called by the owner or the group's admin only. // Must be called by the owner or the group's admin only.
func RemoveUser(subnetID []byte, groupID []byte, userID []byte) { func RemoveUser(subnetID []byte, groupID []byte, userID []byte) {
// V2 format // V2 format
@ -522,8 +522,8 @@ func RemoveUser(subnetID []byte, groupID []byte, userID []byte) {
deleteKeyFromList(ctx, userID, stKey) deleteKeyFromList(ctx, userID, stKey)
} }
// UserAllowed returns bool that indicates if node is included in the // UserAllowed returns bool that indicates if a node is included in the
// specified subnet or not. // specified subnet.
func UserAllowed(subnetID []byte, user []byte) bool { func UserAllowed(subnetID []byte, user []byte) bool {
// V2 format // V2 format
if len(subnetID) != subnetIDSize { if len(subnetID) != subnetIDSize {
@ -551,7 +551,7 @@ func UserAllowed(subnetID []byte, user []byte) bool {
return false return false
} }
// Version returns version of the contract. // Version returns the version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }

View file

@ -112,7 +112,7 @@ func TestVote(t *testing.T) {
c.Invoke(t, stackitem.Null{}, method, int64(0), []interface{}{newAlphabetPub}) c.Invoke(t, stackitem.Null{}, method, int64(0), []interface{}{newAlphabetPub})
// wait one block util // wait one block util
// new committee is accepted // a new committee is accepted
c.AddNewBlock(t) c.AddNewBlock(t)
cNewAlphabet.Invoke(t, stackitem.Null{}, "emit") cNewAlphabet.Invoke(t, stackitem.Null{}, "emit")