github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/services/notary/core_test.go (about)

     1  package notary_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/big"
     7  	"math/rand"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/nspcc-dev/neo-go/pkg/config"
    13  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
    14  	"github.com/nspcc-dev/neo-go/pkg/core"
    15  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
    17  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
    18  	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
    19  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    20  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    21  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    22  	"github.com/nspcc-dev/neo-go/pkg/io"
    23  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    24  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    25  	"github.com/nspcc-dev/neo-go/pkg/network"
    26  	"github.com/nspcc-dev/neo-go/pkg/network/payload"
    27  	"github.com/nspcc-dev/neo-go/pkg/services/notary"
    28  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    29  	"github.com/nspcc-dev/neo-go/pkg/util"
    30  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    31  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    32  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    33  	"github.com/stretchr/testify/require"
    34  	"go.uber.org/zap/zaptest"
    35  )
    36  
    37  func getTestNotary(t *testing.T, bc *core.Blockchain, walletPath, pass string, onTx func(tx *transaction.Transaction) error) (*wallet.Account, *notary.Notary, *mempool.Pool) {
    38  	mainCfg := config.P2PNotary{
    39  		Enabled: true,
    40  		UnlockWallet: config.Wallet{
    41  			Path:     walletPath,
    42  			Password: pass,
    43  		},
    44  	}
    45  	cfg := notary.Config{
    46  		MainCfg: mainCfg,
    47  		Chain:   bc,
    48  		Log:     zaptest.NewLogger(t),
    49  	}
    50  	mp := mempool.New(10, 1, true, nil)
    51  	ntr, err := notary.NewNotary(cfg, netmode.UnitTestNet, mp, onTx)
    52  	require.NoError(t, err)
    53  
    54  	w, err := wallet.NewWalletFromFile(walletPath)
    55  	require.NoError(t, err)
    56  	require.NoError(t, w.Accounts[0].Decrypt(pass, w.Scrypt))
    57  	return w.Accounts[0], ntr, mp
    58  }
    59  
    60  // dupNotaryRequest duplicates notary request by serializing/deserializing it. Use
    61  // it to avoid data races when reusing the same payload. Normal OnNewRequest handler
    62  // never receives the same (as in the same pointer) payload multiple times, even if
    63  // the contents is the same it would be a separate buffer.
    64  func dupNotaryRequest(t *testing.T, p *payload.P2PNotaryRequest) *payload.P2PNotaryRequest {
    65  	b, err := p.Bytes()
    66  	require.NoError(t, err)
    67  	r, err := payload.NewP2PNotaryRequestFromBytes(b)
    68  	require.NoError(t, err)
    69  	return r
    70  }
    71  
    72  func TestNotary(t *testing.T) {
    73  	bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
    74  		c.P2PSigExtensions = true
    75  	})
    76  	e := neotest.NewExecutor(t, bc, validators, committee)
    77  	notaryHash := e.NativeHash(t, nativenames.Notary)
    78  	designationSuperInvoker := e.NewInvoker(e.NativeHash(t, nativenames.Designation), validators, committee)
    79  	gasValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas))
    80  
    81  	var (
    82  		nonce           uint32
    83  		nvbDiffFallback uint32 = 20
    84  	)
    85  
    86  	mtx := sync.RWMutex{}
    87  	completedTxes := make(map[util.Uint256]*transaction.Transaction)
    88  	var unluckies []*payload.P2PNotaryRequest
    89  	var (
    90  		finalizeWithError bool
    91  		choosy            bool
    92  	)
    93  	setFinalizeWithError := func(v bool) {
    94  		mtx.Lock()
    95  		finalizeWithError = v
    96  		mtx.Unlock()
    97  	}
    98  	setChoosy := func(v bool) {
    99  		mtx.Lock()
   100  		choosy = v
   101  		mtx.Unlock()
   102  	}
   103  	onTransaction := func(tx *transaction.Transaction) error {
   104  		mtx.Lock()
   105  		defer mtx.Unlock()
   106  		if !choosy {
   107  			if completedTxes[tx.Hash()] != nil {
   108  				panic("transaction was completed twice")
   109  			}
   110  			if finalizeWithError {
   111  				return errors.New("error while finalizing transaction")
   112  			}
   113  			completedTxes[tx.Hash()] = tx
   114  			return nil
   115  		}
   116  		for _, unl := range unluckies {
   117  			if tx.Hash().Equals(unl.FallbackTransaction.Hash()) {
   118  				return errors.New("error while finalizing transaction")
   119  			}
   120  		}
   121  		completedTxes[tx.Hash()] = tx
   122  		return nil
   123  	}
   124  	getCompletedTx := func(t *testing.T, waitForNonNil bool, h util.Uint256) *transaction.Transaction {
   125  		if !waitForNonNil {
   126  			mtx.RLock()
   127  			defer mtx.RUnlock()
   128  			return completedTxes[h]
   129  		}
   130  		var completedTx *transaction.Transaction
   131  		require.Eventually(t, func() bool {
   132  			mtx.RLock()
   133  			defer mtx.RUnlock()
   134  			completedTx = completedTxes[h]
   135  			return completedTx != nil
   136  		}, time.Second*3, time.Millisecond*50, errors.New("transaction expected to be completed"))
   137  		return completedTx
   138  	}
   139  
   140  	acc1, ntr1, mp1 := getTestNotary(t, bc, "./testdata/notary1.json", "one", onTransaction)
   141  	acc2, _, _ := getTestNotary(t, bc, "./testdata/notary2.json", "two", onTransaction)
   142  	randomAcc, err := keys.NewPrivateKey()
   143  	require.NoError(t, err)
   144  
   145  	bc.SetNotary(ntr1)
   146  	bc.RegisterPostBlock(func(f func(*transaction.Transaction, *mempool.Pool, bool) bool, pool *mempool.Pool, b *block.Block) {
   147  		ntr1.PostPersist()
   148  	})
   149  
   150  	mp1.RunSubscriptions()
   151  	ntr1.Start()
   152  	t.Cleanup(func() {
   153  		ntr1.Shutdown()
   154  		mp1.StopSubscriptions()
   155  	})
   156  
   157  	notaryNodes := []any{acc1.PublicKey().Bytes(), acc2.PrivateKey().PublicKey().Bytes()}
   158  	designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
   159  		int64(noderoles.P2PNotary), notaryNodes)
   160  
   161  	type requester struct {
   162  		accounts []*wallet.Account
   163  		m        int
   164  		typ      notary.RequestType
   165  	}
   166  	createFallbackTx := func(requester *wallet.Account, mainTx *transaction.Transaction, nvbIncrement ...uint32) *transaction.Transaction {
   167  		fallback := transaction.New([]byte{byte(opcode.RET)}, 2000_0000)
   168  		fallback.Nonce = nonce
   169  		nonce++
   170  		fallback.SystemFee = 1_0000_0000
   171  		fallback.ValidUntilBlock = bc.BlockHeight() + 2*nvbDiffFallback
   172  		fallback.Signers = []transaction.Signer{
   173  			{
   174  				Account: bc.GetNotaryContractScriptHash(),
   175  				Scopes:  transaction.None,
   176  			},
   177  			{
   178  				Account: requester.ScriptHash(),
   179  				Scopes:  transaction.None,
   180  			},
   181  		}
   182  		nvb := bc.BlockHeight() + nvbDiffFallback
   183  		if len(nvbIncrement) != 0 {
   184  			nvb += nvbIncrement[0]
   185  		}
   186  		fallback.Attributes = []transaction.Attribute{
   187  			{
   188  				Type:  transaction.NotaryAssistedT,
   189  				Value: &transaction.NotaryAssisted{NKeys: 0},
   190  			},
   191  			{
   192  				Type:  transaction.NotValidBeforeT,
   193  				Value: &transaction.NotValidBefore{Height: nvb},
   194  			},
   195  			{
   196  				Type:  transaction.ConflictsT,
   197  				Value: &transaction.Conflicts{Hash: mainTx.Hash()},
   198  			},
   199  		}
   200  		fallback.Scripts = []transaction.Witness{
   201  			{
   202  				InvocationScript:   append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...),
   203  				VerificationScript: []byte{},
   204  			},
   205  		}
   206  		err = requester.SignTx(netmode.UnitTestNet, fallback)
   207  		require.NoError(t, err)
   208  		return fallback
   209  	}
   210  	createMixedRequest := func(requesters []requester, NVBincrements ...uint32) []*payload.P2PNotaryRequest {
   211  		mainTx := *transaction.New([]byte{byte(opcode.RET)}, 11000000)
   212  		mainTx.Nonce = nonce
   213  		nonce++
   214  		mainTx.SystemFee = 100000000
   215  		mainTx.ValidUntilBlock = bc.BlockHeight() + 2*nvbDiffFallback
   216  		signers := make([]transaction.Signer, len(requesters)+1)
   217  		var (
   218  			nKeys               uint8
   219  			verificationScripts [][]byte
   220  		)
   221  		for i := range requesters {
   222  			var script []byte
   223  			switch requesters[i].typ {
   224  			case notary.Signature:
   225  				script = requesters[i].accounts[0].PublicKey().GetVerificationScript()
   226  				nKeys++
   227  			case notary.MultiSignature:
   228  				pubs := make(keys.PublicKeys, len(requesters[i].accounts))
   229  				for j, r := range requesters[i].accounts {
   230  					pubs[j] = r.PublicKey()
   231  				}
   232  				script, err = smartcontract.CreateMultiSigRedeemScript(requesters[i].m, pubs)
   233  				require.NoError(t, err)
   234  				nKeys += uint8(len(requesters[i].accounts))
   235  			}
   236  			signers[i] = transaction.Signer{
   237  				Account: hash.Hash160(script),
   238  				Scopes:  transaction.None,
   239  			}
   240  			verificationScripts = append(verificationScripts, script)
   241  		}
   242  		signers[len(signers)-1] = transaction.Signer{
   243  			Account: bc.GetNotaryContractScriptHash(),
   244  			Scopes:  transaction.None,
   245  		}
   246  		mainTx.Signers = signers
   247  		mainTx.Attributes = []transaction.Attribute{
   248  			{
   249  				Type:  transaction.NotaryAssistedT,
   250  				Value: &transaction.NotaryAssisted{NKeys: nKeys},
   251  			},
   252  		}
   253  		payloads := make([]*payload.P2PNotaryRequest, nKeys)
   254  		plIndex := 0
   255  		// we'll collect only m signatures out of n (so only m payloads are needed), but let's create payloads for all requesters (for the next tests)
   256  		for i, r := range requesters {
   257  			for _, acc := range r.accounts {
   258  				cp := mainTx
   259  				main := &cp
   260  				main.Scripts = make([]transaction.Witness, len(requesters))
   261  				for j := range main.Scripts {
   262  					main.Scripts[j].VerificationScript = verificationScripts[j]
   263  					if i == j {
   264  						main.Scripts[j].InvocationScript = append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, acc.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), main)...)
   265  					}
   266  				}
   267  				main.Scripts = append(main.Scripts, transaction.Witness{}) // empty Notary witness
   268  
   269  				_ = main.Size() // for size update test
   270  
   271  				var fallback *transaction.Transaction
   272  				if len(NVBincrements) == int(nKeys) {
   273  					fallback = createFallbackTx(acc, main, NVBincrements[plIndex])
   274  				} else {
   275  					fallback = createFallbackTx(acc, main)
   276  				}
   277  
   278  				_ = fallback.Size() // for size update test
   279  
   280  				payloads[plIndex] = &payload.P2PNotaryRequest{
   281  					MainTransaction:     main,
   282  					FallbackTransaction: fallback,
   283  				}
   284  				plIndex++
   285  			}
   286  		}
   287  		return payloads
   288  	}
   289  	checkMainTx := func(t *testing.T, requesters []requester, requests []*payload.P2PNotaryRequest, sentCount int, shouldComplete bool) {
   290  		nSigs := 0
   291  		for _, r := range requesters {
   292  			switch r.typ {
   293  			case notary.Signature:
   294  				nSigs++
   295  			case notary.MultiSignature:
   296  				nSigs += r.m
   297  			}
   298  		}
   299  		nSigners := len(requesters) + 1
   300  		if sentCount >= nSigs && shouldComplete {
   301  			completedTx := getCompletedTx(t, true, requests[0].MainTransaction.Hash())
   302  			require.Equal(t, nSigners, len(completedTx.Signers))
   303  			require.Equal(t, nSigners, len(completedTx.Scripts))
   304  
   305  			// check that tx size was updated
   306  			require.Equal(t, io.GetVarSize(completedTx), completedTx.Size())
   307  
   308  			for i := 0; i < len(completedTx.Scripts)-1; i++ {
   309  				_, err := bc.VerifyWitness(completedTx.Signers[i].Account, completedTx, &completedTx.Scripts[i], -1)
   310  				require.NoError(t, err)
   311  			}
   312  			require.Equal(t, transaction.Witness{
   313  				InvocationScript:   append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, acc1.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), requests[0].MainTransaction)...),
   314  				VerificationScript: []byte{},
   315  			}, completedTx.Scripts[len(completedTx.Scripts)-1])
   316  		} else {
   317  			completedTx := getCompletedTx(t, false, requests[0].MainTransaction.Hash())
   318  			require.Nil(t, completedTx, fmt.Errorf("main transaction shouldn't be completed: sent %d out of %d requests", sentCount, nSigs))
   319  		}
   320  	}
   321  	checkFallbackTxs := func(t *testing.T, requests []*payload.P2PNotaryRequest, shouldComplete bool) {
   322  		for i, req := range requests {
   323  			if shouldComplete {
   324  				completedTx := getCompletedTx(t, true, req.FallbackTransaction.Hash())
   325  				require.Equal(t, 2, len(completedTx.Signers))
   326  				require.Equal(t, 2, len(completedTx.Scripts))
   327  				require.Equal(t, transaction.Witness{
   328  					InvocationScript:   append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, acc1.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), req.FallbackTransaction)...),
   329  					VerificationScript: []byte{},
   330  				}, completedTx.Scripts[0])
   331  
   332  				// check that tx size was updated
   333  				require.Equal(t, io.GetVarSize(completedTx), completedTx.Size())
   334  
   335  				_, err := bc.VerifyWitness(completedTx.Signers[1].Account, completedTx, &completedTx.Scripts[1], -1)
   336  				require.NoError(t, err)
   337  			} else {
   338  				completedTx := getCompletedTx(t, false, req.FallbackTransaction.Hash())
   339  				require.Nil(t, completedTx, fmt.Errorf("fallback transaction for request #%d shouldn't be completed", i))
   340  			}
   341  		}
   342  	}
   343  	checkCompleteStandardRequest := func(t *testing.T, nKeys int, shouldComplete bool, nvbIncrements ...uint32) ([]*payload.P2PNotaryRequest, []requester) {
   344  		requesters := make([]requester, nKeys)
   345  		for i := range requesters {
   346  			acc, _ := wallet.NewAccount()
   347  			requesters[i] = requester{
   348  				accounts: []*wallet.Account{acc},
   349  				typ:      notary.Signature,
   350  			}
   351  		}
   352  
   353  		requests := createMixedRequest(requesters, nvbIncrements...)
   354  		sendOrder := make([]int, nKeys)
   355  		for i := range sendOrder {
   356  			sendOrder[i] = i
   357  		}
   358  		rand.Shuffle(nKeys, func(i, j int) {
   359  			sendOrder[j], sendOrder[i] = sendOrder[i], sendOrder[j]
   360  		})
   361  		for i := range requests {
   362  			ntr1.OnNewRequest(requests[sendOrder[i]])
   363  			checkMainTx(t, requesters, requests, i+1, shouldComplete)
   364  			completedCount := len(completedTxes)
   365  
   366  			// check that the same request won't be processed twice
   367  			ntr1.OnNewRequest(dupNotaryRequest(t, requests[sendOrder[i]]))
   368  			checkMainTx(t, requesters, requests, i+1, shouldComplete)
   369  			require.Equal(t, completedCount, len(completedTxes))
   370  		}
   371  		return requests, requesters
   372  	}
   373  	checkCompleteMultisigRequest := func(t *testing.T, nSigs int, nKeys int, shouldComplete bool) ([]*payload.P2PNotaryRequest, []requester) {
   374  		accounts := make([]*wallet.Account, nKeys)
   375  		for i := range accounts {
   376  			accounts[i], _ = wallet.NewAccount()
   377  		}
   378  		requesters := []requester{
   379  			{
   380  				accounts: accounts,
   381  				m:        nSigs,
   382  				typ:      notary.MultiSignature,
   383  			},
   384  		}
   385  		requests := createMixedRequest(requesters)
   386  		sendOrder := make([]int, nKeys)
   387  		for i := range sendOrder {
   388  			sendOrder[i] = i
   389  		}
   390  		rand.Shuffle(nKeys, func(i, j int) {
   391  			sendOrder[j], sendOrder[i] = sendOrder[i], sendOrder[j]
   392  		})
   393  
   394  		var submittedRequests []*payload.P2PNotaryRequest
   395  		// sent only nSigs (m out of n) requests - it should be enough to complete min tx
   396  		for i := 0; i < nSigs; i++ {
   397  			submittedRequests = append(submittedRequests, requests[sendOrder[i]])
   398  
   399  			ntr1.OnNewRequest(requests[sendOrder[i]])
   400  			checkMainTx(t, requesters, submittedRequests, i+1, shouldComplete)
   401  
   402  			// check that the same request won't be processed twice
   403  			ntr1.OnNewRequest(dupNotaryRequest(t, requests[sendOrder[i]]))
   404  			checkMainTx(t, requesters, submittedRequests, i+1, shouldComplete)
   405  		}
   406  
   407  		// sent the rest (n-m) out of n requests: main tx is already collected, so only fallbacks should be applied
   408  		completedCount := len(completedTxes)
   409  		for i := nSigs; i < nKeys; i++ {
   410  			submittedRequests = append(submittedRequests, requests[sendOrder[i]])
   411  
   412  			ntr1.OnNewRequest(requests[sendOrder[i]])
   413  			checkMainTx(t, requesters, submittedRequests, i+1, shouldComplete)
   414  			require.Equal(t, completedCount, len(completedTxes))
   415  		}
   416  
   417  		return submittedRequests, requesters
   418  	}
   419  
   420  	checkCompleteMixedRequest := func(t *testing.T, nSigSigners int, shouldComplete bool) ([]*payload.P2PNotaryRequest, []requester) {
   421  		requesters := make([]requester, nSigSigners)
   422  		for i := range requesters {
   423  			acc, _ := wallet.NewAccount()
   424  			requesters[i] = requester{
   425  				accounts: []*wallet.Account{acc},
   426  				typ:      notary.Signature,
   427  			}
   428  		}
   429  		multisigAccounts := make([]*wallet.Account, 3)
   430  		for i := range multisigAccounts {
   431  			multisigAccounts[i], _ = wallet.NewAccount()
   432  		}
   433  
   434  		requesters = append(requesters, requester{
   435  			accounts: multisigAccounts,
   436  			m:        2,
   437  			typ:      notary.MultiSignature,
   438  		})
   439  
   440  		requests := createMixedRequest(requesters)
   441  		for i := range requests {
   442  			ntr1.OnNewRequest(requests[i])
   443  			checkMainTx(t, requesters, requests, i+1, shouldComplete)
   444  			completedCount := len(completedTxes)
   445  
   446  			// check that the same request won't be processed twice
   447  			ntr1.OnNewRequest(dupNotaryRequest(t, requests[i]))
   448  			checkMainTx(t, requesters, requests, i+1, shouldComplete)
   449  			require.Equal(t, completedCount, len(completedTxes))
   450  		}
   451  		return requests, requesters
   452  	}
   453  
   454  	// OnNewRequest: missing account
   455  	ntr1.UpdateNotaryNodes(keys.PublicKeys{randomAcc.PublicKey()})
   456  	r, _ := checkCompleteStandardRequest(t, 1, false)
   457  	checkFallbackTxs(t, r, false)
   458  	// set account back for the next tests
   459  	ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PublicKey()})
   460  
   461  	// OnNewRequest: signature request
   462  	for _, i := range []int{1, 2, 3, 10} {
   463  		r, _ := checkCompleteStandardRequest(t, i, true)
   464  		checkFallbackTxs(t, r, false)
   465  	}
   466  
   467  	// OnNewRequest: multisignature request
   468  	r, _ = checkCompleteMultisigRequest(t, 1, 1, true)
   469  	checkFallbackTxs(t, r, false)
   470  	r, _ = checkCompleteMultisigRequest(t, 1, 2, true)
   471  	checkFallbackTxs(t, r, false)
   472  	r, _ = checkCompleteMultisigRequest(t, 1, 3, true)
   473  	checkFallbackTxs(t, r, false)
   474  	r, _ = checkCompleteMultisigRequest(t, 3, 3, true)
   475  	checkFallbackTxs(t, r, false)
   476  	r, _ = checkCompleteMultisigRequest(t, 3, 4, true)
   477  	checkFallbackTxs(t, r, false)
   478  	r, _ = checkCompleteMultisigRequest(t, 3, 10, true)
   479  	checkFallbackTxs(t, r, false)
   480  
   481  	// OnNewRequest: mixed request
   482  	r, _ = checkCompleteMixedRequest(t, 1, true)
   483  	checkFallbackTxs(t, r, false)
   484  	r, _ = checkCompleteMixedRequest(t, 2, true)
   485  	checkFallbackTxs(t, r, false)
   486  	r, _ = checkCompleteMixedRequest(t, 3, true)
   487  	checkFallbackTxs(t, r, false)
   488  	// PostPersist: missing account
   489  	setFinalizeWithError(true)
   490  	r, requesters := checkCompleteStandardRequest(t, 1, false)
   491  	checkFallbackTxs(t, r, false)
   492  	ntr1.UpdateNotaryNodes(keys.PublicKeys{randomAcc.PublicKey()})
   493  	setFinalizeWithError(false)
   494  
   495  	e.AddNewBlock(t)
   496  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   497  	e.AddNewBlock(t)
   498  	checkMainTx(t, requesters, r, 1, false)
   499  	checkFallbackTxs(t, r, false)
   500  	// set account back for the next tests
   501  	ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PublicKey()})
   502  
   503  	// PostPersist: complete main transaction, signature request
   504  	setFinalizeWithError(true)
   505  	requests, requesters := checkCompleteStandardRequest(t, 3, false)
   506  	// check PostPersist with finalisation error
   507  	setFinalizeWithError(true)
   508  	e.AddNewBlock(t)
   509  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   510  	e.AddNewBlock(t)
   511  	checkMainTx(t, requesters, requests, len(requests), false)
   512  	// check PostPersist without finalisation error
   513  	setFinalizeWithError(false)
   514  	e.AddNewBlock(t)
   515  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   516  	e.AddNewBlock(t)
   517  	checkMainTx(t, requesters, requests, len(requests), true)
   518  
   519  	// PostPersist: complete main transaction, multisignature account
   520  	setFinalizeWithError(true)
   521  	requests, requesters = checkCompleteMultisigRequest(t, 3, 4, false)
   522  	checkFallbackTxs(t, requests, false)
   523  	// check PostPersist with finalisation error
   524  	setFinalizeWithError(true)
   525  	e.AddNewBlock(t)
   526  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   527  	e.AddNewBlock(t)
   528  	checkMainTx(t, requesters, requests, len(requests), false)
   529  	checkFallbackTxs(t, requests, false)
   530  	// check PostPersist without finalisation error
   531  	setFinalizeWithError(false)
   532  	e.AddNewBlock(t)
   533  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   534  	e.AddNewBlock(t)
   535  	checkMainTx(t, requesters, requests, len(requests), true)
   536  	checkFallbackTxs(t, requests, false)
   537  
   538  	// PostPersist: complete fallback, signature request
   539  	setFinalizeWithError(true)
   540  	requests, requesters = checkCompleteStandardRequest(t, 3, false)
   541  	checkFallbackTxs(t, requests, false)
   542  	// make fallbacks valid
   543  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   544  	require.NoError(t, err)
   545  	// check PostPersist for valid fallbacks with finalisation error
   546  	e.AddNewBlock(t)
   547  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   548  	e.AddNewBlock(t)
   549  	checkMainTx(t, requesters, requests, len(requests), false)
   550  	checkFallbackTxs(t, requests, false)
   551  	// check PostPersist for valid fallbacks without finalisation error
   552  	setFinalizeWithError(false)
   553  	e.AddNewBlock(t)
   554  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   555  	e.AddNewBlock(t)
   556  	checkMainTx(t, requesters, requests, len(requests), false)
   557  	checkFallbackTxs(t, requests, true)
   558  
   559  	// PostPersist: complete fallback, multisignature request
   560  	nSigs, nKeys := 3, 5
   561  	// check OnNewRequest with finalization error
   562  	setFinalizeWithError(true)
   563  	requests, requesters = checkCompleteMultisigRequest(t, nSigs, nKeys, false)
   564  	checkFallbackTxs(t, requests, false)
   565  	// make fallbacks valid
   566  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   567  	require.NoError(t, err)
   568  	// check PostPersist for valid fallbacks with finalisation error
   569  	e.AddNewBlock(t)
   570  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   571  	e.AddNewBlock(t)
   572  	checkMainTx(t, requesters, requests, len(requests), false)
   573  	checkFallbackTxs(t, requests, false)
   574  	// check PostPersist for valid fallbacks without finalisation error
   575  	setFinalizeWithError(false)
   576  	e.AddNewBlock(t)
   577  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   578  	e.AddNewBlock(t)
   579  	checkMainTx(t, requesters, requests, len(requests), false)
   580  	checkFallbackTxs(t, requests[:nSigs], true)
   581  	// the rest of fallbacks should also be applied even if the main tx was already constructed by the moment they were sent
   582  	checkFallbackTxs(t, requests[nSigs:], true)
   583  
   584  	// PostPersist: partial fallbacks completion due to finalisation errors
   585  	setFinalizeWithError(true)
   586  	requests, requesters = checkCompleteStandardRequest(t, 5, false)
   587  	checkFallbackTxs(t, requests, false)
   588  	// make fallbacks valid
   589  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   590  	require.NoError(t, err)
   591  	// some of fallbacks should fail finalisation
   592  	unluckies = []*payload.P2PNotaryRequest{requests[0], requests[4]}
   593  	lucky := requests[1:4]
   594  	setChoosy(true)
   595  	// check PostPersist for lucky fallbacks
   596  	e.AddNewBlock(t)
   597  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   598  	e.AddNewBlock(t)
   599  	checkMainTx(t, requesters, requests, len(requests), false)
   600  	checkFallbackTxs(t, lucky, true)
   601  	checkFallbackTxs(t, unluckies, false)
   602  	// reset finalisation function for unlucky fallbacks to finalise without an error
   603  	setChoosy(false)
   604  	setFinalizeWithError(false)
   605  	// check PostPersist for unlucky fallbacks
   606  	e.AddNewBlock(t)
   607  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   608  	e.AddNewBlock(t)
   609  	checkMainTx(t, requesters, requests, len(requests), false)
   610  	checkFallbackTxs(t, lucky, true)
   611  	checkFallbackTxs(t, unluckies, true)
   612  
   613  	// PostPersist: different NVBs
   614  	// check OnNewRequest with finalization error and different NVBs
   615  	setFinalizeWithError(true)
   616  	// Introduce some slippage between first and second fallback NVBs in order to avoid possible race caused by early
   617  	// first fallback transaction acceptance. The rest of fallbacks follow X+4 NVB pattern for testing code shortness.
   618  	requests, requesters = checkCompleteStandardRequest(t, 5, false, 1, 7, 11, 15, 19)
   619  	checkFallbackTxs(t, requests, false)
   620  	// generate blocks to reach the most earlier fallback's NVB
   621  	// Here and below add +1 slippage to ensure that PostPersist for (nvbDiffFallback+1) height is properly handled, i.e.
   622  	// to exclude race condition when main transaction is finalized between `finalizeWithError` disabling and new block addition.
   623  	e.GenerateNewBlocks(t, int((nvbDiffFallback+1)+1))
   624  	require.NoError(t, err)
   625  	// check PostPersist for valid fallbacks without finalisation error
   626  	setFinalizeWithError(false)
   627  	for i := range requests {
   628  		e.AddNewBlock(t)
   629  		e.AddNewBlock(t)
   630  		e.AddNewBlock(t)
   631  		e.AddNewBlock(t)
   632  
   633  		checkMainTx(t, requesters, requests, len(requests), false)
   634  		checkFallbackTxs(t, requests[:i+1], true)
   635  		checkFallbackTxs(t, requests[i+1:], false)
   636  	}
   637  
   638  	// OnRequestRemoval: missing account
   639  	// check OnNewRequest with finalization error
   640  	setFinalizeWithError(true)
   641  	requests, requesters = checkCompleteStandardRequest(t, 4, false)
   642  	checkFallbackTxs(t, requests, false)
   643  	// make fallbacks valid and remove one fallback
   644  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   645  	require.NoError(t, err)
   646  	ntr1.UpdateNotaryNodes(keys.PublicKeys{randomAcc.PublicKey()})
   647  	ntr1.OnRequestRemoval(requests[3])
   648  	// non of the fallbacks should be completed
   649  	setFinalizeWithError(false)
   650  	e.AddNewBlock(t)
   651  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   652  	e.AddNewBlock(t)
   653  	checkMainTx(t, requesters, requests, len(requests), false)
   654  	checkFallbackTxs(t, requests, false)
   655  	// set account back for the next tests
   656  	ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PublicKey()})
   657  
   658  	// OnRequestRemoval: signature request, remove one fallback
   659  	// check OnNewRequest with finalization error
   660  	setFinalizeWithError(true)
   661  	requests, requesters = checkCompleteStandardRequest(t, 4, false)
   662  	checkFallbackTxs(t, requests, false)
   663  	// make fallbacks valid and remove one fallback
   664  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   665  	require.NoError(t, err)
   666  	unlucky := requests[3]
   667  	ntr1.OnRequestRemoval(unlucky)
   668  	// rest of the fallbacks should be completed
   669  	setFinalizeWithError(false)
   670  	e.AddNewBlock(t)
   671  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   672  	e.AddNewBlock(t)
   673  	checkMainTx(t, requesters, requests, len(requests), false)
   674  	checkFallbackTxs(t, requests[:3], true)
   675  	require.Nil(t, completedTxes[unlucky.FallbackTransaction.Hash()])
   676  
   677  	// OnRequestRemoval: signature request, remove all fallbacks
   678  	setFinalizeWithError(true)
   679  	requests, requesters = checkCompleteStandardRequest(t, 4, false)
   680  	// remove all fallbacks
   681  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   682  	require.NoError(t, err)
   683  	for i := range requests {
   684  		ntr1.OnRequestRemoval(requests[i])
   685  	}
   686  	// then the whole request should be removed, i.e. there are no completed transactions
   687  	setFinalizeWithError(false)
   688  	e.AddNewBlock(t)
   689  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   690  	e.AddNewBlock(t)
   691  	checkMainTx(t, requesters, requests, len(requests), false)
   692  	checkFallbackTxs(t, requests, false)
   693  
   694  	// OnRequestRemoval: signature request, remove unexisting fallback
   695  	ntr1.OnRequestRemoval(requests[0])
   696  	e.AddNewBlock(t)
   697  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   698  	e.AddNewBlock(t)
   699  	checkMainTx(t, requesters, requests, len(requests), false)
   700  	checkFallbackTxs(t, requests, false)
   701  
   702  	// OnRequestRemoval: multisignature request, remove one fallback
   703  	nSigs, nKeys = 3, 5
   704  	// check OnNewRequest with finalization error
   705  	setFinalizeWithError(true)
   706  	requests, requesters = checkCompleteMultisigRequest(t, nSigs, nKeys, false)
   707  	checkMainTx(t, requesters, requests, len(requests), false)
   708  	checkFallbackTxs(t, requests, false)
   709  	// make fallbacks valid and remove the last fallback
   710  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   711  	require.NoError(t, err)
   712  	unlucky = requests[nSigs-1]
   713  	ntr1.OnRequestRemoval(unlucky)
   714  	// then (m-1) out of n fallbacks should be completed
   715  	setFinalizeWithError(false)
   716  	e.AddNewBlock(t)
   717  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   718  	e.AddNewBlock(t)
   719  	checkMainTx(t, requesters, requests, len(requests), false)
   720  	checkFallbackTxs(t, requests[:nSigs-1], true)
   721  	require.Nil(t, completedTxes[unlucky.FallbackTransaction.Hash()])
   722  	//  the rest (n-(m-1)) out of n fallbacks should also be completed even if main tx has been collected by the moment they were sent
   723  	checkFallbackTxs(t, requests[nSigs:], true)
   724  
   725  	// OnRequestRemoval: multisignature request, remove all fallbacks
   726  	setFinalizeWithError(true)
   727  	requests, requesters = checkCompleteMultisigRequest(t, nSigs, nKeys, false)
   728  	// make fallbacks valid and then remove all of them
   729  	e.GenerateNewBlocks(t, int(nvbDiffFallback+1))
   730  	require.NoError(t, err)
   731  	for i := range requests {
   732  		ntr1.OnRequestRemoval(requests[i])
   733  	}
   734  	// then the whole request should be removed, i.e. there are no completed transactions
   735  	setFinalizeWithError(false)
   736  	e.AddNewBlock(t)
   737  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   738  	e.AddNewBlock(t)
   739  	checkMainTx(t, requesters, requests, len(requests), false)
   740  	checkFallbackTxs(t, requests, false)
   741  
   742  	// // OnRequestRemoval: multisignature request, remove unexisting fallbac, i.e. there still shouldn't be any completed transactions after this
   743  	ntr1.OnRequestRemoval(requests[0])
   744  	e.AddNewBlock(t)
   745  	// Allow a single-block slippage since PostPersist is handled by Notary service via block notification routine.
   746  	e.AddNewBlock(t)
   747  	checkMainTx(t, requesters, requests, len(requests), false)
   748  	checkFallbackTxs(t, requests, false)
   749  
   750  	// Subscriptions test
   751  	setFinalizeWithError(false)
   752  	requester1, _ := wallet.NewAccount()
   753  	requester2, _ := wallet.NewAccount()
   754  	amount := int64(100_0000_0000)
   755  	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []any{requester1.ScriptHash(), int64(bc.BlockHeight() + 50)})
   756  	e.CheckGASBalance(t, notaryHash, big.NewInt(amount))
   757  	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []any{requester2.ScriptHash(), int64(bc.BlockHeight() + 50)})
   758  	e.CheckGASBalance(t, notaryHash, big.NewInt(2*amount))
   759  
   760  	// create request for 2 standard signatures => main tx should be completed after the second request is added to the pool
   761  	requests = createMixedRequest([]requester{
   762  		{
   763  			accounts: []*wallet.Account{requester1},
   764  			typ:      notary.Signature,
   765  		},
   766  		{
   767  			accounts: []*wallet.Account{requester2},
   768  			typ:      notary.Signature,
   769  		},
   770  	})
   771  	feer := network.NewNotaryFeer(bc)
   772  	require.NoError(t, mp1.Add(requests[0].FallbackTransaction, feer, requests[0]))
   773  	require.NoError(t, mp1.Add(requests[1].FallbackTransaction, feer, requests[1]))
   774  	require.Eventually(t, func() bool {
   775  		mtx.RLock()
   776  		defer mtx.RUnlock()
   777  		return completedTxes[requests[0].MainTransaction.Hash()] != nil
   778  	}, 3*time.Second, 100*time.Millisecond)
   779  	checkFallbackTxs(t, requests, false)
   780  }
   781  
   782  func TestNotary_GenesisRoles(t *testing.T) {
   783  	const (
   784  		notaryPath = "./testdata/notary1.json"
   785  		notaryPass = "one"
   786  	)
   787  
   788  	w, err := wallet.NewWalletFromFile(notaryPath)
   789  	require.NoError(t, err)
   790  	require.NoError(t, w.Accounts[0].Decrypt(notaryPass, w.Scrypt))
   791  	acc := w.Accounts[0]
   792  
   793  	bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
   794  		c.P2PSigExtensions = true
   795  		c.Genesis.Roles = map[noderoles.Role]keys.PublicKeys{
   796  			noderoles.P2PNotary: {acc.PublicKey()},
   797  		}
   798  	})
   799  
   800  	_, ntr, _ := getTestNotary(t, bc, "./testdata/notary1.json", "one", func(tx *transaction.Transaction) error { return nil })
   801  	require.False(t, ntr.IsAuthorized())
   802  
   803  	bc.SetNotary(ntr)
   804  	require.True(t, ntr.IsAuthorized())
   805  }