Drop notaryless deploy parameter #50

Merged
fyrchik merged 4 commits from fyrchik/frostfs-contract:fix-remove-notary-disabled into master 2023-11-08 10:50:26 +00:00
41 changed files with 213 additions and 1097 deletions

View File

@ -22,7 +22,7 @@ all: sidechain mainnet
sidechain: alphabet morph nns
alphabet_sc = alphabet
morph_sc = audit balance container frostfsid netmap proxy reputation policy
morph_sc = balance container frostfsid netmap proxy policy
mainnet_sc = frostfs processing
nns_sc = nns
all_sc = $(alphabet_sc) $(morph_sc) $(mainnet_sc) $(nns_sc)
@ -64,6 +64,18 @@ generate-wrappers: build $(foreach sc,$(all_sc),generate-wrapper.$(sc))
test:
@go test ./tests/...
# Run all code formatters
fmts: fumpt imports
# Reformat imports
imports:
@echo "⇒ Processing goimports check"
@goimports -w $(all_sc) tests/
fumpt:
@echo "⇒ Processing gofumpt check"
@gofumpt -l -w $(all_sc) tests/
clean:
find . -name '*.nef' -exec rm -rf {} \;
find . -name 'config.json' -exec rm -rf {} \;

View File

@ -18,38 +18,32 @@ const (
indexKey = "index"
totalKey = "threshold"
nameKey = "name"
notaryDisabledKey = "notary"
)
// OnNEP17Payment is a callback for NEP-17 compatible native GAS and NEO
// contracts.
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
caller := runtime.GetCallingScriptHash()
if !common.BytesEqual(caller, []byte(gas.Hash)) && !common.BytesEqual(caller, []byte(neo.Hash)) {
common.AbortWithMessage("alphabet contract accepts GAS and NEO only")
}
}
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
args := data.(struct {
//TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrNetmap interop.Hash160
addrProxy interop.Hash160
name string
index int
total int
addrNetmap interop.Hash160
addrProxy interop.Hash160
name string
index int
total int
})
if len(args.addrNetmap) != interop.Hash160Len || len(args.addrProxy) != interop.Hash160Len {
@ -67,7 +61,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}

View File

@ -20,13 +20,12 @@ Alphabet contract does not produce notifications to process.
# Contract storage scheme
| Key | Value | Description |
|--------------------|------------|-------------------------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| `proxyScriptHash` | Hash160 | proxy contract hash |
| `name` | string | assigned glagolitic letter |
| `index` | int | the index of deployed alphabet contract |
| `threshold` | int | the total number of deployed alphabet contracts |
| Key | Value | Description |
|--------------------|------------|-------------------------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| `proxyScriptHash` | Hash160 | proxy contract hash |
| `name` | string | assigned glagolitic letter |
| `index` | int | the index of deployed alphabet contract |
| `threshold` | int | the total number of deployed alphabet contracts |
*/
package alphabet

View File

@ -1,226 +0,0 @@
package audit
import (
"git.frostfs.info/TrueCloudLab/frostfs-contract/common"
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
)
type (
auditHeader struct {
epoch int
cid []byte
from interop.PublicKey
}
)
// Audit key is a combination of the epoch, the container ID and the public key of the node that
// has executed the audit. Together, it shouldn't be more than 64 bytes. We can't shrink
// epoch and container ID since we iterate over these values. But we can shrink
// public key by using first bytes of the hashed value.
// V2 format
const maxKeySize = 24 // 24 + 32 (container ID length) + 8 (epoch length) = 64
func (a auditHeader) ID() []byte {
var buf interface{} = a.epoch
hashedKey := crypto.Sha256(a.from)
shortedKey := hashedKey[:maxKeySize]
return append(buf.([]byte), append(a.cid, shortedKey...)...)
}
const (
netmapContractKey = "netmapScriptHash"
notaryDisabledKey = "notary"
)
func _deploy(data interface{}, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
common.CheckVersion(args[len(args)-1].(int))
return
}
args := data.(struct {
//TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrNetmap interop.Hash160
})
if len(args.addrNetmap) != interop.Hash160Len {
panic("incorrect length of contract script hash")
}
storage.Put(ctx, netmapContractKey, args.addrNetmap)
runtime.Log("audit contract initialized")
}
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}
management.UpdateWithData(script, manifest, common.AppendVersion(data))
runtime.Log("audit contract updated")
}
// Put method stores a stable marshalled `DataAuditResult` structure. It can be
// invoked only by Inner Ring nodes.
//
// Inner Ring nodes perform audit of containers and produce `DataAuditResult`
// structures. They are stored in audit contract and used for settlements
// in later epochs.
func Put(rawAuditResult []byte) {
ctx := storage.GetContext()
innerRing := common.InnerRingNodes()
hdr := newAuditHeader(rawAuditResult)
presented := false
for i := range innerRing {
ir := innerRing[i]
if common.BytesEqual(ir, hdr.from) {
presented = true
break
}
}
if !runtime.CheckWitness(hdr.from) || !presented {
panic("put access denied")
}
storage.Put(ctx, hdr.ID(), rawAuditResult)
runtime.Log("audit: result has been saved")
}
// Get method returns a stable marshaled DataAuditResult structure.
//
// The ID of the DataAuditResult can be obtained from listing methods.
func Get(id []byte) []byte {
ctx := storage.GetReadOnlyContext()
return storage.Get(ctx, id).([]byte)
}
// List method returns a list of all available DataAuditResult IDs from
// the contract storage.
func List() [][]byte {
ctx := storage.GetReadOnlyContext()
it := storage.Find(ctx, []byte{}, storage.KeysOnly)
return list(it)
}
// ListByEpoch method returns a list of DataAuditResult IDs generated during
// the specified epoch.
func ListByEpoch(epoch int) [][]byte {
ctx := storage.GetReadOnlyContext()
var buf interface{} = epoch
it := storage.Find(ctx, buf.([]byte), storage.KeysOnly)
return list(it)
}
// ListByCID method returns a list of DataAuditResult IDs generated during
// the specified epoch for the specified container.
func ListByCID(epoch int, cid []byte) [][]byte {
ctx := storage.GetReadOnlyContext()
var buf interface{} = epoch
prefix := append(buf.([]byte), cid...)
it := storage.Find(ctx, prefix, storage.KeysOnly)
return list(it)
}
// ListByNode method returns a list of DataAuditResult IDs generated in
// the specified epoch for the specified container by the specified Inner Ring node.
func ListByNode(epoch int, cid []byte, key interop.PublicKey) [][]byte {
ctx := storage.GetReadOnlyContext()
hdr := auditHeader{
epoch: epoch,
cid: cid,
from: key,
}
it := storage.Find(ctx, hdr.ID(), storage.KeysOnly)
return list(it)
}
func list(it iterator.Iterator) [][]byte {
var result [][]byte
ignore := [][]byte{
[]byte(netmapContractKey),
}
loop:
for iterator.Next(it) {
key := iterator.Value(it).([]byte) // iterator MUST BE `storage.KeysOnly`
for _, ignoreKey := range ignore {
if common.BytesEqual(key, ignoreKey) {
continue loop
}
}
result = append(result, key)
}
return result
}
// Version returns the version of the contract.
func Version() int {
return common.Version
}
// readNext reads the length from the first byte, and then reads data (max 127 bytes).
func readNext(input []byte) ([]byte, int) {
var buf interface{} = input[0]
ln := buf.(int)
return input[1 : 1+ln], 1 + ln
}
func newAuditHeader(input []byte) auditHeader {
// V2 format
offset := int(input[1])
offset = 2 + offset + 1 // version prefix + version len + epoch prefix
var buf interface{} = input[offset : offset+8] // [ 8 integer bytes ]
epoch := buf.(int)
offset = offset + 8
// cid is a nested structure with raw bytes
// [ cid struct prefix (wireType + len = 2 bytes), cid value wireType (1 byte), ... ]
cid, cidOffset := readNext(input[offset+2+1:])
// key is a raw byte
// [ public key wireType (1 byte), ... ]
key, _ := readNext(input[offset+2+1+cidOffset+1:])
return auditHeader{
epoch,
cid,
key,
}
}

View File

@ -1,4 +0,0 @@
name: "Audit"
safemethods: ["get", "list", "listByEpoch", "listByCID", "listByNode", "version"]
permissions:
- methods: ["update"]

View File

@ -1,30 +0,0 @@
/*
Audit contract is a contract deployed in FrostFS sidechain.
Inner Ring nodes perform audit of the registered containers during every epoch.
If a container contains StorageGroup objects, an Inner Ring node initializes
a series of audit checks. Based on the results of these checks, the Inner Ring
node creates a DataAuditResult structure for the container. The content of this
structure makes it possible to determine which storage nodes have been examined and
see the status of these checks. Regarding this information, the container owner is
charged for data storage.
Audit contract is used as a reliable and verifiable storage for all
DataAuditResult structures. At the end of data audit routine, Inner Ring
nodes send a stable marshaled version of the DataAuditResult structure to the
contract. When Alphabet nodes of the Inner Ring perform settlement operations,
they make a list and get these AuditResultStructures from the audit contract.
# Contract notifications
Audit contract does not produce notifications to process.
# Contract storage scheme
| Key | Value | Description |
|--------------------|------------|-----------------------------------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| auditID | ByteArray | serialized DataAuditResult structure |
*/
package audit

View File

@ -47,7 +47,6 @@ const (
netmapContractKey = "netmapScriptHash"
containerContractKey = "containerScriptHash"
notaryDisabledKey = "notary"
)
var token Token
@ -64,22 +63,18 @@ func init() {
token = createToken()
}
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
args := data.(struct {
// TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrNetmap interop.Hash160
addrContainer interop.Hash160
addrNetmap interop.Hash160
addrContainer interop.Hash160
})
if len(args.addrNetmap) != interop.Hash160Len || len(args.addrContainer) != interop.Hash160Len {
@ -94,7 +89,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}
@ -133,7 +128,7 @@ func BalanceOf(account interop.Hash160) int {
//
// It produces Transfer and TransferX notifications. TransferX notification
// will have empty details field.
func Transfer(from, to interop.Hash160, amount int, data interface{}) bool {
func Transfer(from, to interop.Hash160, amount int, data any) bool {
ctx := storage.GetContext()
return token.transfer(ctx, from, to, amount, false, nil)
}
@ -335,9 +330,7 @@ func (t Token) transfer(ctx storage.Context, from, to interop.Hash160, amount in
// canTransfer returns the amount it can transfer.
func (t Token) canTransfer(ctx storage.Context, from, to interop.Hash160, amount int, innerRing bool) (Account, bool) {
var (
emptyAcc = Account{}
)
emptyAcc := Account{}
if !innerRing {
if len(to) != interop.Hash160Len || !isUsableAddress(from) {
@ -375,7 +368,7 @@ func isUsableAddress(addr interop.Hash160) bool {
return false
}
func getAccount(ctx storage.Context, key interface{}) Account {
func getAccount(ctx storage.Context, key any) Account {
data := storage.Get(ctx, key)
if data != nil {
acc := std.Deserialize(data.([]byte)).(account)
@ -389,7 +382,7 @@ func getAccount(ctx storage.Context, key interface{}) Account {
return Account{}
}
func setAccount(ctx storage.Context, key interface{}, acc Account) {
func setAccount(ctx storage.Context, key any, acc Account) {
common.SetSerialized(ctx, key, account{
Balance: common.ToFixedWidth64(acc.Balance),
Until: common.ToFixedWidth64(acc.Until),

View File

@ -77,11 +77,10 @@ when FrostFS contract has transferred GAS assets back to the user.
# Contract storage scheme
| Key | Value | Description |
|-----------------------|------------|----------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| `containerScriptHash` | Hash160 | container contract hash |
| circulationKey | int | the token circulation key value |
| Key | Value | Description |
|-----------------------|------------|----------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| `containerScriptHash` | Hash160 | container contract hash |
| circulationKey | int | the token circulation key value |
*/
package balance

View File

@ -1,26 +1,11 @@
package common
import (
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util"
)
const (
panicMsgForNotaryDisabledEnv = "contract not applicable for notary-disabled environment"
)
// BytesEqual compares two slices of bytes by wrapping them into strings,
// which is necessary with new util.Equals interop behaviour, see neo-go#1176.
func BytesEqual(a []byte, b []byte) bool {
return util.Equals(string(a), string(b))
}
// RmAndCheckNotaryDisabledKey remove notary disabled key from storage and
// panic in notary disabled environment
func RmAndCheckNotaryDisabledKey(data interface{}, key interface{}) {
//TODO(@acid-ant): #9 remove notaryDisabled from args in future version
storage.Delete(storage.GetContext(), key)
if data.([]interface{})[0].(bool) {
panic(panicMsgForNotaryDisabledEnv)
}
}

View File

@ -7,7 +7,7 @@ import (
)
// SetSerialized serializes data and puts it into contract storage.
func SetSerialized(ctx storage.Context, key interface{}, value interface{}) {
func SetSerialized(ctx storage.Context, key any, value interface{}) {
data := std.Serialize(value)
storage.Put(ctx, key, data)
}

View File

@ -31,7 +31,7 @@ func LockTransferDetails(txDetails []byte) []byte {
}
func UnlockTransferDetails(epoch int) []byte {
var buf interface{} = epoch
var buf any = epoch
return append(unlockPrefix, buf.([]byte)...)
}

View File

@ -38,9 +38,9 @@ func CheckVersion(from int) {
}
// AppendVersion appends current contract version to the list of deploy arguments.
func AppendVersion(data interface{}) []interface{} {
func AppendVersion(data any) []interface{} {
if data == nil {
return []interface{}{Version}
return []any{Version}
}
return append(data.([]interface{}), Version)
return append(data.([]any), Version)
}

View File

@ -50,7 +50,6 @@ const (
nnsContractKey = "nnsScriptHash"
nnsRootKey = "nnsRoot"
nnsHasAliasKey = "nnsHasAlias"
notaryDisabledKey = "notary"
// RegistrationFeeKey is a key in netmap config which contains fee for container registration.
RegistrationFeeKey = "ContainerFee"
@ -83,21 +82,17 @@ const (
defaultTTL = 3600 // 1 hour
)
var (
eACLPrefix = []byte("eACL")
)
var eACLPrefix = []byte("eACL")
// OnNEP11Payment is needed for registration with contract as the owner to work.
func OnNEP11Payment(a interop.Hash160, b int, c []byte, d interface{}) {
func OnNEP11Payment(a interop.Hash160, b int, c []byte, d any) {
}
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
it := storage.Find(ctx, []byte{}, storage.None)
@ -123,13 +118,11 @@ func _deploy(data interface{}, isUpdate bool) {
}
args := data.(struct {
//TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrNetmap interop.Hash160
addrBalance interop.Hash160
addrID interop.Hash160
addrNNS interop.Hash160
nnsRoot string
addrNetmap interop.Hash160
addrBalance interop.Hash160
addrID interop.Hash160
addrNNS interop.Hash160
nnsRoot string
})
if len(args.addrNetmap) != interop.Hash160Len ||
@ -167,7 +160,7 @@ func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) {
// Update method updates contract source code and manifest. It can be invoked
// by committee only.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}
@ -192,7 +185,8 @@ func Put(container []byte, signature interop.Signature, publicKey interop.Public
// Note that zone must exist.
func PutNamed(container []byte, signature interop.Signature,
publicKey interop.PublicKey, token []byte,
name, zone string) {
name, zone string,
) {
ctx := storage.GetContext()
ownerID := ownerFromBinaryContainer(container)
@ -329,7 +323,7 @@ func Delete(containerID []byte, signature interop.Signature, publicKey interop.P
// and inability to delete a container. We should also check if we own the record in case.
nnsContractAddr := storage.Get(ctx, nnsContractKey).(interop.Hash160)
res := contract.Call(nnsContractAddr, "getRecords", contract.ReadStates|contract.AllowCall, domain, 16 /* TXT */)
if res != nil && std.Base58Encode(containerID) == string(res.([]interface{})[0].(string)) {
if res != nil && std.Base58Encode(containerID) == string(res.([]any)[0].(string)) {
contract.Call(nnsContractAddr, "deleteRecords", contract.All, domain, 16 /* TXT */)
}
}
@ -546,7 +540,7 @@ func GetContainerSize(id []byte) containerSizes {
func ListContainerSizes(epoch int) [][]byte {
ctx := storage.GetReadOnlyContext()
var buf interface{} = epoch
var buf any = epoch
key := []byte(estimateKeyPrefix)
key = append(key, buf.([]byte)...)
@ -578,7 +572,7 @@ func ListContainerSizes(epoch int) [][]byte {
func IterateContainerSizes(epoch int) iterator.Iterator {
ctx := storage.GetReadOnlyContext()
var buf interface{} = epoch
var buf any = epoch
key := []byte(estimateKeyPrefix)
key = append(key, buf.([]byte)...)
@ -696,7 +690,7 @@ func ownerFromBinaryContainer(container []byte) []byte {
}
func estimationKey(epoch int, cid []byte, key interop.PublicKey) []byte {
var buf interface{} = epoch
var buf any = epoch
hash := crypto.Ripemd160(key)
@ -774,7 +768,7 @@ func cleanupContainers(ctx storage.Context, epoch int) {
// V2 format
nbytes := k[len(estimateKeyPrefix) : len(k)-containerIDSize-estimatePostfixSize]
var n interface{} = nbytes
var n any = nbytes
if epoch-n.(int) > TotalCleanupDelta {
storage.Delete(ctx, k)

View File

@ -26,19 +26,17 @@ it in Container contract.
# Contract storage scheme
| Key | Value | Description |
|-----------------------------------------------------------------------------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| `balanceScriptHash` | Hash160 | balance contract hash |
| `identityScriptHash` | Hash160 | frostfsID contract hash |
| `nnsContractKey` | Hash160 | nns contract hash |
| `nnsRoot` | string | default value for domain zone |
| `cnr` + epoch + containerID + publicKeyHash[:10] | ByteArray | estimated container size |
| `est` + containerID + publicKeyHash | ByteArray | serialized epochs array |
| `o` + ownerID + containerID | ByteArray | container ID |
| `x` + containerID | ByteArray | serialized container struct |
| `nnsHasAlias` + containerID | string | domain name |
| Key | Value | Description |
|-----------------------------------------------------------------------------------------------------|
| `netmapScriptHash` | Hash160 | netmap contract hash |
| `balanceScriptHash` | Hash160 | balance contract hash |
| `identityScriptHash` | Hash160 | frostfsID contract hash |
| `nnsContractKey` | Hash160 | nns contract hash |
| `nnsRoot` | string | default value for domain zone |
| `cnr` + epoch + containerID + publicKeyHash[:10] | ByteArray | estimated container size |
| `est` + containerID + publicKeyHash | ByteArray | serialized epochs array |
| `o` + ownerID + containerID | ByteArray | container ID |
| `x` + containerID | ByteArray | serialized container struct |
| `nnsHasAlias` + containerID | string | domain name |
*/
package container

View File

@ -83,12 +83,10 @@ FrostFS network configuration value.
# Contract storage scheme
| Key | Value | Description |
|-----------------------------------------------------------------------------|
| `processingScriptHash` | Hash160 | processing contract hash |
| `candidates` + candidateKey | ByteArray | it flags inner ring candidate |
| `config` + postfix | ByteArray | serialized config data |
| Key | Value | Description |
|-----------------------------------------------------------------------------|
| `processingScriptHash` | Hash160 | processing contract hash |
| `candidates` + candidateKey | ByteArray | it flags inner ring candidate |
| `config` + postfix | ByteArray | serialized config data |
*/
package frostfs

View File

@ -26,9 +26,8 @@ const (
CandidateFeeConfigKey = "InnerRingCandidateFee"
withdrawFeeConfigKey = "WithdrawFee"
alphabetKey = "alphabet"
candidatesKey = "candidates"
notaryDisabledKey = "notary"
alphabetKey = "alphabet"
candidatesKey = "candidates"
processingContractKey = "processingScriptHash"
@ -39,28 +38,22 @@ const (
ignoreDepositNotification = "\x57\x0b"
)
var (
configPrefix = []byte("config")
)
var configPrefix = []byte("config")
// _deploy sets up initial alphabet node keys.
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
args := data.(struct {
//TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrProc interop.Hash160
keys []interop.PublicKey
config [][]byte
addrProc interop.Hash160
keys []interop.PublicKey
config [][]byte
})
if len(args.keys) == 0 {
@ -100,7 +93,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by sidechain committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
blockHeight := ledger.CurrentIndex()
alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1))
alphabetCommittee := common.Multiaddress(alphabetKeys, true)
@ -190,7 +183,7 @@ func InnerRingCandidateAdd(key interop.PublicKey) {
// It takes no more than 9000.0 GAS. Native GAS has precision 8, and
// FrostFS balance contract has precision 12. Values bigger than 9000.0 can
// break JSON limits for integers when precision is converted.
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
rcv := data.(interop.Hash160)
if common.BytesEqual(rcv, []byte(ignoreDepositNotification)) {
return
@ -321,7 +314,7 @@ func Unbind(user []byte, keys []interop.PublicKey) {
// Config returns configuration value of FrostFS configuration. If the key does
// not exists, returns nil.
func Config(key []byte) interface{} {
func Config(key []byte) any {
ctx := storage.GetReadOnlyContext()
return getConfig(ctx, key)
}
@ -376,7 +369,7 @@ func getAlphabetNodes(ctx storage.Context) []interop.PublicKey {
}
// getConfig returns the installed frostfs configuration value or nil if it is not set.
func getConfig(ctx storage.Context, key interface{}) interface{} {
func getConfig(ctx storage.Context, key any) interface{} {
postfix := key.([]byte)
storageKey := append(configPrefix, postfix...)
@ -384,7 +377,7 @@ func getConfig(ctx storage.Context, key interface{}) interface{} {
}
// setConfig sets a frostfs configuration value in the contract storage.
func setConfig(ctx storage.Context, key, val interface{}) {
func setConfig(ctx storage.Context, key, val any) {
postfix := key.([]byte)
storageKey := append(configPrefix, postfix...)

View File

@ -19,11 +19,10 @@ FrostFSID contract does not produce notifications to process.
# Contract storage scheme
| Key | Value | Description |
|-----------------------------|------------|----------------------------------|
| `processingScriptHash` | Hash160 | netmap contract hash |
| `containerScriptHash` | Hash160 | container contract hash |
| `o` + ownerID + publicKey | ByteArray | it flags owner's public key |
| Key | Value | Description |
|-----------------------------|------------|----------------------------------|
| `processingScriptHash` | Hash160 | netmap contract hash |
| `containerScriptHash` | Hash160 | container contract hash |
| `o` + ownerID + publicKey | ByteArray | it flags owner's public key |
*/
package frostfsid

View File

@ -22,26 +22,21 @@ const (
const (
netmapContractKey = "netmapScriptHash"
containerContractKey = "containerScriptHash"
notaryDisabledKey = "notary"
ownerKeysPrefix = 'o'
)
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
args := data.(struct {
//TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrNetmap interop.Hash160
addrContainer interop.Hash160
addrNetmap interop.Hash160
addrContainer interop.Hash160
})
if len(args.addrNetmap) != interop.Hash160Len || len(args.addrContainer) != interop.Hash160Len {
@ -56,7 +51,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}
@ -148,7 +143,7 @@ func Version() int {
return common.Version
}
func getUserInfo(ctx storage.Context, key interface{}) UserInfo {
func getUserInfo(ctx storage.Context, key any) UserInfo {
it := storage.Find(ctx, key, storage.KeysOnly|storage.RemovePrefix)
pubs := [][]byte{}
for iterator.Next(it) {

View File

@ -32,15 +32,14 @@ in the network by invoking NewEpoch method.
# Contract storage scheme
| Key | Value | Description |
|-----------------------------|------------|-----------------------------------|
| `snapshotCount` | int | snapshot count |
| `snapshotEpoch` | int | snapshot epoch |
| `snapshotBlock` | int | snapshot block |
| `snapshot_` + snapshotNum | ByteArray | serialized '[]Node' array |
| `snapshotCurrent` | int | current snapshot |
| `balanceScriptHash` | Hash160 | balance contract hash |
| `containerScriptHash` | Hash160 | container contract hash |
| Key | Value | Description |
|-----------------------------|------------|-----------------------------------|
| `snapshotCount` | int | snapshot count |
| `snapshotEpoch` | int | snapshot epoch |
| `snapshotBlock` | int | snapshot block |
| `snapshot_` + snapshotNum | ByteArray | serialized '[]Node' array |
| `snapshotCurrent` | int | current snapshot |
| `balanceScriptHash` | Hash160 | balance contract hash |
| `containerScriptHash` | Hash160 | container contract hash |
*/
package netmap

View File

@ -43,8 +43,7 @@ type Node struct {
}
const (
notaryDisabledKey = "notary"
innerRingKey = "innerring"
innerRingKey = "innerring"
// DefaultSnapshotCount contains the number of previous snapshots stored by this contract.
// Must be less than 255.
@ -67,19 +66,15 @@ var (
)
// _deploy function sets up initial list of inner ring public keys.
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
ctx := storage.GetContext()
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
var args = data.(struct {
//TODO(@acid-ant): #9 remove notaryDisabled in future version
notaryDisabled bool
addrBalance interop.Hash160
addrContainer interop.Hash160
keys []interop.PublicKey
config [][]byte
version int
args := data.(struct {
addrBalance interop.Hash160
addrContainer interop.Hash160
keys []interop.PublicKey
config [][]byte
version int
})
ln := len(args.config)
@ -122,7 +117,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}
@ -431,7 +426,7 @@ func SnapshotByEpoch(epoch int) []Node {
// Config returns configuration value of FrostFS configuration. If key does
// not exists, returns nil.
func Config(key []byte) interface{} {
func Config(key []byte) any {
ctx := storage.GetReadOnlyContext()
return getConfig(ctx, key)
}
@ -543,14 +538,14 @@ func getSnapshot(ctx storage.Context, key string) []Node {
return []Node{}
}
func getConfig(ctx storage.Context, key interface{}) interface{} {
func getConfig(ctx storage.Context, key any) interface{} {
postfix := key.([]byte)
storageKey := append(configPrefix, postfix...)
return storage.Get(ctx, storageKey)
}
func setConfig(ctx storage.Context, key, val interface{}) {
func setConfig(ctx storage.Context, key, val any) {
postfix := key.([]byte)
storageKey := append(configPrefix, postfix...)

View File

@ -76,7 +76,7 @@ type RecordState struct {
}
// Update updates NameService contract.
func Update(nef []byte, manifest string, data interface{}) {
func Update(nef []byte, manifest string, data any) {
checkCommittee()
// Calculating keys and serializing requires calling
// std and crypto contracts. This can be helpful on update
@ -87,9 +87,9 @@ func Update(nef []byte, manifest string, data interface{}) {
}
// _deploy initializes defaults (total supply and registration price) on contract deploy.
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
@ -128,10 +128,10 @@ func OwnerOf(tokenID []byte) interop.Hash160 {
}
// Properties returns a domain name and an expiration date of the specified domain.
func Properties(tokenID []byte) map[string]interface{} {
func Properties(tokenID []byte) map[string]any {
ctx := storage.GetReadOnlyContext()
ns := getNameState(ctx, tokenID)
return map[string]interface{}{
return map[string]any{
"name": ns.Name,
"expiration": ns.Expiration,
}
@ -166,7 +166,7 @@ func TokensOf(owner interop.Hash160) iterator.Iterator {
}
// Transfer transfers the domain with the specified name to a new owner.
func Transfer(to interop.Hash160, tokenID []byte, data interface{}) bool {
func Transfer(to interop.Hash160, tokenID []byte, data any) bool {
if !isValid(to) {
panic(`invalid receiver`)
}
@ -478,7 +478,7 @@ func updateBalance(ctx storage.Context, tokenId []byte, acc interop.Hash160, dif
// postTransfer sends Transfer notification to the network and calls onNEP11Payment
// method.
func postTransfer(from, to interop.Hash160, tokenID []byte, data interface{}) {
func postTransfer(from, to interop.Hash160, tokenID []byte, data any) {
runtime.Notify("Transfer", from, to, 1, tokenID)
if management.GetContract(to) != nil {
contract.Call(to, "onNEP11Payment", contract.All, from, 1, tokenID, data)

View File

@ -17,7 +17,7 @@ const (
)
// _deploy function sets up initial list of inner ring public keys.
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
}
func storageKey(prefix Kind, entityName, name string) []byte {

View File

@ -21,9 +21,8 @@ Processing contract does not produce notifications to process.
# Contract storage scheme
| Key | Value | Description |
|-----------------------------|------------|----------------------------------|
| `frostfsScriptHash` | Hash160 | frostFS contract hash |
| Key | Value | Description |
|-----------------------------|------------|----------------------------------|
| `frostfsScriptHash` | Hash160 | frostFS contract hash |
*/
package processing

View File

@ -19,16 +19,16 @@ const (
)
// OnNEP17Payment is a callback for NEP-17 compatible native GAS contract.
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
caller := runtime.GetCallingScriptHash()
if !common.BytesEqual(caller, []byte(gas.Hash)) {
common.AbortWithMessage("processing contract accepts GAS only")
}
}
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
@ -50,7 +50,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by the sidechain committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
blockHeight := ledger.CurrentIndex()
alphabetKeys := roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1))
alphabetCommittee := common.Multiaddress(alphabetKeys, true)

View File

@ -21,6 +21,5 @@ Proxy contract does not produce notifications to process.
# Contract storage scheme
Proxy contract does not use storage
*/
package proxy

View File

@ -10,16 +10,16 @@ import (
)
// OnNEP17Payment is a callback for NEP-17 compatible native GAS contract.
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
caller := runtime.GetCallingScriptHash()
if !common.BytesEqual(caller, []byte(gas.Hash)) {
common.AbortWithMessage("proxy contract accepts GAS only")
}
}
func _deploy(data interface{}, isUpdate bool) {
func _deploy(data any, isUpdate bool) {
if isUpdate {
args := data.([]interface{})
args := data.([]any)
common.CheckVersion(args[len(args)-1].(int))
return
}
@ -29,7 +29,7 @@ func _deploy(data interface{}, isUpdate bool) {
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
func Update(script []byte, manifest []byte, data any) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}

View File

@ -1,13 +0,0 @@
name: "Reputation"
safemethods: ["get", "getByID", "listByEpoch"]
permissions:
- methods: ["update"]
events:
- name: reputationPut
parameters:
- name: epoch
type: Integer
- name: peerID
type: ByteArray
- name: value
type: ByteArray

View File

@ -1,25 +0,0 @@
/*
Reputation contract is a contract deployed in FrostFS sidechain.
Inner Ring nodes produce data audit for each container during each epoch. In the end,
nodes produce DataAuditResult structure that contains information about audit
progress. Reputation contract provides storage for such structures and simple
interface to iterate over available DataAuditResults on specified epoch.
During settlement process, Alphabet nodes fetch all DataAuditResult structures
from the epoch and execute balance transfers from data owners to Storage and
Inner Ring nodes if data audit succeeds.
# Contract notifications
Reputation contract does not produce notifications to process.
# Contract storage scheme
| Key | Value | Description |
|-----------------------------|------------|-----------------------------------|
| `c` + epoch + peerID | int | peer reputation count |
| `r` + count | ByteArray | serialized DataAuditResult struct |
*/
package reputation

View File

@ -1,122 +0,0 @@
package reputation
import (
"git.frostfs.info/TrueCloudLab/frostfs-contract/common"
"github.com/nspcc-dev/neo-go/pkg/interop/convert"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
)
const (
notaryDisabledKey = "notary"
reputationValuePrefix = 'r'
reputationCountPrefix = 'c'
)
func _deploy(data interface{}, isUpdate bool) {
common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey)
if isUpdate {
args := data.([]interface{})
common.CheckVersion(args[len(args)-1].(int))
return
}
runtime.Log("reputation contract initialized")
}
// Update method updates contract source code and manifest. It can be invoked
// only by committee.
func Update(script []byte, manifest []byte, data interface{}) {
if !common.HasUpdateAccess() {
panic("only committee can update contract")
}
management.UpdateWithData(script, manifest, common.AppendVersion(data))
runtime.Log("reputation contract updated")
}
// Put method saves DataAuditResult in contract storage. It can be invoked only by
// Inner Ring nodes. It does not require multisignature invocations.
//
// Epoch is the epoch number when DataAuditResult structure was generated.
// PeerID contains public keys of the Inner Ring node that has produced DataAuditResult.
// Value contains a stable marshaled structure of DataAuditResult.
func Put(epoch int, peerID []byte, value []byte) {
ctx := storage.GetContext()
multiaddr := common.AlphabetAddress()
if !runtime.CheckWitness(multiaddr) {
runtime.Notify("reputationPut", epoch, peerID, value)
return
}
id := storageID(epoch, peerID)
key := getReputationKey(reputationCountPrefix, id)
rawCnt := storage.Get(ctx, key)
cnt := 0
if rawCnt != nil {
cnt = rawCnt.(int)
}
cnt++
storage.Put(ctx, key, cnt)
key[0] = reputationValuePrefix
key = append(key, convert.ToBytes(cnt)...)
storage.Put(ctx, key, value)
}
// Get method returns a list of all stable marshaled DataAuditResult structures
// produced by the specified Inner Ring node during the specified epoch.
func Get(epoch int, peerID []byte) [][]byte {
id := storageID(epoch, peerID)
return GetByID(id)
}
// GetByID method returns a list of all stable marshaled DataAuditResult with
// the specified id. Use ListByEpoch method to obtain the id.
func GetByID(id []byte) [][]byte {
ctx := storage.GetReadOnlyContext()
var data [][]byte
it := storage.Find(ctx, getReputationKey(reputationValuePrefix, id), storage.ValuesOnly)
for iterator.Next(it) {
data = append(data, iterator.Value(it).([]byte))
}
return data
}
func getReputationKey(prefix byte, id []byte) []byte {
return append([]byte{prefix}, id...)
}
// ListByEpoch returns a list of IDs that may be used to get reputation data
// with GetByID method.
func ListByEpoch(epoch int) [][]byte {
ctx := storage.GetReadOnlyContext()
key := getReputationKey(reputationCountPrefix, convert.ToBytes(epoch))
it := storage.Find(ctx, key, storage.KeysOnly)
var result [][]byte
for iterator.Next(it) {
key := iterator.Value(it).([]byte) // iterator MUST BE `storage.KeysOnly`
result = append(result, key[1:])
}
return result
}
// Version returns the version of the contract.
func Version() int {
return common.Version
}
func storageID(epoch int, peerID []byte) []byte {
var buf interface{} = epoch
return append(buf.([]byte), peerID...)
}

View File

@ -1,128 +0,0 @@
// Package audit contains RPC wrappers for Audit contract.
//
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
package audit
import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
)
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
Invoker
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
}
// Contract implements all contract methods.
type Contract struct {
ContractReader
actor Actor
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
return &ContractReader{invoker, hash}
}
// New creates an instance of Contract using provided contract hash and the given Actor.
func New(actor Actor, hash util.Uint160) *Contract {
return &Contract{ContractReader{actor, hash}, actor, hash}
}
// Get invokes `get` method of contract.
func (c *ContractReader) Get(id []byte) ([]byte, error) {
return unwrap.Bytes(c.invoker.Call(c.hash, "get", id))
}
// List invokes `list` method of contract.
func (c *ContractReader) List() ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "list"))
}
// ListByCID invokes `listByCID` method of contract.
func (c *ContractReader) ListByCID(epoch *big.Int, cid []byte) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "listByCID", epoch, cid))
}
// ListByEpoch invokes `listByEpoch` method of contract.
func (c *ContractReader) ListByEpoch(epoch *big.Int) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "listByEpoch", epoch))
}
// ListByNode invokes `listByNode` method of contract.
func (c *ContractReader) ListByNode(epoch *big.Int, cid []byte, key *keys.PublicKey) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "listByNode", epoch, cid, key))
}
// Version invokes `version` method of contract.
func (c *ContractReader) Version() (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(c.hash, "version"))
}
// Put creates a transaction invoking `put` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Put(rawAuditResult []byte) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "put", rawAuditResult)
}
// PutTransaction creates a transaction invoking `put` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) PutTransaction(rawAuditResult []byte) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "put", rawAuditResult)
}
// PutUnsigned creates a transaction invoking `put` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) PutUnsigned(rawAuditResult []byte) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "put", nil, rawAuditResult)
}
// Update creates a transaction invoking `update` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Update(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "update", script, manifest, data)
}
// UpdateTransaction creates a transaction invoking `update` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UpdateTransaction(script []byte, manifest []byte, data any) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "update", script, manifest, data)
}
// UpdateUnsigned creates a transaction invoking `update` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UpdateUnsigned(script []byte, manifest []byte, data any) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data)
}

View File

@ -1,207 +0,0 @@
// Package reputation contains RPC wrappers for Reputation contract.
//
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
package reputation
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
)
// ReputationPutEvent represents "reputationPut" event emitted by the contract.
type ReputationPutEvent struct {
Epoch *big.Int
PeerID []byte
Value []byte
}
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
Invoker
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
}
// Contract implements all contract methods.
type Contract struct {
ContractReader
actor Actor
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
return &ContractReader{invoker, hash}
}
// New creates an instance of Contract using provided contract hash and the given Actor.
func New(actor Actor, hash util.Uint160) *Contract {
return &Contract{ContractReader{actor, hash}, actor, hash}
}
// Get invokes `get` method of contract.
func (c *ContractReader) Get(epoch *big.Int, peerID []byte) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "get", epoch, peerID))
}
// GetByID invokes `getByID` method of contract.
func (c *ContractReader) GetByID(id []byte) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "getByID", id))
}
// ListByEpoch invokes `listByEpoch` method of contract.
func (c *ContractReader) ListByEpoch(epoch *big.Int) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "listByEpoch", epoch))
}
// Put creates a transaction invoking `put` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Put(epoch *big.Int, peerID []byte, value []byte) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "put", epoch, peerID, value)
}
// PutTransaction creates a transaction invoking `put` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) PutTransaction(epoch *big.Int, peerID []byte, value []byte) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "put", epoch, peerID, value)
}
// PutUnsigned creates a transaction invoking `put` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) PutUnsigned(epoch *big.Int, peerID []byte, value []byte) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "put", nil, epoch, peerID, value)
}
// Update creates a transaction invoking `update` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Update(script []byte, manifest []byte, data any) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "update", script, manifest, data)
}
// UpdateTransaction creates a transaction invoking `update` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UpdateTransaction(script []byte, manifest []byte, data any) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "update", script, manifest, data)
}
// UpdateUnsigned creates a transaction invoking `update` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UpdateUnsigned(script []byte, manifest []byte, data any) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "update", nil, script, manifest, data)
}
// Version creates a transaction invoking `version` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Version() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "version")
}
// VersionTransaction creates a transaction invoking `version` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) VersionTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "version")
}
// VersionUnsigned creates a transaction invoking `version` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) VersionUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "version", nil)
}
// ReputationPutEventsFromApplicationLog retrieves a set of all emitted events
// with "reputationPut" name from the provided [result.ApplicationLog].
func ReputationPutEventsFromApplicationLog(log *result.ApplicationLog) ([]*ReputationPutEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*ReputationPutEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "reputationPut" {
continue
}
event := new(ReputationPutEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize ReputationPutEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to ReputationPutEvent or
// returns an error if it's not possible to do to so.
func (e *ReputationPutEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 3 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.Epoch, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Epoch: %w", err)
}
index++
e.PeerID, err = arr[index].TryBytes()
if err != nil {
return fmt.Errorf("field PeerID: %w", err)
}
index++
e.Value, err = arr[index].TryBytes()
if err != nil {
return fmt.Errorf("field Value: %w", err)
}
return nil
}

View File

@ -21,13 +21,12 @@ const alphabetPath = "../alphabet"
func deployAlphabetContract(t *testing.T, e *neotest.Executor, addrNetmap, addrProxy util.Uint160, name string, index, total int64) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, alphabetPath, path.Join(alphabetPath, "config.yml"))
args := make([]interface{}, 6)
args[0] = false
args[1] = addrNetmap
args[2] = addrProxy
args[3] = name
args[4] = index
args[5] = total
args := make([]any, 5)
args[0] = addrNetmap
args[1] = addrProxy
args[2] = name
args[3] = index
args[4] = total
e.DeployContract(t, c, args)
return c.Hash
@ -88,8 +87,8 @@ func TestVote(t *testing.T) {
require.True(t, ok)
cNewAlphabet := c.WithSigners(newAlphabet)
cNewAlphabet.InvokeFail(t, common.ErrAlphabetWitnessFailed, method, int64(0), []interface{}{newAlphabetPub})
c.InvokeFail(t, "invalid epoch", method, int64(1), []interface{}{newAlphabetPub})
cNewAlphabet.InvokeFail(t, common.ErrAlphabetWitnessFailed, method, int64(0), []any{newAlphabetPub})
c.InvokeFail(t, "invalid epoch", method, int64(1), []any{newAlphabetPub})
setAlphabetRole(t, e, newAlphabetPub)
transferNeoToContract(t, c)
@ -109,7 +108,7 @@ func TestVote(t *testing.T) {
newInvoker := neoInvoker.WithSigners(newAlphabet)
newInvoker.Invoke(t, stackitem.NewBool(true), "registerCandidate", newAlphabetPub)
c.Invoke(t, stackitem.Null{}, method, int64(0), []interface{}{newAlphabetPub})
c.Invoke(t, stackitem.Null{}, method, int64(0), []any{newAlphabetPub})
// wait one block util
// a new committee is accepted
@ -139,7 +138,7 @@ func setAlphabetRole(t *testing.T, e *neotest.Executor, new []byte) {
designInvoker := e.CommitteeInvoker(designSH)
// set committee as NeoFSAlphabet
designInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(noderoles.NeoFSAlphabet), []interface{}{new})
designInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(noderoles.NeoFSAlphabet), []any{new})
}
func getAlphabetAcc(t *testing.T, e *neotest.Executor) *wallet.Account {

View File

@ -14,10 +14,9 @@ const balancePath = "../balance"
func deployBalanceContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
args := make([]interface{}, 3)
args[0] = false
args[1] = addrNetmap
args[2] = addrContainer
args := make([]any, 3)
args[0] = addrNetmap
args[1] = addrContainer
e.DeployContract(t, c, args)
return c.Hash

View File

@ -24,18 +24,17 @@ import (
const containerPath = "../container"
const (
containerFee = 0_0100_0000
containerAliasFee = 0_0050_0000
containerFee = 0o_0100_0000
containerAliasFee = 0o_0050_0000
)
func deployContainerContract(t *testing.T, e *neotest.Executor, addrNetmap, addrBalance, addrNNS util.Uint160) util.Uint160 {
args := make([]interface{}, 6)
args[0] = int64(0)
args[1] = addrNetmap
args[2] = addrBalance
args[3] = util.Uint160{} // not needed for now
args[4] = addrNNS
args[5] = "frostfs"
args := make([]any, 5)
args[0] = addrNetmap
args[1] = addrBalance
args[2] = util.Uint160{} // not needed for now
args[3] = addrNNS
args[4] = "frostfs"
c := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
e.DeployContract(t, c, args)
@ -164,7 +163,6 @@ func checkContainerList(t *testing.T, c *neotest.ContractInvoker, expected [][]b
}
require.ElementsMatch(t, expected, actual)
})
}
func TestContainerPut(t *testing.T) {
@ -173,7 +171,7 @@ func TestContainerPut(t *testing.T) {
acc := c.NewAccount(t)
cnt := dummyContainer(acc)
putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token}
putArgs := []any{cnt.value, cnt.sig, cnt.pub, cnt.token}
c.InvokeFail(t, "insufficient balance to create container", "put", putArgs...)
balanceMint(t, cBal, acc, containerFee*1, []byte{})
@ -189,7 +187,7 @@ func TestContainerPut(t *testing.T) {
balanceMint(t, cBal, acc, containerFee*1, []byte{})
putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token, "mycnt", ""}
putArgs := []any{cnt.value, cnt.sig, cnt.pub, cnt.token, "mycnt", ""}
t.Run("no fee for alias", func(t *testing.T) {
c.InvokeFail(t, "insufficient balance to create container", "putNamed", putArgs...)
})
@ -224,12 +222,13 @@ func TestContainerPut(t *testing.T) {
balanceMint(t, cBal, acc, (containerFee+containerAliasFee)*1, []byte{})
putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token, "domain", "cdn"}
putArgs := []any{cnt.value, cnt.sig, cnt.pub, cnt.token, "domain", "cdn"}
c2 := c.WithSigners(c.Committee, acc)
c2.Invoke(t, stackitem.Null{}, "putNamed", putArgs...)
expected = stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte(base58.Encode(cnt.id[:])))})
stackitem.NewByteArray([]byte(base58.Encode(cnt.id[:]))),
})
cNNS.Invoke(t, expected, "resolve", "domain.cdn", int64(nns.TXT))
})
})
@ -244,7 +243,7 @@ func TestContainerPut(t *testing.T) {
acc := c.NewAccount(t)
balanceMint(t, cBal, acc, totalPrice*totalContainers, []byte{})
cnt := dummyContainer(acc)
putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token, "precreated", ""}
putArgs := []any{cnt.value, cnt.sig, cnt.pub, cnt.token, "precreated", ""}
c.Invoke(t, stackitem.Null{}, "putNamed", putArgs...)
txs := make([]*transaction.Transaction, 0, containerPerBlock)
@ -314,7 +313,7 @@ func TestContainerDelete(t *testing.T) {
t.Run("gas costs are the same for different epochs", func(t *testing.T) {
_, cnt2 := addContainer(t, c, cBal)
args := []interface{}{cnt2.id[:], cnt2.sig, cnt2.pub, cnt2.token}
args := []any{cnt2.id[:], cnt2.sig, cnt2.pub, cnt2.token}
tx := c.PrepareInvoke(t, "delete", args...)
for _, e := range []int{126, 127, 128, 129, 65536} {
@ -405,7 +404,7 @@ func TestContainerSetEACL(t *testing.T) {
})
e := dummyEACL(cnt.id)
setArgs := []interface{}{e.value, e.sig, e.pub, e.token}
setArgs := []any{e.value, e.sig, e.pub, e.token}
cAcc := c.WithSigners(acc)
cAcc.InvokeFail(t, common.ErrAlphabetWitnessFailed, "setEACL", setArgs...)

View File

@ -21,24 +21,24 @@ import (
const frostfsPath = "../frostfs"
func deployFrostFSContract(t *testing.T, e *neotest.Executor, addrProc util.Uint160,
pubs keys.PublicKeys, config ...interface{}) util.Uint160 {
args := make([]interface{}, 5)
args[0] = false
args[1] = addrProc
pubs keys.PublicKeys, config ...any,
) util.Uint160 {
args := make([]any, 3)
args[0] = addrProc
arr := make([]interface{}, len(pubs))
arr := make([]any, len(pubs))
for i := range pubs {
arr[i] = pubs[i].Bytes()
}
args[2] = arr
args[3] = append([]interface{}{}, config...)
args[1] = arr
args[2] = append([]any{}, config...)
c := neotest.CompileFile(t, e.CommitteeHash, frostfsPath, path.Join(frostfsPath, "config.yml"))
e.DeployContract(t, c, args)
return c.Hash
}
func newFrostFSInvoker(t *testing.T, n int, config ...interface{}) (*neotest.ContractInvoker, neotest.Signer, keys.PublicKeys) {
func newFrostFSInvoker(t *testing.T, n int, config ...any) (*neotest.ContractInvoker, neotest.Signer, keys.PublicKeys) {
e := newExecutor(t)
accounts := make([]*wallet.Account, n)

View File

@ -17,10 +17,9 @@ import (
const frostfsidPath = "../frostfsid"
func deployFrostFSIDContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) util.Uint160 {
args := make([]interface{}, 5)
args[0] = false
args[1] = addrNetmap
args[2] = addrContainer
args := make([]any, 2)
args[0] = addrNetmap
args[1] = addrContainer
c := neotest.CompileFile(t, e.CommitteeHash, frostfsidPath, path.Join(frostfsidPath, "config.yml"))
e.DeployContract(t, c, args)
@ -57,7 +56,7 @@ func TestFrostFSID_AddKey(t *testing.T) {
acc := e.NewAccount(t)
owner := signerToOwner(acc)
e.Invoke(t, stackitem.Null{}, "addKey", owner,
[]interface{}{pubs[0], pubs[1]})
[]any{pubs[0], pubs[1]})
sort.Slice(pubs[:2], func(i, j int) bool {
return bytes.Compare(pubs[i], pubs[j]) == -1
@ -69,8 +68,8 @@ func TestFrostFSID_AddKey(t *testing.T) {
e.Invoke(t, stackitem.NewArray(arr), "key", owner)
t.Run("multiple addKey per block", func(t *testing.T) {
tx1 := e.PrepareInvoke(t, "addKey", owner, []interface{}{pubs[2]})
tx2 := e.PrepareInvoke(t, "addKey", owner, []interface{}{pubs[3], pubs[4]})
tx1 := e.PrepareInvoke(t, "addKey", owner, []any{pubs[2]})
tx2 := e.PrepareInvoke(t, "addKey", owner, []any{pubs[3], pubs[4]})
e.AddNewBlock(t, tx1, tx2)
e.CheckHalt(t, tx1.Hash(), stackitem.Null{})
e.CheckHalt(t, tx2.Hash(), stackitem.Null{})
@ -89,7 +88,7 @@ func TestFrostFSID_AddKey(t *testing.T) {
})
e.Invoke(t, stackitem.Null{}, "removeKey", owner,
[]interface{}{pubs[1], pubs[5]})
[]any{pubs[1], pubs[5]})
arr = []stackitem.Item{
stackitem.NewBuffer(pubs[0]),
stackitem.NewBuffer(pubs[2]),
@ -99,8 +98,8 @@ func TestFrostFSID_AddKey(t *testing.T) {
e.Invoke(t, stackitem.NewArray(arr), "key", owner)
t.Run("multiple removeKey per block", func(t *testing.T) {
tx1 := e.PrepareInvoke(t, "removeKey", owner, []interface{}{pubs[2]})
tx2 := e.PrepareInvoke(t, "removeKey", owner, []interface{}{pubs[0], pubs[4]})
tx1 := e.PrepareInvoke(t, "removeKey", owner, []any{pubs[2]})
tx2 := e.PrepareInvoke(t, "removeKey", owner, []any{pubs[0], pubs[4]})
e.AddNewBlock(t, tx1, tx2)
e.CheckHalt(t, tx1.Hash(), stackitem.Null{})
e.CheckHalt(t, tx2.Hash(), stackitem.Null{})

View File

@ -20,23 +20,22 @@ import (
const netmapPath = "../netmap"
func deployNetmapContract(t *testing.T, e *neotest.Executor, addrBalance, addrContainer util.Uint160, config ...interface{}) util.Uint160 {
func deployNetmapContract(t *testing.T, e *neotest.Executor, addrBalance, addrContainer util.Uint160, config ...any) util.Uint160 {
_, pubs, ok := vm.ParseMultiSigContract(e.Committee.Script())
require.True(t, ok)
args := make([]interface{}, 5)
args[0] = false
args[1] = addrBalance
args[2] = addrContainer
args[3] = []interface{}{pubs[0]}
args[4] = append([]interface{}{}, config...)
args := make([]any, 4)
args[0] = addrBalance
args[1] = addrContainer
args[2] = []any{pubs[0]}
args[3] = append([]any{}, config...)
c := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
e.DeployContract(t, c, args)
return c.Hash
}
func newNetmapInvoker(t *testing.T, config ...interface{}) *neotest.ContractInvoker {
func newNetmapInvoker(t *testing.T, config ...any) *neotest.ContractInvoker {
e := newExecutor(t)
ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))

View File

@ -115,7 +115,8 @@ func TestNNSRegister(t *testing.T) {
expected = stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte("first TXT record")),
stackitem.NewByteArray([]byte("second TXT record"))})
stackitem.NewByteArray([]byte("second TXT record")),
})
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
cAcc.Invoke(t, stackitem.Null{}, "setRecord",
@ -123,7 +124,8 @@ func TestNNSRegister(t *testing.T) {
expected = stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte("replaced first")),
stackitem.NewByteArray([]byte("second TXT record"))})
stackitem.NewByteArray([]byte("second TXT record")),
})
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
}
@ -139,8 +141,8 @@ func TestTLDRecord(t *testing.T) {
func TestNNSRegisterMulti(t *testing.T) {
c := newNNSInvoker(t, true)
newArgs := func(domain string, account neotest.Signer) []interface{} {
return []interface{}{
newArgs := func(domain string, account neotest.Signer) []any {
return []any{
domain, account.ScriptHash(), "doesnt@matter.com",
int64(101), int64(102), int64(103), int64(104),
}
@ -185,7 +187,8 @@ func TestNNSRegisterMulti(t *testing.T) {
c2.Invoke(t, stackitem.Null{}, "addRecord",
"cdn.mainnet.fs.neo.com", int64(nns.A), "166.15.14.13")
result := stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte("166.15.14.13"))})
stackitem.NewByteArray([]byte("166.15.14.13")),
})
c2.Invoke(t, result, "resolve", "cdn.mainnet.fs.neo.com", int64(nns.A))
}
@ -262,7 +265,8 @@ func TestExpiration(t *testing.T) {
checkProperties := func(t *testing.T, expiration uint64) {
expected := stackitem.NewMapWithValue([]stackitem.MapElement{
{Key: stackitem.Make("name"), Value: stackitem.Make("testdomain.com")},
{Key: stackitem.Make("expiration"), Value: stackitem.Make(expiration)}})
{Key: stackitem.Make("expiration"), Value: stackitem.Make(expiration)},
})
s, err := c.TestInvoke(t, "properties", "testdomain.com")
require.NoError(t, err)
require.Equal(t, expected.Value(), s.Top().Item().Value())
@ -351,7 +355,8 @@ func TestNNSRenew(t *testing.T) {
c1.Invoke(t, ts, "renew", "testdomain.com")
expected := stackitem.NewMapWithValue([]stackitem.MapElement{
{Key: stackitem.Make("name"), Value: stackitem.Make("testdomain.com")},
{Key: stackitem.Make("expiration"), Value: stackitem.Make(ts)}})
{Key: stackitem.Make("expiration"), Value: stackitem.Make(ts)},
})
cAcc.Invoke(t, expected, "properties", "testdomain.com")
}

View File

@ -14,7 +14,7 @@ const processingPath = "../processing"
func deployProcessingContract(t *testing.T, e *neotest.Executor, addrFrostFS util.Uint160) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, processingPath, path.Join(processingPath, "config.yml"))
args := make([]interface{}, 1)
args := make([]any, 1)
args[0] = addrFrostFS
e.DeployContract(t, c, args)

View File

@ -12,7 +12,7 @@ import (
const proxyPath = "../proxy"
func deployProxyContract(t *testing.T, e *neotest.Executor, addrNetmap util.Uint160) util.Uint160 {
args := make([]interface{}, 1)
args := make([]any, 1)
args[0] = addrNetmap
c := neotest.CompileFile(t, e.CommitteeHash, proxyPath, path.Join(proxyPath, "config.yml"))

View File

@ -1,80 +0,0 @@
package tests
import (
"path"
"testing"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
const reputationPath = "../reputation"
func deployReputationContract(t *testing.T, e *neotest.Executor) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, reputationPath,
path.Join(reputationPath, "config.yml"))
args := make([]interface{}, 1)
args[0] = false
e.DeployContract(t, c, args)
return c.Hash
}
func newReputationInvoker(t *testing.T) *neotest.ContractInvoker {
bc, acc := chain.NewSingle(t)
e := neotest.NewExecutor(t, bc, acc, acc)
h := deployReputationContract(t, e)
return e.CommitteeInvoker(h)
}
func TestReputation_Put(t *testing.T) {
e := newReputationInvoker(t)
peerID := []byte{1, 2, 3}
e.Invoke(t, stackitem.Null{}, "put", int64(1), peerID, []byte{4})
t.Run("concurrent invocations", func(t *testing.T) {
repValue1 := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
repValue2 := []byte{10, 20, 30, 40, 50, 60, 70, 80}
tx1 := e.PrepareInvoke(t, "put", int64(1), peerID, repValue1)
tx2 := e.PrepareInvoke(t, "put", int64(1), peerID, repValue2)
e.AddNewBlock(t, tx1, tx2)
e.CheckHalt(t, tx1.Hash(), stackitem.Null{})
e.CheckHalt(t, tx2.Hash(), stackitem.Null{})
t.Run("get all", func(t *testing.T) {
result := stackitem.NewArray([]stackitem.Item{
stackitem.NewBuffer([]byte{4}),
stackitem.NewBuffer(repValue1),
stackitem.NewBuffer(repValue2),
})
e.Invoke(t, result, "get", int64(1), peerID)
})
})
}
func TestReputation_ListByEpoch(t *testing.T) {
e := newReputationInvoker(t)
peerIDs := []string{"peer1", "peer2"}
e.Invoke(t, stackitem.Null{}, "put", int64(1), peerIDs[0], []byte{1})
e.Invoke(t, stackitem.Null{}, "put", int64(1), peerIDs[0], []byte{2})
e.Invoke(t, stackitem.Null{}, "put", int64(2), peerIDs[1], []byte{3})
e.Invoke(t, stackitem.Null{}, "put", int64(2), peerIDs[0], []byte{4})
e.Invoke(t, stackitem.Null{}, "put", int64(2), peerIDs[1], []byte{5})
result := stackitem.NewArray([]stackitem.Item{
stackitem.NewBuffer(append([]byte{1}, peerIDs[0]...)),
})
e.Invoke(t, result, "listByEpoch", int64(1))
result = stackitem.NewArray([]stackitem.Item{
stackitem.NewBuffer(append([]byte{2}, peerIDs[0]...)),
stackitem.NewBuffer(append([]byte{2}, peerIDs[1]...)),
})
e.Invoke(t, result, "listByEpoch", int64(2))
}