OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / mempool / policy_test.go
1 // Copyright (c) 2013-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4
5 package mempool
6
7 import (
8         "bytes"
9         "testing"
10         "time"
11
12         "github.com/btcsuite/btcd/btcec"
13         "github.com/btcsuite/btcd/chaincfg"
14         "github.com/btcsuite/btcd/chaincfg/chainhash"
15         "github.com/btcsuite/btcd/txscript"
16         "github.com/btcsuite/btcd/wire"
17         "github.com/btcsuite/btcutil"
18 )
19
20 // TestCalcMinRequiredTxRelayFee tests the calcMinRequiredTxRelayFee API.
21 func TestCalcMinRequiredTxRelayFee(t *testing.T) {
22         tests := []struct {
23                 name     string         // test description.
24                 size     int64          // Transaction size in bytes.
25                 relayFee btcutil.Amount // minimum relay transaction fee.
26                 want     int64          // Expected fee.
27         }{
28                 {
29                         // Ensure combination of size and fee that are less than 1000
30                         // produce a non-zero fee.
31                         "250 bytes with relay fee of 3",
32                         250,
33                         3,
34                         3,
35                 },
36                 {
37                         "100 bytes with default minimum relay fee",
38                         100,
39                         DefaultMinRelayTxFee,
40                         100,
41                 },
42                 {
43                         "max standard tx size with default minimum relay fee",
44                         maxStandardTxWeight / 4,
45                         DefaultMinRelayTxFee,
46                         100000,
47                 },
48                 {
49                         "max standard tx size with max satoshi relay fee",
50                         maxStandardTxWeight / 4,
51                         btcutil.MaxSatoshi,
52                         btcutil.MaxSatoshi,
53                 },
54                 {
55                         "1500 bytes with 5000 relay fee",
56                         1500,
57                         5000,
58                         7500,
59                 },
60                 {
61                         "1500 bytes with 3000 relay fee",
62                         1500,
63                         3000,
64                         4500,
65                 },
66                 {
67                         "782 bytes with 5000 relay fee",
68                         782,
69                         5000,
70                         3910,
71                 },
72                 {
73                         "782 bytes with 3000 relay fee",
74                         782,
75                         3000,
76                         2346,
77                 },
78                 {
79                         "782 bytes with 2550 relay fee",
80                         782,
81                         2550,
82                         1994,
83                 },
84         }
85
86         for _, test := range tests {
87                 got := calcMinRequiredTxRelayFee(test.size, test.relayFee)
88                 if got != test.want {
89                         t.Errorf("TestCalcMinRequiredTxRelayFee test '%s' "+
90                                 "failed: got %v want %v", test.name, got,
91                                 test.want)
92                         continue
93                 }
94         }
95 }
96
97 // TestCheckPkScriptStandard tests the checkPkScriptStandard API.
98 func TestCheckPkScriptStandard(t *testing.T) {
99         var pubKeys [][]byte
100         for i := 0; i < 4; i++ {
101                 pk, err := btcec.NewPrivateKey(btcec.S256())
102                 if err != nil {
103                         t.Fatalf("TestCheckPkScriptStandard NewPrivateKey failed: %v",
104                                 err)
105                         return
106                 }
107                 pubKeys = append(pubKeys, pk.PubKey().SerializeCompressed())
108         }
109
110         tests := []struct {
111                 name       string // test description.
112                 script     *txscript.ScriptBuilder
113                 isStandard bool
114         }{
115                 {
116                         "key1 and key2",
117                         txscript.NewScriptBuilder().AddOp(txscript.OP_2).
118                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
119                                 AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
120                         true,
121                 },
122                 {
123                         "key1 or key2",
124                         txscript.NewScriptBuilder().AddOp(txscript.OP_1).
125                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
126                                 AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
127                         true,
128                 },
129                 {
130                         "escrow",
131                         txscript.NewScriptBuilder().AddOp(txscript.OP_2).
132                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
133                                 AddData(pubKeys[2]).
134                                 AddOp(txscript.OP_3).AddOp(txscript.OP_CHECKMULTISIG),
135                         true,
136                 },
137                 {
138                         "one of four",
139                         txscript.NewScriptBuilder().AddOp(txscript.OP_1).
140                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
141                                 AddData(pubKeys[2]).AddData(pubKeys[3]).
142                                 AddOp(txscript.OP_4).AddOp(txscript.OP_CHECKMULTISIG),
143                         false,
144                 },
145                 {
146                         "malformed1",
147                         txscript.NewScriptBuilder().AddOp(txscript.OP_3).
148                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
149                                 AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
150                         false,
151                 },
152                 {
153                         "malformed2",
154                         txscript.NewScriptBuilder().AddOp(txscript.OP_2).
155                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
156                                 AddOp(txscript.OP_3).AddOp(txscript.OP_CHECKMULTISIG),
157                         false,
158                 },
159                 {
160                         "malformed3",
161                         txscript.NewScriptBuilder().AddOp(txscript.OP_0).
162                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
163                                 AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
164                         false,
165                 },
166                 {
167                         "malformed4",
168                         txscript.NewScriptBuilder().AddOp(txscript.OP_1).
169                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
170                                 AddOp(txscript.OP_0).AddOp(txscript.OP_CHECKMULTISIG),
171                         false,
172                 },
173                 {
174                         "malformed5",
175                         txscript.NewScriptBuilder().AddOp(txscript.OP_1).
176                                 AddData(pubKeys[0]).AddData(pubKeys[1]).
177                                 AddOp(txscript.OP_CHECKMULTISIG),
178                         false,
179                 },
180                 {
181                         "malformed6",
182                         txscript.NewScriptBuilder().AddOp(txscript.OP_1).
183                                 AddData(pubKeys[0]).AddData(pubKeys[1]),
184                         false,
185                 },
186         }
187
188         for _, test := range tests {
189                 script, err := test.script.Script()
190                 if err != nil {
191                         t.Fatalf("TestCheckPkScriptStandard test '%s' "+
192                                 "failed: %v", test.name, err)
193                         continue
194                 }
195                 scriptClass := txscript.GetScriptClass(script)
196                 got := checkPkScriptStandard(script, scriptClass)
197                 if (test.isStandard && got != nil) ||
198                         (!test.isStandard && got == nil) {
199
200                         t.Fatalf("TestCheckPkScriptStandard test '%s' failed",
201                                 test.name)
202                         return
203                 }
204         }
205 }
206
207 // TestDust tests the isDust API.
208 func TestDust(t *testing.T) {
209         pkScript := []byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43,
210                 0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9,
211                 0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c,
212                 0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d,
213                 0xba, 0x5e, 0x88, 0xac}
214
215         tests := []struct {
216                 name     string // test description
217                 txOut    wire.TxOut
218                 relayFee btcutil.Amount // minimum relay transaction fee.
219                 isDust   bool
220         }{
221                 {
222                         // Any value is allowed with a zero relay fee.
223                         "zero value with zero relay fee",
224                         wire.TxOut{Value: 0, PkScript: pkScript},
225                         0,
226                         false,
227                 },
228                 {
229                         // Zero value is dust with any relay fee"
230                         "zero value with very small tx fee",
231                         wire.TxOut{Value: 0, PkScript: pkScript},
232                         1,
233                         true,
234                 },
235                 {
236                         "38 byte public key script with value 584",
237                         wire.TxOut{Value: 584, PkScript: pkScript},
238                         1000,
239                         true,
240                 },
241                 {
242                         "38 byte public key script with value 585",
243                         wire.TxOut{Value: 585, PkScript: pkScript},
244                         1000,
245                         false,
246                 },
247                 {
248                         // Maximum allowed value is never dust.
249                         "max satoshi amount is never dust",
250                         wire.TxOut{Value: btcutil.MaxSatoshi, PkScript: pkScript},
251                         btcutil.MaxSatoshi,
252                         false,
253                 },
254                 {
255                         // Maximum int64 value causes overflow.
256                         "maximum int64 value",
257                         wire.TxOut{Value: 1<<63 - 1, PkScript: pkScript},
258                         1<<63 - 1,
259                         true,
260                 },
261                 {
262                         // Unspendable pkScript due to an invalid public key
263                         // script.
264                         "unspendable pkScript",
265                         wire.TxOut{Value: 5000, PkScript: []byte{0x01}},
266                         0, // no relay fee
267                         true,
268                 },
269         }
270         for _, test := range tests {
271                 res := isDust(&test.txOut, test.relayFee)
272                 if res != test.isDust {
273                         t.Fatalf("Dust test '%s' failed: want %v got %v",
274                                 test.name, test.isDust, res)
275                         continue
276                 }
277         }
278 }
279
280 // TestCheckTransactionStandard tests the checkTransactionStandard API.
281 func TestCheckTransactionStandard(t *testing.T) {
282         // Create some dummy, but otherwise standard, data for transactions.
283         prevOutHash, err := chainhash.NewHashFromStr("01")
284         if err != nil {
285                 t.Fatalf("NewShaHashFromStr: unexpected error: %v", err)
286         }
287         dummyPrevOut := wire.OutPoint{Hash: *prevOutHash, Index: 1}
288         dummySigScript := bytes.Repeat([]byte{0x00}, 65)
289         dummyTxIn := wire.TxIn{
290                 PreviousOutPoint: dummyPrevOut,
291                 SignatureScript:  dummySigScript,
292                 Sequence:         wire.MaxTxInSequenceNum,
293         }
294         addrHash := [20]byte{0x01}
295         addr, err := btcutil.NewAddressPubKeyHash(addrHash[:],
296                 &chaincfg.TestNet3Params)
297         if err != nil {
298                 t.Fatalf("NewAddressPubKeyHash: unexpected error: %v", err)
299         }
300         dummyPkScript, err := txscript.PayToAddrScript(addr)
301         if err != nil {
302                 t.Fatalf("PayToAddrScript: unexpected error: %v", err)
303         }
304         dummyTxOut := wire.TxOut{
305                 Value:    100000000, // 1 BTC
306                 PkScript: dummyPkScript,
307         }
308
309         tests := []struct {
310                 name       string
311                 tx         wire.MsgTx
312                 height     int32
313                 isStandard bool
314                 code       wire.RejectCode
315         }{
316                 {
317                         name: "Typical pay-to-pubkey-hash transaction",
318                         tx: wire.MsgTx{
319                                 Version:  1,
320                                 TxIn:     []*wire.TxIn{&dummyTxIn},
321                                 TxOut:    []*wire.TxOut{&dummyTxOut},
322                                 LockTime: 0,
323                         },
324                         height:     300000,
325                         isStandard: true,
326                 },
327                 {
328                         name: "Transaction version too high",
329                         tx: wire.MsgTx{
330                                 Version:  wire.TxVersion + 1,
331                                 TxIn:     []*wire.TxIn{&dummyTxIn},
332                                 TxOut:    []*wire.TxOut{&dummyTxOut},
333                                 LockTime: 0,
334                         },
335                         height:     300000,
336                         isStandard: false,
337                         code:       wire.RejectNonstandard,
338                 },
339                 {
340                         name: "Transaction is not finalized",
341                         tx: wire.MsgTx{
342                                 Version: 1,
343                                 TxIn: []*wire.TxIn{{
344                                         PreviousOutPoint: dummyPrevOut,
345                                         SignatureScript:  dummySigScript,
346                                         Sequence:         0,
347                                 }},
348                                 TxOut:    []*wire.TxOut{&dummyTxOut},
349                                 LockTime: 300001,
350                         },
351                         height:     300000,
352                         isStandard: false,
353                         code:       wire.RejectNonstandard,
354                 },
355                 {
356                         name: "Transaction size is too large",
357                         tx: wire.MsgTx{
358                                 Version: 1,
359                                 TxIn:    []*wire.TxIn{&dummyTxIn},
360                                 TxOut: []*wire.TxOut{{
361                                         Value: 0,
362                                         PkScript: bytes.Repeat([]byte{0x00},
363                                                 (maxStandardTxWeight/4)+1),
364                                 }},
365                                 LockTime: 0,
366                         },
367                         height:     300000,
368                         isStandard: false,
369                         code:       wire.RejectNonstandard,
370                 },
371                 {
372                         name: "Signature script size is too large",
373                         tx: wire.MsgTx{
374                                 Version: 1,
375                                 TxIn: []*wire.TxIn{{
376                                         PreviousOutPoint: dummyPrevOut,
377                                         SignatureScript: bytes.Repeat([]byte{0x00},
378                                                 maxStandardSigScriptSize+1),
379                                         Sequence: wire.MaxTxInSequenceNum,
380                                 }},
381                                 TxOut:    []*wire.TxOut{&dummyTxOut},
382                                 LockTime: 0,
383                         },
384                         height:     300000,
385                         isStandard: false,
386                         code:       wire.RejectNonstandard,
387                 },
388                 {
389                         name: "Signature script that does more than push data",
390                         tx: wire.MsgTx{
391                                 Version: 1,
392                                 TxIn: []*wire.TxIn{{
393                                         PreviousOutPoint: dummyPrevOut,
394                                         SignatureScript: []byte{
395                                                 txscript.OP_CHECKSIGVERIFY},
396                                         Sequence: wire.MaxTxInSequenceNum,
397                                 }},
398                                 TxOut:    []*wire.TxOut{&dummyTxOut},
399                                 LockTime: 0,
400                         },
401                         height:     300000,
402                         isStandard: false,
403                         code:       wire.RejectNonstandard,
404                 },
405                 {
406                         name: "Valid but non standard public key script",
407                         tx: wire.MsgTx{
408                                 Version: 1,
409                                 TxIn:    []*wire.TxIn{&dummyTxIn},
410                                 TxOut: []*wire.TxOut{{
411                                         Value:    100000000,
412                                         PkScript: []byte{txscript.OP_TRUE},
413                                 }},
414                                 LockTime: 0,
415                         },
416                         height:     300000,
417                         isStandard: false,
418                         code:       wire.RejectNonstandard,
419                 },
420                 {
421                         name: "More than one nulldata output",
422                         tx: wire.MsgTx{
423                                 Version: 1,
424                                 TxIn:    []*wire.TxIn{&dummyTxIn},
425                                 TxOut: []*wire.TxOut{{
426                                         Value:    0,
427                                         PkScript: []byte{txscript.OP_RETURN},
428                                 }, {
429                                         Value:    0,
430                                         PkScript: []byte{txscript.OP_RETURN},
431                                 }},
432                                 LockTime: 0,
433                         },
434                         height:     300000,
435                         isStandard: false,
436                         code:       wire.RejectNonstandard,
437                 },
438                 {
439                         name: "Dust output",
440                         tx: wire.MsgTx{
441                                 Version: 1,
442                                 TxIn:    []*wire.TxIn{&dummyTxIn},
443                                 TxOut: []*wire.TxOut{{
444                                         Value:    0,
445                                         PkScript: dummyPkScript,
446                                 }},
447                                 LockTime: 0,
448                         },
449                         height:     300000,
450                         isStandard: false,
451                         code:       wire.RejectDust,
452                 },
453                 {
454                         name: "One nulldata output with 0 amount (standard)",
455                         tx: wire.MsgTx{
456                                 Version: 1,
457                                 TxIn:    []*wire.TxIn{&dummyTxIn},
458                                 TxOut: []*wire.TxOut{{
459                                         Value:    0,
460                                         PkScript: []byte{txscript.OP_RETURN},
461                                 }},
462                                 LockTime: 0,
463                         },
464                         height:     300000,
465                         isStandard: true,
466                 },
467         }
468
469         pastMedianTime := time.Now()
470         for _, test := range tests {
471                 // Ensure standardness is as expected.
472                 err := checkTransactionStandard(btcutil.NewTx(&test.tx),
473                         test.height, pastMedianTime, DefaultMinRelayTxFee, 1)
474                 if err == nil && test.isStandard {
475                         // Test passes since function returned standard for a
476                         // transaction which is intended to be standard.
477                         continue
478                 }
479                 if err == nil && !test.isStandard {
480                         t.Errorf("checkTransactionStandard (%s): standard when "+
481                                 "it should not be", test.name)
482                         continue
483                 }
484                 if err != nil && test.isStandard {
485                         t.Errorf("checkTransactionStandard (%s): nonstandard "+
486                                 "when it should not be: %v", test.name, err)
487                         continue
488                 }
489
490                 // Ensure error type is a TxRuleError inside of a RuleError.
491                 rerr, ok := err.(RuleError)
492                 if !ok {
493                         t.Errorf("checkTransactionStandard (%s): unexpected "+
494                                 "error type - got %T", test.name, err)
495                         continue
496                 }
497                 txrerr, ok := rerr.Err.(TxRuleError)
498                 if !ok {
499                         t.Errorf("checkTransactionStandard (%s): unexpected "+
500                                 "error type - got %T", test.name, rerr.Err)
501                         continue
502                 }
503
504                 // Ensure the reject code is the expected one.
505                 if txrerr.RejectCode != test.code {
506                         t.Errorf("checkTransactionStandard (%s): unexpected "+
507                                 "error code - got %v, want %v", test.name,
508                                 txrerr.RejectCode, test.code)
509                         continue
510                 }
511         }
512 }