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 }