forked from TrueCloudLab/frostfs-contract
[#50] Drop audit and reputation contracts
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
d890a7eba4
commit
0ea65ca637
10 changed files with 1 additions and 822 deletions
2
Makefile
2
Makefile
|
@ -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)
|
||||
|
|
|
@ -1,220 +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 any = a.epoch
|
||||
|
||||
hashedKey := crypto.Sha256(a.from)
|
||||
shortedKey := hashedKey[:maxKeySize]
|
||||
|
||||
return append(buf.([]byte), append(a.cid, shortedKey...)...)
|
||||
}
|
||||
|
||||
const (
|
||||
netmapContractKey = "netmapScriptHash"
|
||||
)
|
||||
|
||||
func _deploy(data any, isUpdate bool) {
|
||||
ctx := storage.GetContext()
|
||||
|
||||
if isUpdate {
|
||||
args := data.([]any)
|
||||
common.CheckVersion(args[len(args)-1].(int))
|
||||
return
|
||||
}
|
||||
|
||||
args := data.(struct {
|
||||
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 any) {
|
||||
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 any = 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 any = 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 any = 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 any = 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,
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
name: "Audit"
|
||||
safemethods: ["get", "list", "listByEpoch", "listByCID", "listByNode", "version"]
|
||||
permissions:
|
||||
- methods: ["update"]
|
29
audit/doc.go
29
audit/doc.go
|
@ -1,29 +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
|
|
@ -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
|
|
@ -1,24 +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
|
|
@ -1,119 +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 (
|
||||
reputationValuePrefix = 'r'
|
||||
reputationCountPrefix = 'c'
|
||||
)
|
||||
|
||||
func _deploy(data any, isUpdate bool) {
|
||||
if isUpdate {
|
||||
args := data.([]any)
|
||||
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 any) {
|
||||
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 any = epoch
|
||||
|
||||
return append(buf.([]byte), peerID...)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,77 +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"))
|
||||
|
||||
e.DeployContract(t, c, []any{})
|
||||
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))
|
||||
}
|
Loading…
Reference in a new issue