github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/network/payload/notary_request_test.go (about)

     1  package payload
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/nspcc-dev/neo-go/internal/random"
     7  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
     8  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
     9  	"github.com/nspcc-dev/neo-go/pkg/util"
    10  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestNotaryRequestIsValid(t *testing.T) {
    15  	mainTx := &transaction.Transaction{
    16  		Attributes:      []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
    17  		Script:          []byte{0, 1, 2},
    18  		ValidUntilBlock: 123,
    19  	}
    20  	errorCases := map[string]*P2PNotaryRequest{
    21  		"main tx: missing NotaryAssisted attribute": {MainTransaction: &transaction.Transaction{}},
    22  		"main tx: zero NKeys":                       {MainTransaction: &transaction.Transaction{Attributes: []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}}}}},
    23  		"fallback transaction: invalid signers count": {
    24  			MainTransaction:     mainTx,
    25  			FallbackTransaction: &transaction.Transaction{Signers: []transaction.Signer{{Account: random.Uint160()}}},
    26  		},
    27  		"fallback transaction: invalid witnesses count": {
    28  			MainTransaction:     mainTx,
    29  			FallbackTransaction: &transaction.Transaction{Signers: []transaction.Signer{{Account: random.Uint160()}}},
    30  		},
    31  		"fallback tx: invalid dummy Notary witness (bad witnesses length)": {
    32  			MainTransaction: mainTx,
    33  			FallbackTransaction: &transaction.Transaction{
    34  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    35  				Scripts: []transaction.Witness{{}},
    36  			},
    37  		},
    38  		"fallback tx: invalid dummy Notary witness (bad invocation script length)": {
    39  			MainTransaction: mainTx,
    40  			FallbackTransaction: &transaction.Transaction{
    41  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    42  				Scripts: []transaction.Witness{{}, {}},
    43  			},
    44  		},
    45  		"fallback tx: invalid dummy Notary witness (bad invocation script prefix)": {
    46  			MainTransaction: mainTx,
    47  			FallbackTransaction: &transaction.Transaction{
    48  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    49  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 65}, make([]byte, keys.SignatureLen)...)}, {}},
    50  			},
    51  		},
    52  		"fallback tx: invalid dummy Notary witness (non-empty verification script))": {
    53  			MainTransaction: mainTx,
    54  			FallbackTransaction: &transaction.Transaction{
    55  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    56  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 1)}, {}},
    57  			},
    58  		},
    59  		"fallback tx: missing NotValidBefore attribute": {
    60  			MainTransaction: mainTx,
    61  			FallbackTransaction: &transaction.Transaction{
    62  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    63  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
    64  			},
    65  		},
    66  		"fallback tx: invalid number of Conflicts attributes": {
    67  			MainTransaction: mainTx,
    68  			FallbackTransaction: &transaction.Transaction{
    69  				Attributes: []transaction.Attribute{{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}}},
    70  				Signers:    []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    71  				Scripts:    []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
    72  			},
    73  		},
    74  		"fallback tx: does not conflicts with main tx": {
    75  			MainTransaction: mainTx,
    76  			FallbackTransaction: &transaction.Transaction{
    77  				Attributes: []transaction.Attribute{
    78  					{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
    79  					{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: util.Uint256{}}},
    80  				},
    81  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    82  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
    83  			},
    84  		},
    85  		"fallback tx: missing NotaryAssisted attribute": {
    86  			MainTransaction: mainTx,
    87  			FallbackTransaction: &transaction.Transaction{
    88  				Attributes: []transaction.Attribute{
    89  					{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
    90  					{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
    91  				},
    92  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
    93  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
    94  			},
    95  		},
    96  		"fallback tx: non-zero NKeys": {
    97  			MainTransaction: mainTx,
    98  			FallbackTransaction: &transaction.Transaction{
    99  				Attributes: []transaction.Attribute{
   100  					{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
   101  					{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
   102  					{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}},
   103  				},
   104  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
   105  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
   106  			},
   107  		},
   108  		"fallback tx: ValidUntilBlock mismatch": {
   109  			MainTransaction: mainTx,
   110  			FallbackTransaction: &transaction.Transaction{
   111  				ValidUntilBlock: 321,
   112  				Attributes: []transaction.Attribute{
   113  					{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
   114  					{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
   115  					{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
   116  				},
   117  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
   118  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
   119  			},
   120  		},
   121  	}
   122  	for name, errCase := range errorCases {
   123  		t.Run(name, func(t *testing.T) {
   124  			require.Error(t, errCase.isValid())
   125  		})
   126  	}
   127  	t.Run("good", func(t *testing.T) {
   128  		p := &P2PNotaryRequest{
   129  			MainTransaction: mainTx,
   130  			FallbackTransaction: &transaction.Transaction{
   131  				ValidUntilBlock: 123,
   132  				Attributes: []transaction.Attribute{
   133  					{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
   134  					{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
   135  					{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
   136  				},
   137  				Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
   138  				Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {}},
   139  			},
   140  		}
   141  		require.NoError(t, p.isValid())
   142  	})
   143  }
   144  
   145  func TestNotaryRequestBytesFromBytes(t *testing.T) {
   146  	mainTx := &transaction.Transaction{
   147  		Attributes:      []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
   148  		Script:          []byte{0, 1, 2},
   149  		ValidUntilBlock: 123,
   150  		Signers:         []transaction.Signer{{Account: util.Uint160{1, 5, 9}}},
   151  		Scripts: []transaction.Witness{{
   152  			InvocationScript:   []byte{1, 4, 7},
   153  			VerificationScript: []byte{3, 6, 9},
   154  		}},
   155  	}
   156  	_ = mainTx.Hash()
   157  	_ = mainTx.Size()
   158  	fallbackTx := &transaction.Transaction{
   159  		Script:          []byte{3, 2, 1},
   160  		ValidUntilBlock: 123,
   161  		Attributes: []transaction.Attribute{
   162  			{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
   163  			{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
   164  			{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
   165  		},
   166  		Signers: []transaction.Signer{{Account: util.Uint160{1, 4, 7}}, {Account: util.Uint160{9, 8, 7}}},
   167  		Scripts: []transaction.Witness{
   168  			{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)},
   169  			{InvocationScript: []byte{1, 2, 3}, VerificationScript: []byte{1, 2, 3}}},
   170  	}
   171  	_ = fallbackTx.Hash()
   172  	_ = fallbackTx.Size()
   173  	p := &P2PNotaryRequest{
   174  		MainTransaction:     mainTx,
   175  		FallbackTransaction: fallbackTx,
   176  		Witness: transaction.Witness{
   177  			InvocationScript:   []byte{1, 2, 3},
   178  			VerificationScript: []byte{7, 8, 9},
   179  		},
   180  	}
   181  
   182  	_ = p.Hash() // initialize hash caches
   183  	bytes, err := p.Bytes()
   184  	require.NoError(t, err)
   185  	actual, err := NewP2PNotaryRequestFromBytes(bytes)
   186  	require.NoError(t, err)
   187  	require.Equal(t, p, actual)
   188  }
   189  
   190  func TestP2PNotaryRequest_Copy(t *testing.T) {
   191  	priv, err := keys.NewPrivateKey()
   192  	require.NoError(t, err)
   193  	orig := &P2PNotaryRequest{
   194  		MainTransaction: &transaction.Transaction{
   195  			NetworkFee:      2000,
   196  			SystemFee:       500,
   197  			Nonce:           12345678,
   198  			ValidUntilBlock: 100,
   199  			Version:         1,
   200  			Signers: []transaction.Signer{
   201  				{Account: random.Uint160(), Scopes: transaction.Global, AllowedContracts: []util.Uint160{random.Uint160()}, AllowedGroups: keys.PublicKeys{priv.PublicKey()}, Rules: []transaction.WitnessRule{{Action: 0x01, Condition: transaction.ConditionCalledByEntry{}}}},
   202  				{Account: random.Uint160(), Scopes: transaction.CalledByEntry},
   203  			},
   204  
   205  			Attributes: []transaction.Attribute{
   206  				{Type: transaction.HighPriority, Value: &transaction.OracleResponse{
   207  					ID:     0,
   208  					Code:   transaction.Success,
   209  					Result: []byte{4, 8, 15, 16, 23, 42},
   210  				}},
   211  			},
   212  			Scripts: []transaction.Witness{
   213  				{
   214  					InvocationScript:   []byte{0x04, 0x05},
   215  					VerificationScript: []byte{0x06, 0x07},
   216  				},
   217  			}},
   218  		FallbackTransaction: &transaction.Transaction{
   219  			Version:    2,
   220  			SystemFee:  200,
   221  			NetworkFee: 100,
   222  			Script:     []byte{3, 2, 1},
   223  			Signers:    []transaction.Signer{{Account: util.Uint160{4, 5, 6}}},
   224  			Attributes: []transaction.Attribute{{Type: transaction.NotValidBeforeT}},
   225  			Scripts: []transaction.Witness{
   226  				{
   227  					InvocationScript:   []byte{0x0D, 0x0E},
   228  					VerificationScript: []byte{0x0F, 0x10},
   229  				},
   230  			},
   231  		},
   232  		Witness: transaction.Witness{
   233  			InvocationScript:   []byte{0x11, 0x12},
   234  			VerificationScript: []byte{0x13, 0x14},
   235  		},
   236  	}
   237  
   238  	p2pCopy := orig.Copy()
   239  
   240  	require.Equal(t, orig, p2pCopy)
   241  	require.NotSame(t, orig, p2pCopy)
   242  
   243  	require.Equal(t, orig.MainTransaction, p2pCopy.MainTransaction)
   244  	require.Equal(t, orig.FallbackTransaction, p2pCopy.FallbackTransaction)
   245  	require.Equal(t, orig.Witness, p2pCopy.Witness)
   246  
   247  	p2pCopy.MainTransaction.Version = 3
   248  	p2pCopy.FallbackTransaction.Script[0] = 0x1F
   249  	p2pCopy.Witness.VerificationScript[1] = 0x22
   250  
   251  	require.NotEqual(t, orig.MainTransaction.Version, p2pCopy.MainTransaction.Version)
   252  	require.NotEqual(t, orig.FallbackTransaction.Script[0], p2pCopy.FallbackTransaction.Script[0])
   253  	require.NotEqual(t, orig.Witness.VerificationScript[1], p2pCopy.Witness.VerificationScript[1])
   254  }