notary

package
v0.106.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2024 License: MIT Imports: 24 Imported by: 9

Documentation

Overview

Package notary provides an RPC-based wrapper for the Notary subsystem.

It provides both regular ContractReader/Contract interfaces for the notary contract and notary-specific Actor as well as some helper functions to simplify creation of notary requests.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrFallbackAccepted is returned from [Actor.WaitSuccess] when
	// fallback transaction enters the chain instead of the main one.
	ErrFallbackAccepted = errors.New("fallback transaction accepted")
)

Hash stores the hash of the native Notary contract.

Functions

func FakeContractAccount

func FakeContractAccount(hash util.Uint160) *wallet.Account

FakeContractAccount creates a fake account belonging to some deployed contract. SignTx can be called on this account with no error, but at the same time it adds no signature or other data into the invocation script (it obviously can't do that, so CanSign() returns false for it). Use this account for Actor when one of the signers is a contract and it doesn't need a signature or you can provide it externally.

func FakeMultisigAccount

func FakeMultisigAccount(m int, pkeys keys.PublicKeys) (*wallet.Account, error)

FakeMultisigAccount creates a fake account belonging to the given "m out of len(pkeys)" account for the given set of keys. The account returned has SignTx that returns no error, but at the same time adds no signatures (it can't do that, so CanSign() returns false for it). Use this account for Actor when multisignature account needs to be added into a notary transaction, but you have no keys at all for it (if you have at least one (which usually is the case) ordinary multisig account works fine already).

func FakeSimpleAccount

func FakeSimpleAccount(k *keys.PublicKey) *wallet.Account

FakeSimpleAccount creates a fake account belonging to the given public key. It uses a simple signature contract and this account has SignTx that returns no error, but at the same time adds no signature (it obviously can't do that, so CanSign() returns false for it). Use this account for Actor when simple signatures are needed to be collected.

Types

type Actor

type Actor struct {
	// Actor is the main transaction actor, it has appropriate attributes and
	// transaction modifiers to set ValidUntilBlock. Use it to create main
	// transactions that have incomplete set of signatures. They can be
	// signed (using available wallets), but can not be sent directly to the
	// network. Instead of sending them to the network use Actor methods to
	// wrap them into notary requests.
	actor.Actor
	// FbActor is the fallback transaction actor, it has two required signers
	// and a set of attributes expected from a fallback transaction. It can
	// be used to create _unsigned_ transactions with whatever actions
	// required (but no additional attributes can be added). Signing them
	// while technically possible (with notary contract signature missing),
	// will lead to incorrect transaction because NotValidBefore and
	// Conflicts attributes as well as ValidUntilBlock field can be
	// correctly set only when some main transaction is available.
	FbActor actor.Actor
	// contains filtered or unexported fields
}

Actor encapsulates everything needed to create proper notary requests for assisted transactions.

Example
package main

import (
	"context"
	"math/big"
	"time"

	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
	"github.com/nspcc-dev/neo-go/pkg/rpcclient"
	"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
	"github.com/nspcc-dev/neo-go/pkg/rpcclient/gas"
	"github.com/nspcc-dev/neo-go/pkg/rpcclient/notary"
	"github.com/nspcc-dev/neo-go/pkg/rpcclient/policy"
	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
	"github.com/nspcc-dev/neo-go/pkg/wallet"
)

func main() {
	// No error checking done at all, intentionally.
	w, _ := wallet.NewWalletFromFile("somewhere")
	defer w.Close()
	// We assume there are two accounts in the wallet --- one is a simple signature
	// account and another one is committee account. The first one will send notary
	// requests, while committee signatures need to be collected.

	// Create an RPC client.
	c, _ := rpcclient.New(context.Background(), "url", rpcclient.Options{})

	// An actor for the first account.
	single, _ := actor.NewSimple(c, w.Accounts[0])

	// Transfer some GAS to the Notary contract to be able to send notary requests
	// from the first account.
	gasSingle := gas.New(single)
	txid, vub, _ := gasSingle.Transfer(single.Sender(), notary.Hash, big.NewInt(10_0000_0000), &notary.OnNEP17PaymentData{Till: 10000000})

	var depositOK bool
	// Wait for transaction to be persisted, either it gets in and we get
	// an application log with some result or it expires.
	for height, err := c.GetBlockCount(); err == nil && height <= vub; height, err = c.GetBlockCount() {
		appLog, err := c.GetApplicationLog(txid, nil)
		// We can't separate "application log missing" from other errors at the moment, see #2248.
		if err != nil {
			time.Sleep(5 * time.Second)
			continue
		}
		if len(appLog.Executions) == 1 && appLog.Executions[0].VMState == vmstate.Halt {
			depositOK = true
		} else {
			break
		}
	}
	if !depositOK {
		panic("deposit failed")
	}

	var opts = new(notary.ActorOptions)
	// Add high priority attribute, we gonna be making committee-signed transactions anyway.
	opts.MainAttributes = []transaction.Attribute{{Type: transaction.HighPriority}}

	// Create an Actor with the simple account used for paying fees and committee
	// signature to be collected.
	multi, _ := notary.NewTunedActor(c, []actor.SignerAccount{{
		// Sender, regular account with None scope.
		Signer: transaction.Signer{
			Account: w.Accounts[0].ScriptHash(),
			Scopes:  transaction.None,
		},
		Account: w.Accounts[0],
	}, {
		// Commmitee.
		Signer: transaction.Signer{
			Account: w.Accounts[1].ScriptHash(),
			Scopes:  transaction.CalledByEntry,
		},
		Account: w.Accounts[1],
	}}, opts)

	// Use the Policy contract to perform something requiring committee signature.
	policyContract := policy.New(multi)

	// Wrap a transaction to set storage price into a notary request. Fallback will
	// be create automatically and all appropriate attributes will be added to both
	// transactions.
	mainTx, fbTx, vub, _ := multi.Notarize(policyContract.SetStoragePriceTransaction(10))
	_ = mainTx
	_ = fbTx
	_ = vub
}
Output:

func NewActor

func NewActor(c RPCActor, signers []actor.SignerAccount, simpleAcc *wallet.Account) (*Actor, error)

NewActor creates a new notary.Actor using the given RPC client, the set of signers for main transactions and the account that will sign notary requests (one plain signature or contract-based). The set of signers will be extended by the notary contract signer with the None scope (as required by the notary protocol) and all transactions created with the resulting Actor will get a NotaryAssisted attribute with appropriate number of keys specified (depending on signers). A fallback Actor will be created as well with the notary contract and simpleAcc signers and a full set of required fallback transaction attributes (NotaryAssisted, NotValidBefore and Conflicts).

func NewTunedActor

func NewTunedActor(c RPCActor, signers []actor.SignerAccount, opts *ActorOptions) (*Actor, error)

NewTunedActor is the same as NewActor, but allows to override the default options (see ActorOptions for details). Use with care.

func (*Actor) Notarize

func (a *Actor) Notarize(mainTx *transaction.Transaction, err error) (util.Uint256, util.Uint256, uint32, error)

Notarize is a simple wrapper for transaction-creating functions that allows to send any partially-signed transaction in a notary request with a fallback transaction created based on Actor settings and SendRequest adjustment rules. The values returned are main and fallback transaction hashes, ValidUntilBlock and error if any.

func (*Actor) SendRequest

func (a *Actor) SendRequest(mainTx *transaction.Transaction, fbTx *transaction.Transaction) (util.Uint256, util.Uint256, uint32, error)

SendRequest creates and sends a notary request using the given main and fallback transactions. It accepts signed main transaction and unsigned fallback transaction that will be adjusted in its NotValidBefore and Conflicts attributes as well as ValidUntilBlock value. Conflicts is set to the main transaction hash, while NotValidBefore is set to the middle of current mainTx lifetime (between current block and ValidUntilBlock). The values returned are main and fallback transaction hashes, ValidUntilBlock and error if any.

func (*Actor) SendRequestExactly

func (a *Actor) SendRequestExactly(mainTx *transaction.Transaction, fbTx *transaction.Transaction) (util.Uint256, util.Uint256, uint32, error)

SendRequestExactly accepts signed and completely prepared main and fallback transactions, creates a P2P notary request containing them, signs and sends it to the network. Caller takes full responsibility for transaction correctness in this case, use this method only if you know exactly that you need to override some of the other method's behavior and you can do it. The values returned are main and fallback transaction hashes, ValidUntilBlock and error if any.

func (*Actor) Wait added in v0.99.5

func (a *Actor) Wait(mainHash, fbHash util.Uint256, vub uint32, err error) (*state.AppExecResult, error)

Wait waits until main or fallback transaction will be accepted to the chain and returns the resulting application execution result or actor.ErrTxNotAccepted if both transactions failed to persist. Wait can be used if underlying Actor supports transaction awaiting, see actor.Actor and actor.Waiter documentation for details. Wait may be used as a wrapper for Notarize, SendRequest or SendRequestExactly. Notice that "already exists" or "already on chain" answers are not treated as errors by this routine because they mean that some of the transactions given might be already accepted or soon going to be accepted. These transactions can be waited for in a usual way potentially with positive result.

func (*Actor) WaitSuccess added in v0.106.3

func (a *Actor) WaitSuccess(mainHash, fbHash util.Uint256, vub uint32, err error) (*state.AppExecResult, error)

WaitSuccess works similar to Actor.Wait, but checks that the main transaction was accepted and it has a HALT VM state (executed successfully). state.AppExecResult is still returned (if there is no error) in case you need some additional event or stack checks.

type ActorOptions

type ActorOptions struct {
	// FbAttributes are additional attributes to be added into fallback
	// transaction by an appropriate actor. Irrespective of this setting
	// (which defaults to nil) NotaryAssisted, NotValidBefore and Conflicts
	// attributes are always added.
	FbAttributes []transaction.Attribute
	// FbScript is the script to use in the Notarize convenience method, it
	// defaults to a simple RET instruction (doing nothing).
	FbScript []byte
	// FbSigner is the second signer to be used for the fallback transaction.
	// By default it's derived from the account and has None scope, it has
	// to be a simple signature or deployed contract account, but this setting
	// allows you to give it some other scope to be used in complex fallback
	// scripts.
	FbSigner actor.SignerAccount
	// MainAttribtues are additional attributes to be added into main
	// transaction by an appropriate actor. Irrespective of this setting
	// (which defaults to nil) NotaryAssisted attribute is always added.
	MainAttributes []transaction.Attribute
	// MainCheckerModifier will be used by the main Actor when creating
	// transactions. It defaults to using [actor.DefaultCheckerModifier]
	// for result check and adds MaxNotValidBeforeDelta to the
	// ValidUntilBlock transaction's field. Only override it if you know
	// what you're doing.
	MainCheckerModifier actor.TransactionCheckerModifier
	// MainModifier will be used by the main Actor when creating
	// transactions. By default it adds MaxNotValidBeforeDelta to the
	// ValidUntilBlock transaction's field. Only override it if you know
	// what you're doing.
	MainModifier actor.TransactionModifier
}

ActorOptions are used to influence main and fallback actors as well as the default Notarize behavior.

func NewDefaultActorOptions

func NewDefaultActorOptions(reader *ContractReader, acc *wallet.Account) *ActorOptions

NewDefaultActorOptions returns the default Actor options. Internal functions of it need some data from the contract, so it should be added.

type Contract

type Contract struct {
	ContractReader
	// contains filtered or unexported fields
}

Contract provides full Notary interface, both safe and state-changing methods. The only method omitted is onNEP17Payment which can only be called successfully from the GASToken native contract.

func New

func New(actor ContractActor) *Contract

New creates an instance of Contract to perform state-changing actions in the Notary contract.

func (*Contract) LockDepositUntil

func (c *Contract) LockDepositUntil(account util.Uint160, index uint32) (util.Uint256, uint32, error)

LockDepositUntil creates and sends a transaction that extends the deposit lock time for the given account. The return result from the "lockDepositUntil" method is checked to be true, so transaction fails (with FAULT state) if not successful. The returned values are transaction hash, its ValidUntilBlock value and an error if any.

func (*Contract) LockDepositUntilTransaction

func (c *Contract) LockDepositUntilTransaction(account util.Uint160, index uint32) (*transaction.Transaction, error)

LockDepositUntilTransaction creates a transaction that extends the deposit lock time for the given account. The return result from the "lockDepositUntil" method is checked to be true, so transaction fails (with FAULT state) if not successful. The returned values are transaction hash, its ValidUntilBlock value and an error if any. The transaction is signed, but not sent to the network, instead it's returned to the caller.

func (*Contract) LockDepositUntilUnsigned

func (c *Contract) LockDepositUntilUnsigned(account util.Uint160, index uint32) (*transaction.Transaction, error)

LockDepositUntilUnsigned creates a transaction that extends the deposit lock time for the given account. The return result from the "lockDepositUntil" method is checked to be true, so transaction fails (with FAULT state) if not successful. The returned values are transaction hash, its ValidUntilBlock value and an error if any. The transaction is not signed and just returned to the caller.

func (*Contract) SetMaxNotValidBeforeDelta

func (c *Contract) SetMaxNotValidBeforeDelta(blocks uint32) (util.Uint256, uint32, error)

SetMaxNotValidBeforeDelta creates and sends a transaction that sets the new maximum NotValidBefore attribute value delta that can be used in notary-assisted transactions. The action is successful when transaction ends in HALT state. Notice that this setting can be changed only by the network's committee, so use an appropriate Actor. The returned values are transaction hash, its ValidUntilBlock value and an error if any.

func (*Contract) SetMaxNotValidBeforeDeltaTransaction

func (c *Contract) SetMaxNotValidBeforeDeltaTransaction(blocks uint32) (*transaction.Transaction, error)

SetMaxNotValidBeforeDeltaTransaction creates a transaction that sets the new maximum NotValidBefore attribute value delta that can be used in notary-assisted transactions. The action is successful when transaction ends in HALT state. Notice that this setting can be changed only by the network's committee, so use an appropriate Actor. The transaction is signed, but not sent to the network, instead it's returned to the caller.

func (*Contract) SetMaxNotValidBeforeDeltaUnsigned

func (c *Contract) SetMaxNotValidBeforeDeltaUnsigned(blocks uint32) (*transaction.Transaction, error)

SetMaxNotValidBeforeDeltaUnsigned creates a transaction that sets the new maximum NotValidBefore attribute value delta that can be used in notary-assisted transactions. The action is successful when transaction ends in HALT state. Notice that this setting can be changed only by the network's committee, so use an appropriate Actor. The transaction is not signed and just returned to the caller.

func (*Contract) Withdraw

func (c *Contract) Withdraw(from util.Uint160, to util.Uint160) (util.Uint256, uint32, error)

Withdraw creates and sends a transaction that withdraws the deposit belonging to "from" account and sends it to "to" account. The return result from the "withdraw" method is checked to be true, so transaction fails (with FAULT state) if not successful. The returned values are transaction hash, its ValidUntilBlock value and an error if any.

func (*Contract) WithdrawTransaction

func (c *Contract) WithdrawTransaction(from util.Uint160, to util.Uint160) (*transaction.Transaction, error)

WithdrawTransaction creates a transaction that withdraws the deposit belonging to "from" account and sends it to "to" account. The return result from the "withdraw" method is checked to be true, so transaction fails (with FAULT state) if not successful. The transaction is signed, but not sent to the network, instead it's returned to the caller.

func (*Contract) WithdrawUnsigned

func (c *Contract) WithdrawUnsigned(from util.Uint160, to util.Uint160) (*transaction.Transaction, error)

WithdrawUnsigned creates a transaction that withdraws the deposit belonging to "from" account and sends it to "to" account. The return result from the "withdraw" method is checked to be true, so transaction fails (with FAULT state) if not successful. The transaction is not signed and just returned to the caller.

type ContractActor

type ContractActor interface {
	ContractInvoker

	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)
}

ContractActor is used by Contract to create and send transactions.

type ContractInvoker

type ContractInvoker interface {
	Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
}

ContractInvoker is used by ContractReader to perform read-only calls.

type ContractReader

type ContractReader struct {
	// contains filtered or unexported fields
}

ContractReader represents safe (read-only) methods of Notary. It can be used to query various data, but `verify` method is not exposed there because it can't be successful in standalone invocation (missing transaction with the NotaryAssisted attribute and its signature).

func NewReader

func NewReader(invoker ContractInvoker) *ContractReader

NewReader creates an instance of ContractReader to get data from the Notary contract.

func (*ContractReader) BalanceOf

func (c *ContractReader) BalanceOf(account util.Uint160) (*big.Int, error)

BalanceOf returns the locked GAS balance for the given account.

func (*ContractReader) ExpirationOf

func (c *ContractReader) ExpirationOf(account util.Uint160) (uint32, error)

ExpirationOf returns the index of the block when the GAS deposit for the given account will expire.

func (*ContractReader) GetMaxNotValidBeforeDelta

func (c *ContractReader) GetMaxNotValidBeforeDelta() (uint32, error)

GetMaxNotValidBeforeDelta returns the maximum NotValidBefore attribute delta that can be used in notary-assisted transactions.

type OnNEP17PaymentData

type OnNEP17PaymentData struct {
	// Account can be nil, in this case transfer sender (from) account is used.
	Account *util.Uint160
	// Till specifies the deposit lock time (in blocks).
	Till uint32
}

OnNEP17PaymentData is the data set that is accepted by the notary contract onNEP17Payment handler. It's mandatory for GAS tranfers to this contract.

func (*OnNEP17PaymentData) FromStackItem added in v0.102.0

func (d *OnNEP17PaymentData) FromStackItem(si stackitem.Item) error

FromStackItem implements stackitem.Convertible interface.

func (*OnNEP17PaymentData) ToStackItem added in v0.102.0

func (d *OnNEP17PaymentData) ToStackItem() (stackitem.Item, error)

ToStackItem implements stackitem.Convertible interface.

type RPCActor

type RPCActor interface {
	actor.RPCActor

	SubmitP2PNotaryRequest(req *payload.P2PNotaryRequest) (util.Uint256, error)
}

RPCActor is a set of methods required from RPC client to create Actor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL