forked from TrueCloudLab/frostfs-node
[#971] morph/client: Group Invoke
and TestInvoke
params
Also: - add `validUntilBlock` and nonce calculation; - pass notification hashes to notary calls. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
8e1f187822
commit
3849d13e0b
2 changed files with 176 additions and 29 deletions
|
@ -1,6 +1,7 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -243,14 +244,31 @@ func (c *Client) GetNotaryDeposit() (res int64, err error) {
|
||||||
return bigIntDeposit.Int64(), nil
|
return bigIntDeposit.Int64(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateNotaryListPrm groups parameters of UpdateNotaryList operation.
|
||||||
|
type UpdateNotaryListPrm struct {
|
||||||
|
list keys.PublicKeys
|
||||||
|
hash util.Uint256
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetList sets list of the new notary role keys.
|
||||||
|
func (u *UpdateNotaryListPrm) SetList(list keys.PublicKeys) {
|
||||||
|
u.list = list
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHash sets hash of the transaction that led to the update
|
||||||
|
// of the notary role in the designate contract.
|
||||||
|
func (u *UpdateNotaryListPrm) SetHash(hash util.Uint256) {
|
||||||
|
u.hash = hash
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateNotaryList updates list of notary nodes in designate contract. Requires
|
// UpdateNotaryList updates list of notary nodes in designate contract. Requires
|
||||||
// committee multi signature.
|
// committee multi signature.
|
||||||
//
|
//
|
||||||
// This function must be invoked with notary enabled otherwise it throws panic.
|
// This function must be invoked with notary enabled otherwise it throws panic.
|
||||||
func (c *Client) UpdateNotaryList(list keys.PublicKeys) error {
|
func (c *Client) UpdateNotaryList(prm UpdateNotaryListPrm) error {
|
||||||
if c.multiClient != nil {
|
if c.multiClient != nil {
|
||||||
return c.multiClient.iterateClients(func(c *Client) error {
|
return c.multiClient.iterateClients(func(c *Client) error {
|
||||||
return c.UpdateNotaryList(list)
|
return c.UpdateNotaryList(prm)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,23 +276,46 @@ func (c *Client) UpdateNotaryList(list keys.PublicKeys) error {
|
||||||
panic(notaryNotEnabledPanicMsg)
|
panic(notaryNotEnabledPanicMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nonce, vub, err := c.CalculateNonceAndVUB(prm.hash)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not calculate nonce and `valicUntilBlock` values: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return c.notaryInvokeAsCommittee(
|
return c.notaryInvokeAsCommittee(
|
||||||
setDesignateMethod,
|
setDesignateMethod,
|
||||||
1, // FIXME: do not use constant nonce for alphabet NR: #844
|
nonce,
|
||||||
|
vub,
|
||||||
noderoles.P2PNotary,
|
noderoles.P2PNotary,
|
||||||
list,
|
prm.list,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateAlphabetListPrm groups parameters of UpdateNeoFSAlphabetList operation.
|
||||||
|
type UpdateAlphabetListPrm struct {
|
||||||
|
list keys.PublicKeys
|
||||||
|
hash util.Uint256
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetList sets list of the new alphabet role keys.
|
||||||
|
func (u *UpdateAlphabetListPrm) SetList(list keys.PublicKeys) {
|
||||||
|
u.list = list
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHash sets hash of the transaction that led to the update
|
||||||
|
// of the alphabet role in the designate contract.
|
||||||
|
func (u *UpdateAlphabetListPrm) SetHash(hash util.Uint256) {
|
||||||
|
u.hash = hash
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateNeoFSAlphabetList updates list of alphabet nodes in designate contract.
|
// UpdateNeoFSAlphabetList updates list of alphabet nodes in designate contract.
|
||||||
// As for side chain list should contain all inner ring nodes.
|
// As for side chain list should contain all inner ring nodes.
|
||||||
// Requires committee multi signature.
|
// Requires committee multi signature.
|
||||||
//
|
//
|
||||||
// This function must be invoked with notary enabled otherwise it throws panic.
|
// This function must be invoked with notary enabled otherwise it throws panic.
|
||||||
func (c *Client) UpdateNeoFSAlphabetList(list keys.PublicKeys) error {
|
func (c *Client) UpdateNeoFSAlphabetList(prm UpdateAlphabetListPrm) error {
|
||||||
if c.multiClient != nil {
|
if c.multiClient != nil {
|
||||||
return c.multiClient.iterateClients(func(c *Client) error {
|
return c.multiClient.iterateClients(func(c *Client) error {
|
||||||
return c.UpdateNeoFSAlphabetList(list)
|
return c.UpdateNeoFSAlphabetList(prm)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,11 +323,17 @@ func (c *Client) UpdateNeoFSAlphabetList(list keys.PublicKeys) error {
|
||||||
panic(notaryNotEnabledPanicMsg)
|
panic(notaryNotEnabledPanicMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nonce, vub, err := c.CalculateNonceAndVUB(prm.hash)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not calculate nonce and `valicUntilBlock` values: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return c.notaryInvokeAsCommittee(
|
return c.notaryInvokeAsCommittee(
|
||||||
setDesignateMethod,
|
setDesignateMethod,
|
||||||
1, // FIXME: do not use constant nonce for alphabet NR: #844
|
nonce,
|
||||||
|
vub,
|
||||||
noderoles.NeoFSAlphabet,
|
noderoles.NeoFSAlphabet,
|
||||||
list,
|
prm.list,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,11 +341,11 @@ func (c *Client) UpdateNeoFSAlphabetList(list keys.PublicKeys) error {
|
||||||
// blockchain. Fallback tx is a `RET`. If Notary support is not enabled
|
// blockchain. Fallback tx is a `RET`. If Notary support is not enabled
|
||||||
// it fallbacks to a simple `Invoke()`.
|
// it fallbacks to a simple `Invoke()`.
|
||||||
//
|
//
|
||||||
// This function must be invoked with notary enabled otherwise it throws panic.
|
// `nonce` and `vub` are used only if notary is enabled.
|
||||||
func (c *Client) NotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce uint32, method string, args ...interface{}) error {
|
func (c *Client) NotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce uint32, vub *uint32, method string, args ...interface{}) error {
|
||||||
if c.multiClient != nil {
|
if c.multiClient != nil {
|
||||||
return c.multiClient.iterateClients(func(c *Client) error {
|
return c.multiClient.iterateClients(func(c *Client) error {
|
||||||
return c.NotaryInvoke(contract, fee, nonce, method, args...)
|
return c.NotaryInvoke(contract, fee, nonce, vub, method, args...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +353,7 @@ func (c *Client) NotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce ui
|
||||||
return c.Invoke(contract, fee, method, args...)
|
return c.Invoke(contract, fee, method, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.notaryInvoke(false, true, contract, nonce, method, args...)
|
return c.notaryInvoke(false, true, contract, nonce, vub, method, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// randSource is a source of random numbers.
|
// randSource is a source of random numbers.
|
||||||
|
@ -328,7 +375,7 @@ func (c *Client) NotaryInvokeNotAlpha(contract util.Uint160, fee fixedn.Fixed8,
|
||||||
return c.Invoke(contract, fee, method, args...)
|
return c.Invoke(contract, fee, method, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.notaryInvoke(false, false, contract, randSource.Uint32(), method, args...)
|
return c.notaryInvoke(false, false, contract, randSource.Uint32(), nil, method, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotarySignAndInvokeTX signs and sends notary request that was received from
|
// NotarySignAndInvokeTX signs and sends notary request that was received from
|
||||||
|
@ -376,16 +423,16 @@ func (c *Client) NotarySignAndInvokeTX(mainTx *transaction.Transaction) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) notaryInvokeAsCommittee(method string, nonce uint32, args ...interface{}) error {
|
func (c *Client) notaryInvokeAsCommittee(method string, nonce, vub uint32, args ...interface{}) error {
|
||||||
designate, err := c.GetDesignateHash()
|
designate, err := c.GetDesignateHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.notaryInvoke(true, true, designate, nonce, method, args...)
|
return c.notaryInvoke(true, true, designate, nonce, &vub, method, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) notaryInvoke(committee, invokedByAlpha bool, contract util.Uint160, nonce uint32, method string, args ...interface{}) error {
|
func (c *Client) notaryInvoke(committee, invokedByAlpha bool, contract util.Uint160, nonce uint32, vub *uint32, method string, args ...interface{}) error {
|
||||||
alphabetList, err := c.notary.alphabetSource() // prepare arguments for test invocation
|
alphabetList, err := c.notary.alphabetSource() // prepare arguments for test invocation
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -427,10 +474,16 @@ func (c *Client) notaryInvoke(committee, invokedByAlpha bool, contract util.Uint
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
until, err := c.notaryTxValidationLimit()
|
var until uint32
|
||||||
|
|
||||||
|
if vub != nil {
|
||||||
|
until = *vub
|
||||||
|
} else {
|
||||||
|
until, err = c.notaryTxValidationLimit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// prepare main tx
|
// prepare main tx
|
||||||
mainTx := &transaction.Transaction{
|
mainTx := &transaction.Transaction{
|
||||||
|
@ -774,3 +827,24 @@ func CalculateNotaryDepositAmount(c *Client, gasMul, gasDiv int64) (fixedn.Fixed
|
||||||
|
|
||||||
return fixedn.Fixed8(depositAmount), nil
|
return fixedn.Fixed8(depositAmount), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateNonceAndVUB calculates nonce and ValidUntilBlock values
|
||||||
|
// based on transaction hash. Uses MurmurHash3.
|
||||||
|
func (c *Client) CalculateNonceAndVUB(hash util.Uint256) (nonce uint32, vub uint32, err error) {
|
||||||
|
if c.multiClient != nil {
|
||||||
|
return nonce, vub, c.multiClient.iterateClients(func(c *Client) error {
|
||||||
|
nonce, vub, err = c.CalculateNonceAndVUB(hash)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cache values since some operations uses same TX as triggers
|
||||||
|
nonce = binary.LittleEndian.Uint32(hash.BytesLE())
|
||||||
|
|
||||||
|
height, err := c.client.GetTransactionHeight(hash)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("could not get transaction height: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nonce, height + c.notary.txValidTime, nil
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -71,34 +72,106 @@ func (s StaticClient) Morph() *Client {
|
||||||
return s.client
|
return s.client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvokePrm groups parameters of the Invoke operation.
|
||||||
|
type InvokePrm struct {
|
||||||
|
// required parameters
|
||||||
|
method string
|
||||||
|
args []interface{}
|
||||||
|
|
||||||
|
// optional parameters
|
||||||
|
InvokePrmOptional
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvokePrmOptional groups optional parameters of the Invoke operation.
|
||||||
|
type InvokePrmOptional struct {
|
||||||
|
// hash is an optional hash of the transaction
|
||||||
|
// that generated the notification that required
|
||||||
|
// to invoke notary request.
|
||||||
|
// It is used to generate same but unique nonce and
|
||||||
|
// `validUntilBlock` values by all notification
|
||||||
|
// receivers.
|
||||||
|
hash *util.Uint256
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMethod sets method of the contract to call.
|
||||||
|
func (i *InvokePrm) SetMethod(method string) {
|
||||||
|
i.method = method
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetArgs sets arguments of the contact call.
|
||||||
|
func (i *InvokePrm) SetArgs(args ...interface{}) {
|
||||||
|
i.args = args
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHash sets optional hash of the transaction.
|
||||||
|
// If hash is set and notary is enabled, StaticClient
|
||||||
|
// uses it for notary nonce and `validUntilBlock`
|
||||||
|
// calculation.
|
||||||
|
func (i *InvokePrmOptional) SetHash(hash util.Uint256) {
|
||||||
|
i.hash = &hash
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke calls Invoke method of Client with static internal script hash and fee.
|
// Invoke calls Invoke method of Client with static internal script hash and fee.
|
||||||
// Supported args types are the same as in Client.
|
// Supported args types are the same as in Client.
|
||||||
//
|
//
|
||||||
// If TryNotary is provided, calls NotaryInvoke on Client.
|
// If TryNotary is provided:
|
||||||
func (s StaticClient) Invoke(method string, args ...interface{}) error {
|
// - if AsAlphabet is provided, calls NotaryInvoke;
|
||||||
|
// - otherwise, calls NotaryInvokeNotAlpha.
|
||||||
|
func (s StaticClient) Invoke(prm InvokePrm) error {
|
||||||
if s.tryNotary {
|
if s.tryNotary {
|
||||||
if s.alpha {
|
if s.alpha {
|
||||||
// FIXME: do not use constant nonce for alphabet NR: #844
|
var (
|
||||||
return s.client.NotaryInvoke(s.scScriptHash, s.fee, 1, method, args...)
|
nonce uint32 = 1
|
||||||
|
vubP *uint32
|
||||||
|
vub uint32
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if prm.hash != nil {
|
||||||
|
nonce, vub, err = s.client.CalculateNonceAndVUB(*prm.hash)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not calculate nonce and VUB for notary alphabet invoke: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.client.NotaryInvokeNotAlpha(s.scScriptHash, s.fee, method, args...)
|
vubP = &vub
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.NotaryInvoke(s.scScriptHash, s.fee, nonce, vubP, prm.method, prm.args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.NotaryInvokeNotAlpha(s.scScriptHash, s.fee, prm.method, prm.args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.client.Invoke(
|
return s.client.Invoke(
|
||||||
s.scScriptHash,
|
s.scScriptHash,
|
||||||
s.fee,
|
s.fee,
|
||||||
method,
|
prm.method,
|
||||||
args...,
|
prm.args...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestInvokePrm groups parameters of the TestInvoke operation.
|
||||||
|
type TestInvokePrm struct {
|
||||||
|
method string
|
||||||
|
args []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMethod sets method of the contract to call.
|
||||||
|
func (ti *TestInvokePrm) SetMethod(method string) {
|
||||||
|
ti.method = method
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetArgs sets arguments of the contact call.
|
||||||
|
func (ti *TestInvokePrm) SetArgs(args ...interface{}) {
|
||||||
|
ti.args = args
|
||||||
|
}
|
||||||
|
|
||||||
// TestInvoke calls TestInvoke method of Client with static internal script hash.
|
// TestInvoke calls TestInvoke method of Client with static internal script hash.
|
||||||
func (s StaticClient) TestInvoke(method string, args ...interface{}) ([]stackitem.Item, error) {
|
func (s StaticClient) TestInvoke(prm TestInvokePrm) ([]stackitem.Item, error) {
|
||||||
return s.client.TestInvoke(
|
return s.client.TestInvoke(
|
||||||
s.scScriptHash,
|
s.scScriptHash,
|
||||||
method,
|
prm.method,
|
||||||
args...,
|
prm.args...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue