[#846] morph/notary: Add nonce parameter to notary invocation method

This prevents notary requests collisions
for TXs that contains equals hashable fields.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2021-09-23 19:56:13 +03:00 committed by Alex Vanin
parent 3a8f0edac1
commit e3c0288e50
3 changed files with 18 additions and 10 deletions

View file

@ -94,7 +94,8 @@ func (s *Server) voteForSidechainValidator(validators keys.PublicKeys) error {
epoch := s.EpochCounter() epoch := s.EpochCounter()
s.contracts.alphabet.iterate(func(letter GlagoliticLetter, contract util.Uint160) { s.contracts.alphabet.iterate(func(letter GlagoliticLetter, contract util.Uint160) {
err := s.morphClient.NotaryInvoke(contract, s.feeConfig.SideChainFee(), voteMethod, int64(epoch), validators) // FIXME: do not use constant nonce for alphabet NR: #844
err := s.morphClient.NotaryInvoke(contract, s.feeConfig.SideChainFee(), 1, voteMethod, int64(epoch), validators)
if err != nil { if err != nil {
s.log.Warn("can't invoke vote method in alphabet contract", s.log.Warn("can't invoke vote method in alphabet contract",
zap.Int8("alphabet_index", int8(letter)), zap.Int8("alphabet_index", int8(letter)),

View file

@ -16,6 +16,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/nspcc-dev/neofs-node/pkg/util/rand"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -248,6 +249,7 @@ func (c *Client) UpdateNotaryList(list keys.PublicKeys) error {
return c.notaryInvokeAsCommittee( return c.notaryInvokeAsCommittee(
setDesignateMethod, setDesignateMethod,
1, // FIXME: do not use constant nonce for alphabet NR: #844
noderoles.P2PNotary, noderoles.P2PNotary,
list, list,
) )
@ -271,6 +273,7 @@ func (c *Client) UpdateNeoFSAlphabetList(list keys.PublicKeys) error {
return c.notaryInvokeAsCommittee( return c.notaryInvokeAsCommittee(
setDesignateMethod, setDesignateMethod,
1, // FIXME: do not use constant nonce for alphabet NR: #844
noderoles.NeoFSAlphabet, noderoles.NeoFSAlphabet,
list, list,
) )
@ -281,10 +284,10 @@ func (c *Client) UpdateNeoFSAlphabetList(list keys.PublicKeys) error {
// it fallbacks to a simple `Invoke()`. // it fallbacks to a simple `Invoke()`.
// //
// 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) NotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, method string, args ...interface{}) error { func (c *Client) NotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce 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, method, args...) return c.NotaryInvoke(contract, fee, nonce, method, args...)
}) })
} }
@ -292,9 +295,12 @@ func (c *Client) NotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, method s
return c.Invoke(contract, fee, method, args...) return c.Invoke(contract, fee, method, args...)
} }
return c.notaryInvoke(false, true, contract, method, args...) return c.notaryInvoke(false, true, contract, nonce, method, args...)
} }
// randSource is a source of random numbers.
var randSource = rand.New()
// NotaryInvokeNotAlpha does the same as NotaryInvoke but does not use client's // NotaryInvokeNotAlpha does the same as NotaryInvoke but does not use client's
// private key in Invocation script. It means that main TX of notary request is // private key in Invocation script. It means that main TX of notary request is
// not expected to be signed by the current node. // not expected to be signed by the current node.
@ -311,7 +317,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, method, args...) return c.notaryInvoke(false, false, contract, randSource.Uint32(), method, args...)
} }
// NotarySignAndInvokeTX signs and sends notary request that was received from // NotarySignAndInvokeTX signs and sends notary request that was received from
@ -359,16 +365,16 @@ func (c *Client) NotarySignAndInvokeTX(mainTx *transaction.Transaction) error {
return nil return nil
} }
func (c *Client) notaryInvokeAsCommittee(method string, args ...interface{}) error { func (c *Client) notaryInvokeAsCommittee(method string, nonce 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, method, args...) return c.notaryInvoke(true, true, designate, nonce, method, args...)
} }
func (c *Client) notaryInvoke(committee, invokedByAlpha bool, contract util.Uint160, method string, args ...interface{}) error { func (c *Client) notaryInvoke(committee, invokedByAlpha bool, contract util.Uint160, nonce 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
@ -417,7 +423,7 @@ func (c *Client) notaryInvoke(committee, invokedByAlpha bool, contract util.Uint
// prepare main tx // prepare main tx
mainTx := &transaction.Transaction{ mainTx := &transaction.Transaction{
Nonce: 1, Nonce: nonce,
SystemFee: test.GasConsumed, SystemFee: test.GasConsumed,
ValidUntilBlock: until, ValidUntilBlock: until,
Script: test.Script, Script: test.Script,

View file

@ -78,7 +78,8 @@ func (s StaticClient) Morph() *Client {
func (s StaticClient) Invoke(method string, args ...interface{}) error { func (s StaticClient) Invoke(method string, args ...interface{}) error {
if s.tryNotary { if s.tryNotary {
if s.alpha { if s.alpha {
return s.client.NotaryInvoke(s.scScriptHash, s.fee, method, args...) // FIXME: do not use constant nonce for alphabet NR: #844
return s.client.NotaryInvoke(s.scScriptHash, s.fee, 1, method, args...)
} }
return s.client.NotaryInvokeNotAlpha(s.scScriptHash, s.fee, method, args...) return s.client.NotaryInvokeNotAlpha(s.scScriptHash, s.fee, method, args...)