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

     1  package notary
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/nspcc-dev/neo-go/internal/fakechain"
     7  	"github.com/nspcc-dev/neo-go/pkg/config"
     8  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
    10  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    11  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    12  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    13  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    14  	"github.com/nspcc-dev/neo-go/pkg/util"
    15  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    16  	"github.com/stretchr/testify/require"
    17  	"go.uber.org/zap/zaptest"
    18  )
    19  
    20  func TestWallet(t *testing.T) {
    21  	bc := fakechain.NewFakeChain()
    22  	mainCfg := config.P2PNotary{Enabled: true}
    23  	cfg := Config{
    24  		MainCfg: mainCfg,
    25  		Chain:   bc,
    26  		Log:     zaptest.NewLogger(t),
    27  	}
    28  	t.Run("unexisting wallet", func(t *testing.T) {
    29  		cfg.MainCfg.UnlockWallet.Path = "./testdata/does_not_exists.json"
    30  		_, err := NewNotary(cfg, netmode.UnitTestNet, mempool.New(1, 1, true, nil), nil)
    31  		require.Error(t, err)
    32  	})
    33  
    34  	t.Run("bad password", func(t *testing.T) {
    35  		cfg.MainCfg.UnlockWallet.Path = "./testdata/notary1.json"
    36  		cfg.MainCfg.UnlockWallet.Password = "invalid"
    37  		_, err := NewNotary(cfg, netmode.UnitTestNet, mempool.New(1, 1, true, nil), nil)
    38  		require.Error(t, err)
    39  	})
    40  
    41  	t.Run("good", func(t *testing.T) {
    42  		cfg.MainCfg.UnlockWallet.Path = "./testdata/notary1.json"
    43  		cfg.MainCfg.UnlockWallet.Password = "one"
    44  		_, err := NewNotary(cfg, netmode.UnitTestNet, mempool.New(1, 1, true, nil), nil)
    45  		require.NoError(t, err)
    46  	})
    47  }
    48  
    49  func TestVerifyIncompleteRequest(t *testing.T) {
    50  	bc := fakechain.NewFakeChain()
    51  	notaryContractHash := util.Uint160{1, 2, 3}
    52  	bc.NotaryContractScriptHash = notaryContractHash
    53  	_, ntr, _ := getTestNotary(t, bc, "./testdata/notary1.json", "one")
    54  	sig := append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...) // we're not interested in signature correctness
    55  	acc1, _ := keys.NewPrivateKey()
    56  	acc2, _ := keys.NewPrivateKey()
    57  	acc3, _ := keys.NewPrivateKey()
    58  	sigScript1 := acc1.PublicKey().GetVerificationScript()
    59  	sigScript2 := acc2.PublicKey().GetVerificationScript()
    60  	sigScript3 := acc3.PublicKey().GetVerificationScript()
    61  	multisigScript1, err := smartcontract.CreateMultiSigRedeemScript(1, keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()})
    62  	require.NoError(t, err)
    63  	multisigScriptHash1 := hash.Hash160(multisigScript1)
    64  	multisigScript2, err := smartcontract.CreateMultiSigRedeemScript(2, keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()})
    65  	require.NoError(t, err)
    66  	multisigScriptHash2 := hash.Hash160(multisigScript2)
    67  
    68  	checkErr := func(t *testing.T, tx *transaction.Transaction, nKeys uint8) {
    69  		witnessInfo, err := ntr.verifyIncompleteWitnesses(tx, nKeys)
    70  		require.Error(t, err)
    71  		require.Nil(t, witnessInfo)
    72  	}
    73  
    74  	errCases := map[string]struct {
    75  		tx    *transaction.Transaction
    76  		nKeys uint8
    77  	}{
    78  		"not enough signers": {
    79  			tx: &transaction.Transaction{
    80  				Signers: []transaction.Signer{{Account: notaryContractHash}},
    81  				Scripts: []transaction.Witness{{}},
    82  			},
    83  		},
    84  		"missing Notary witness": {
    85  			tx: &transaction.Transaction{
    86  				Signers: []transaction.Signer{{Account: acc1.GetScriptHash()}, {Account: acc2.GetScriptHash()}},
    87  				Scripts: []transaction.Witness{{}, {}},
    88  			},
    89  		},
    90  		"bad verification script": {
    91  			tx: &transaction.Transaction{
    92  				Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
    93  				Scripts: []transaction.Witness{
    94  					{
    95  						InvocationScript:   []byte{},
    96  						VerificationScript: []byte{1, 2, 3},
    97  					},
    98  					{},
    99  				},
   100  			},
   101  		},
   102  		"sig: bad nKeys": {
   103  			tx: &transaction.Transaction{
   104  				Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: acc2.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
   105  				Scripts: []transaction.Witness{
   106  					{
   107  						InvocationScript:   sig,
   108  						VerificationScript: sigScript1,
   109  					},
   110  					{
   111  						InvocationScript:   sig,
   112  						VerificationScript: sigScript2,
   113  					},
   114  					{},
   115  				},
   116  			},
   117  			nKeys: 3,
   118  		},
   119  		"multisig: bad witnesses count": {
   120  			tx: &transaction.Transaction{
   121  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: notaryContractHash}},
   122  				Scripts: []transaction.Witness{
   123  					{
   124  						InvocationScript:   sig,
   125  						VerificationScript: multisigScript1,
   126  					},
   127  				},
   128  			},
   129  			nKeys: 2,
   130  		},
   131  		"multisig: bad nKeys": {
   132  			tx: &transaction.Transaction{
   133  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: notaryContractHash}},
   134  				Scripts: []transaction.Witness{
   135  					{
   136  						InvocationScript:   sig,
   137  						VerificationScript: multisigScript1,
   138  					},
   139  					{},
   140  				},
   141  			},
   142  			nKeys: 2,
   143  		},
   144  	}
   145  
   146  	for name, errCase := range errCases {
   147  		t.Run(name, func(t *testing.T) {
   148  			checkErr(t, errCase.tx, errCase.nKeys)
   149  		})
   150  	}
   151  
   152  	testCases := map[string]struct {
   153  		tx           *transaction.Transaction
   154  		nKeys        uint8
   155  		expectedInfo []witnessInfo
   156  	}{
   157  		"single sig": {
   158  			tx: &transaction.Transaction{
   159  				Signers: []transaction.Signer{{Account: acc1.GetScriptHash()}, {Account: notaryContractHash}},
   160  				Scripts: []transaction.Witness{
   161  					{
   162  						InvocationScript:   sig,
   163  						VerificationScript: sigScript1,
   164  					},
   165  					{},
   166  				},
   167  			},
   168  			nKeys: 1,
   169  			expectedInfo: []witnessInfo{
   170  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   171  				{typ: Contract},
   172  			},
   173  		},
   174  		"multiple sig": {
   175  			tx: &transaction.Transaction{
   176  				Signers: []transaction.Signer{{Account: acc1.GetScriptHash()}, {Account: acc2.GetScriptHash()}, {Account: acc3.GetScriptHash()}, {Account: notaryContractHash}},
   177  				Scripts: []transaction.Witness{
   178  					{
   179  						InvocationScript:   sig,
   180  						VerificationScript: sigScript1,
   181  					},
   182  					{
   183  						InvocationScript:   []byte{},
   184  						VerificationScript: sigScript2,
   185  					},
   186  					{
   187  						InvocationScript:   sig,
   188  						VerificationScript: sigScript3,
   189  					},
   190  					{},
   191  				},
   192  			},
   193  			nKeys: 3,
   194  			expectedInfo: []witnessInfo{
   195  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   196  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc2.PublicKey()}},
   197  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc3.PublicKey()}},
   198  				{typ: Contract},
   199  			},
   200  		},
   201  		"single multisig 1 out of 3": {
   202  			tx: &transaction.Transaction{
   203  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: notaryContractHash}},
   204  				Scripts: []transaction.Witness{
   205  					{
   206  						InvocationScript:   sig,
   207  						VerificationScript: multisigScript1,
   208  					},
   209  					{},
   210  				},
   211  			},
   212  			nKeys: 3,
   213  			expectedInfo: []witnessInfo{
   214  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   215  				{typ: Contract},
   216  			},
   217  		},
   218  		"single multisig 2 out of 3": {
   219  			tx: &transaction.Transaction{
   220  				Signers: []transaction.Signer{{Account: multisigScriptHash2}, {Account: notaryContractHash}},
   221  				Scripts: []transaction.Witness{
   222  					{
   223  						InvocationScript:   sig,
   224  						VerificationScript: multisigScript2,
   225  					},
   226  					{},
   227  				},
   228  			},
   229  			nKeys: 3,
   230  			expectedInfo: []witnessInfo{
   231  				{typ: MultiSignature, nSigsLeft: 2, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   232  				{typ: Contract},
   233  			},
   234  		},
   235  		"empty sig + single multisig 1 out of 3": {
   236  			tx: &transaction.Transaction{
   237  				Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
   238  				Scripts: []transaction.Witness{
   239  					{
   240  						InvocationScript:   []byte{},
   241  						VerificationScript: sigScript1,
   242  					},
   243  					{
   244  						InvocationScript:   sig,
   245  						VerificationScript: multisigScript1,
   246  					},
   247  					{},
   248  				},
   249  			},
   250  			nKeys: 1 + 3,
   251  			expectedInfo: []witnessInfo{
   252  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   253  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   254  				{typ: Contract},
   255  			},
   256  		},
   257  		"single multisig 1 out of 3 + empty single sig": {
   258  			tx: &transaction.Transaction{
   259  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
   260  				Scripts: []transaction.Witness{
   261  					{
   262  						InvocationScript:   sig,
   263  						VerificationScript: multisigScript1,
   264  					},
   265  					{
   266  						InvocationScript:   []byte{},
   267  						VerificationScript: sigScript1,
   268  					},
   269  					{},
   270  				},
   271  			},
   272  			nKeys: 3 + 1,
   273  			expectedInfo: []witnessInfo{
   274  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   275  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   276  				{typ: Contract},
   277  			},
   278  		},
   279  		"several multisig witnesses": {
   280  			tx: &transaction.Transaction{
   281  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: multisigScriptHash2}, {Account: notaryContractHash}},
   282  				Scripts: []transaction.Witness{
   283  					{
   284  						InvocationScript:   sig,
   285  						VerificationScript: multisigScript1,
   286  					},
   287  					{
   288  						InvocationScript:   sig,
   289  						VerificationScript: multisigScript2,
   290  					},
   291  					{},
   292  				},
   293  			},
   294  			nKeys: 3 + 3,
   295  			expectedInfo: []witnessInfo{
   296  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   297  				{typ: MultiSignature, nSigsLeft: 2, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   298  				{typ: Contract},
   299  			},
   300  		},
   301  		"multisig + sig": {
   302  			tx: &transaction.Transaction{
   303  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
   304  				Scripts: []transaction.Witness{
   305  					{
   306  						InvocationScript:   sig,
   307  						VerificationScript: multisigScript1,
   308  					},
   309  					{
   310  						InvocationScript:   sig,
   311  						VerificationScript: sigScript1,
   312  					},
   313  					{},
   314  				},
   315  			},
   316  			nKeys: 3 + 1,
   317  			expectedInfo: []witnessInfo{
   318  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   319  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   320  				{typ: Contract},
   321  			},
   322  		},
   323  		"sig + multisig": {
   324  			tx: &transaction.Transaction{
   325  				Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
   326  				Scripts: []transaction.Witness{
   327  					{
   328  						InvocationScript:   sig,
   329  						VerificationScript: sigScript1,
   330  					},
   331  					{
   332  						InvocationScript:   sig,
   333  						VerificationScript: multisigScript1,
   334  					},
   335  					{},
   336  				},
   337  			},
   338  			nKeys: 1 + 3,
   339  			expectedInfo: []witnessInfo{
   340  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   341  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   342  				{typ: Contract},
   343  			},
   344  		},
   345  		"empty multisig + sig": {
   346  			tx: &transaction.Transaction{
   347  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
   348  				Scripts: []transaction.Witness{
   349  					{
   350  						InvocationScript:   []byte{},
   351  						VerificationScript: multisigScript1,
   352  					},
   353  					{
   354  						InvocationScript:   sig,
   355  						VerificationScript: sigScript1,
   356  					},
   357  					{},
   358  				},
   359  			},
   360  			nKeys: 3 + 1,
   361  			expectedInfo: []witnessInfo{
   362  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   363  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   364  				{typ: Contract},
   365  			},
   366  		},
   367  		"sig + empty multisig": {
   368  			tx: &transaction.Transaction{
   369  				Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
   370  				Scripts: []transaction.Witness{
   371  					{
   372  						InvocationScript:   sig,
   373  						VerificationScript: sigScript1,
   374  					},
   375  					{
   376  						InvocationScript:   []byte{},
   377  						VerificationScript: multisigScript1,
   378  					},
   379  					{},
   380  				},
   381  			},
   382  			nKeys: 1 + 3,
   383  			expectedInfo: []witnessInfo{
   384  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   385  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   386  				{typ: Contract},
   387  			},
   388  		},
   389  		"multisig + empty sig": {
   390  			tx: &transaction.Transaction{
   391  				Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
   392  				Scripts: []transaction.Witness{
   393  					{
   394  						InvocationScript:   sig,
   395  						VerificationScript: multisigScript1,
   396  					},
   397  					{
   398  						InvocationScript:   []byte{},
   399  						VerificationScript: sigScript1,
   400  					},
   401  					{},
   402  				},
   403  			},
   404  			nKeys: 3 + 1,
   405  			expectedInfo: []witnessInfo{
   406  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   407  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   408  				{typ: Contract},
   409  			},
   410  		},
   411  		"empty sig + multisig": {
   412  			tx: &transaction.Transaction{
   413  				Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
   414  				Scripts: []transaction.Witness{
   415  					{
   416  						InvocationScript:   []byte{},
   417  						VerificationScript: sigScript1,
   418  					},
   419  					{
   420  						InvocationScript:   sig,
   421  						VerificationScript: multisigScript1,
   422  					},
   423  					{},
   424  				},
   425  			},
   426  			nKeys: 1 + 3,
   427  			expectedInfo: []witnessInfo{
   428  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   429  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   430  				{typ: Contract},
   431  			},
   432  		},
   433  		"multiple sigs + multiple multisigs": {
   434  			tx: &transaction.Transaction{
   435  				Signers: []transaction.Signer{{Account: multisigScriptHash1},
   436  					{Account: acc1.PublicKey().GetScriptHash()},
   437  					{Account: acc2.PublicKey().GetScriptHash()},
   438  					{Account: acc3.PublicKey().GetScriptHash()},
   439  					{Account: multisigScriptHash2},
   440  					{Account: notaryContractHash}},
   441  				Scripts: []transaction.Witness{
   442  					{
   443  						InvocationScript:   sig,
   444  						VerificationScript: multisigScript1,
   445  					},
   446  					{
   447  						InvocationScript:   sig,
   448  						VerificationScript: sigScript1,
   449  					},
   450  					{
   451  						InvocationScript:   []byte{},
   452  						VerificationScript: sigScript2,
   453  					},
   454  					{
   455  						InvocationScript:   sig,
   456  						VerificationScript: sigScript3,
   457  					},
   458  					{
   459  						InvocationScript:   []byte{},
   460  						VerificationScript: multisigScript2,
   461  					},
   462  					{},
   463  				},
   464  			},
   465  			nKeys: 3 + 1 + 1 + 1 + 3,
   466  			expectedInfo: []witnessInfo{
   467  				{typ: MultiSignature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   468  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc1.PublicKey()}},
   469  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc2.PublicKey()}},
   470  				{typ: Signature, nSigsLeft: 1, pubs: keys.PublicKeys{acc3.PublicKey()}},
   471  				{typ: MultiSignature, nSigsLeft: 2, pubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()}},
   472  				{typ: Contract},
   473  			},
   474  		},
   475  	}
   476  
   477  	for name, testCase := range testCases {
   478  		t.Run(name, func(t *testing.T) {
   479  			actualInfo, err := ntr.verifyIncompleteWitnesses(testCase.tx, testCase.nKeys)
   480  			require.NoError(t, err)
   481  			require.Equal(t, len(testCase.expectedInfo), len(actualInfo))
   482  			for i, expected := range testCase.expectedInfo {
   483  				actual := actualInfo[i]
   484  				require.Equal(t, expected.typ, actual.typ)
   485  				require.Equal(t, expected.nSigsLeft, actual.nSigsLeft)
   486  				require.ElementsMatch(t, expected.pubs, actual.pubs)
   487  				require.Nil(t, actual.sigs)
   488  			}
   489  		})
   490  	}
   491  }