OSDN Git Service

6cd48791afc424fd48b8e11e7356311f2e4f3418
[bytom/vapor.git] / account / utxo_keeper_test.go
1 package account
2
3 import (
4         "encoding/json"
5         "os"
6         "testing"
7         "time"
8
9         dbm "github.com/vapor/database/leveldb"
10         "github.com/vapor/protocol/bc"
11         "github.com/vapor/testutil"
12 )
13
14 func TestAddUnconfirmedUtxo(t *testing.T) {
15         cases := []struct {
16                 before   utxoKeeper
17                 after    utxoKeeper
18                 addUtxos []*UTXO
19         }{
20                 {
21                         before: utxoKeeper{
22                                 unconfirmed: map[bc.Hash]*UTXO{},
23                         },
24                         after: utxoKeeper{
25                                 unconfirmed: map[bc.Hash]*UTXO{},
26                         },
27                         addUtxos: []*UTXO{},
28                 },
29                 {
30                         before: utxoKeeper{
31                                 unconfirmed: map[bc.Hash]*UTXO{},
32                         },
33                         after: utxoKeeper{
34                                 unconfirmed: map[bc.Hash]*UTXO{
35                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
36                                 },
37                         },
38                         addUtxos: []*UTXO{
39                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
40                         },
41                 },
42                 {
43                         before: utxoKeeper{
44                                 unconfirmed: map[bc.Hash]*UTXO{
45                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
46                                 },
47                         },
48                         after: utxoKeeper{
49                                 unconfirmed: map[bc.Hash]*UTXO{
50                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
51                                 },
52                         },
53                         addUtxos: []*UTXO{
54                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
55                         },
56                 },
57                 {
58                         before: utxoKeeper{
59                                 unconfirmed: map[bc.Hash]*UTXO{
60                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
61                                 },
62                         },
63                         after: utxoKeeper{
64                                 unconfirmed: map[bc.Hash]*UTXO{
65                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
66                                         bc.NewHash([32]byte{0x02}): &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
67                                         bc.NewHash([32]byte{0x03}): &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
68                                 },
69                         },
70                         addUtxos: []*UTXO{
71                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
72                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
73                         },
74                 },
75         }
76
77         for i, c := range cases {
78                 c.before.AddUnconfirmedUtxo(c.addUtxos)
79                 if !testutil.DeepEqual(c.before, c.after) {
80                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
81                 }
82         }
83 }
84
85 func TestCancel(t *testing.T) {
86         cases := []struct {
87                 before    utxoKeeper
88                 after     utxoKeeper
89                 cancelRid uint64
90         }{
91                 {
92                         before: utxoKeeper{
93                                 reserved:     map[bc.Hash]uint64{},
94                                 reservations: map[uint64]*reservation{},
95                         },
96                         after: utxoKeeper{
97                                 reserved:     map[bc.Hash]uint64{},
98                                 reservations: map[uint64]*reservation{},
99                         },
100                         cancelRid: 0,
101                 },
102                 {
103                         before: utxoKeeper{
104                                 reserved: map[bc.Hash]uint64{
105                                         bc.NewHash([32]byte{0x01}): 1,
106                                 },
107                                 reservations: map[uint64]*reservation{
108                                         1: &reservation{
109                                                 id: 1,
110                                                 utxos: []*UTXO{
111                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
112                                                 },
113                                                 change: 9527,
114                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
115                                         },
116                                 },
117                         },
118                         after: utxoKeeper{
119                                 reserved:     map[bc.Hash]uint64{},
120                                 reservations: map[uint64]*reservation{},
121                         },
122                         cancelRid: 1,
123                 },
124                 {
125                         before: utxoKeeper{
126                                 reserved: map[bc.Hash]uint64{
127                                         bc.NewHash([32]byte{0x01}): 1,
128                                 },
129                                 reservations: map[uint64]*reservation{
130                                         1: &reservation{
131                                                 id: 1,
132                                                 utxos: []*UTXO{
133                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
134                                                 },
135                                                 change: 9527,
136                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
137                                         },
138                                 },
139                         },
140                         after: utxoKeeper{
141                                 reserved: map[bc.Hash]uint64{
142                                         bc.NewHash([32]byte{0x01}): 1,
143                                 },
144                                 reservations: map[uint64]*reservation{
145                                         1: &reservation{
146                                                 id: 1,
147                                                 utxos: []*UTXO{
148                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
149                                                 },
150                                                 change: 9527,
151                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
152                                         },
153                                 },
154                         },
155                         cancelRid: 2,
156                 },
157                 {
158                         before: utxoKeeper{
159                                 reserved: map[bc.Hash]uint64{
160                                         bc.NewHash([32]byte{0x01}): 1,
161                                         bc.NewHash([32]byte{0x02}): 3,
162                                         bc.NewHash([32]byte{0x03}): 3,
163                                         bc.NewHash([32]byte{0x04}): 3,
164                                 },
165                                 reservations: map[uint64]*reservation{
166                                         1: &reservation{
167                                                 id: 1,
168                                                 utxos: []*UTXO{
169                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
170                                                 },
171                                                 change: 9527,
172                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
173                                         },
174                                         3: &reservation{
175                                                 id: 3,
176                                                 utxos: []*UTXO{
177                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
178                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
179                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x04})},
180                                                 },
181                                                 change: 9528,
182                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
183                                         },
184                                 },
185                         },
186                         after: utxoKeeper{
187                                 reserved: map[bc.Hash]uint64{
188                                         bc.NewHash([32]byte{0x01}): 1,
189                                 },
190                                 reservations: map[uint64]*reservation{
191                                         1: &reservation{
192                                                 id: 1,
193                                                 utxos: []*UTXO{
194                                                         &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
195                                                 },
196                                                 change: 9527,
197                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
198                                         },
199                                 },
200                         },
201                         cancelRid: 3,
202                 },
203         }
204
205         for i, c := range cases {
206                 c.before.cancel(c.cancelRid)
207                 if !testutil.DeepEqual(c.before, c.after) {
208                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
209                 }
210         }
211 }
212
213 func TestRemoveUnconfirmedUtxo(t *testing.T) {
214         cases := []struct {
215                 before      utxoKeeper
216                 after       utxoKeeper
217                 removeUtxos []*bc.Hash
218         }{
219                 {
220                         before: utxoKeeper{
221                                 unconfirmed: map[bc.Hash]*UTXO{},
222                         },
223                         after: utxoKeeper{
224                                 unconfirmed: map[bc.Hash]*UTXO{},
225                         },
226                         removeUtxos: []*bc.Hash{},
227                 },
228                 {
229                         before: utxoKeeper{
230                                 unconfirmed: map[bc.Hash]*UTXO{
231                                         bc.Hash{V0: 1}: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
232                                 },
233                         },
234                         after: utxoKeeper{
235                                 unconfirmed: map[bc.Hash]*UTXO{},
236                         },
237                         removeUtxos: []*bc.Hash{
238                                 &bc.Hash{V0: 1},
239                         },
240                 },
241                 {
242                         before: utxoKeeper{
243                                 unconfirmed: map[bc.Hash]*UTXO{
244                                         bc.Hash{V0: 1}: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
245                                         bc.Hash{V0: 2}: &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
246                                         bc.Hash{V0: 3}: &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
247                                         bc.Hash{V0: 4}: &UTXO{OutputID: bc.NewHash([32]byte{0x04})},
248                                         bc.Hash{V0: 5}: &UTXO{OutputID: bc.NewHash([32]byte{0x05})},
249                                 },
250                         },
251                         after: utxoKeeper{
252                                 unconfirmed: map[bc.Hash]*UTXO{
253                                         bc.Hash{V0: 2}: &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
254                                         bc.Hash{V0: 4}: &UTXO{OutputID: bc.NewHash([32]byte{0x04})},
255                                 },
256                         },
257                         removeUtxos: []*bc.Hash{
258                                 &bc.Hash{V0: 1},
259                                 &bc.Hash{V0: 3},
260                                 &bc.Hash{V0: 5},
261                         },
262                 },
263         }
264
265         for i, c := range cases {
266                 c.before.RemoveUnconfirmedUtxo(c.removeUtxos)
267                 if !testutil.DeepEqual(c.before, c.after) {
268                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
269                 }
270         }
271 }
272
273 func TestReserve(t *testing.T) {
274         currentHeight := func() uint64 { return 9527 }
275         testDB := dbm.NewDB("testdb", "leveldb", "temp")
276         defer func() {
277                 testDB.Close()
278                 os.RemoveAll("temp")
279         }()
280
281         cases := []struct {
282                 before        utxoKeeper
283                 after         utxoKeeper
284                 err           error
285                 reserveAmount uint64
286                 exp           time.Time
287                 vote          []byte
288         }{
289                 {
290                         before: utxoKeeper{
291                                 db:            testDB,
292                                 currentHeight: currentHeight,
293                                 reserved:      map[bc.Hash]uint64{},
294                                 reservations:  map[uint64]*reservation{},
295                         },
296                         after: utxoKeeper{
297                                 db:            testDB,
298                                 currentHeight: currentHeight,
299                                 reserved:      map[bc.Hash]uint64{},
300                                 reservations:  map[uint64]*reservation{},
301                         },
302                         reserveAmount: 1,
303                         err:           ErrInsufficient,
304                 },
305                 {
306                         before: utxoKeeper{
307                                 db:            testDB,
308                                 currentHeight: currentHeight,
309                                 unconfirmed: map[bc.Hash]*UTXO{
310                                         bc.NewHash([32]byte{0x01}): &UTXO{
311                                                 OutputID:  bc.NewHash([32]byte{0x01}),
312                                                 AccountID: "testAccount",
313                                                 Amount:    3,
314                                         },
315                                 },
316                                 reserved:     map[bc.Hash]uint64{},
317                                 reservations: map[uint64]*reservation{},
318                         },
319                         after: utxoKeeper{
320                                 db:            testDB,
321                                 currentHeight: currentHeight,
322                                 unconfirmed: map[bc.Hash]*UTXO{
323                                         bc.NewHash([32]byte{0x01}): &UTXO{
324                                                 OutputID:  bc.NewHash([32]byte{0x01}),
325                                                 AccountID: "testAccount",
326                                                 Amount:    3,
327                                         },
328                                 },
329                                 reserved:     map[bc.Hash]uint64{},
330                                 reservations: map[uint64]*reservation{},
331                         },
332                         reserveAmount: 4,
333                         err:           ErrInsufficient,
334                 },
335                 {
336                         before: utxoKeeper{
337                                 db:            testDB,
338                                 currentHeight: currentHeight,
339                                 unconfirmed: map[bc.Hash]*UTXO{
340                                         bc.NewHash([32]byte{0x01}): &UTXO{
341                                                 OutputID:    bc.NewHash([32]byte{0x01}),
342                                                 AccountID:   "testAccount",
343                                                 Amount:      3,
344                                                 ValidHeight: 9528,
345                                         },
346                                 },
347                                 reserved:     map[bc.Hash]uint64{},
348                                 reservations: map[uint64]*reservation{},
349                         },
350                         after: utxoKeeper{
351                                 db:            testDB,
352                                 currentHeight: currentHeight,
353                                 unconfirmed: map[bc.Hash]*UTXO{
354                                         bc.NewHash([32]byte{0x01}): &UTXO{
355                                                 OutputID:    bc.NewHash([32]byte{0x01}),
356                                                 AccountID:   "testAccount",
357                                                 Amount:      3,
358                                                 ValidHeight: 9528,
359                                         },
360                                 },
361                                 reserved:     map[bc.Hash]uint64{},
362                                 reservations: map[uint64]*reservation{},
363                         },
364                         reserveAmount: 3,
365                         err:           ErrImmature,
366                 },
367                 {
368                         before: utxoKeeper{
369                                 db:            testDB,
370                                 currentHeight: currentHeight,
371                                 unconfirmed: map[bc.Hash]*UTXO{
372                                         bc.NewHash([32]byte{0x01}): &UTXO{
373                                                 OutputID:  bc.NewHash([32]byte{0x01}),
374                                                 AccountID: "testAccount",
375                                                 Amount:    3,
376                                         },
377                                 },
378                                 reserved: map[bc.Hash]uint64{
379                                         bc.NewHash([32]byte{0x01}): 0,
380                                 },
381                                 reservations: map[uint64]*reservation{},
382                         },
383                         after: utxoKeeper{
384                                 db:            testDB,
385                                 currentHeight: currentHeight,
386                                 unconfirmed: map[bc.Hash]*UTXO{
387                                         bc.NewHash([32]byte{0x01}): &UTXO{
388                                                 OutputID:  bc.NewHash([32]byte{0x01}),
389                                                 AccountID: "testAccount",
390                                                 Amount:    3,
391                                         },
392                                 },
393                                 reserved: map[bc.Hash]uint64{
394                                         bc.NewHash([32]byte{0x01}): 0,
395                                 },
396                                 reservations: map[uint64]*reservation{},
397                         },
398                         reserveAmount: 3,
399                         err:           ErrReserved,
400                 },
401                 {
402                         before: utxoKeeper{
403                                 db:            testDB,
404                                 currentHeight: currentHeight,
405                                 unconfirmed: map[bc.Hash]*UTXO{
406                                         bc.NewHash([32]byte{0x01}): &UTXO{
407                                                 OutputID:  bc.NewHash([32]byte{0x01}),
408                                                 AccountID: "testAccount",
409                                                 Amount:    3,
410                                         },
411                                 },
412                                 reserved:     map[bc.Hash]uint64{},
413                                 reservations: map[uint64]*reservation{},
414                         },
415                         after: utxoKeeper{
416                                 db:            testDB,
417                                 currentHeight: currentHeight,
418                                 unconfirmed: map[bc.Hash]*UTXO{
419                                         bc.NewHash([32]byte{0x01}): &UTXO{
420                                                 OutputID:  bc.NewHash([32]byte{0x01}),
421                                                 AccountID: "testAccount",
422                                                 Amount:    3,
423                                         },
424                                 },
425                                 reserved: map[bc.Hash]uint64{
426                                         bc.NewHash([32]byte{0x01}): 1,
427                                 },
428                                 reservations: map[uint64]*reservation{
429                                         1: &reservation{
430                                                 id: 1,
431                                                 utxos: []*UTXO{
432                                                         &UTXO{
433                                                                 OutputID:  bc.NewHash([32]byte{0x01}),
434                                                                 AccountID: "testAccount",
435                                                                 Amount:    3,
436                                                         },
437                                                 },
438                                                 change: 1,
439                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
440                                         },
441                                 },
442                         },
443                         reserveAmount: 2,
444                         err:           nil,
445                         exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
446                 },
447                 {
448                         before: utxoKeeper{
449                                 db:            testDB,
450                                 currentHeight: currentHeight,
451                                 nextIndex:     1,
452                                 unconfirmed: map[bc.Hash]*UTXO{
453                                         bc.NewHash([32]byte{0x01}): &UTXO{
454                                                 OutputID:  bc.NewHash([32]byte{0x01}),
455                                                 AccountID: "testAccount",
456                                                 Amount:    3,
457                                         },
458                                         bc.NewHash([32]byte{0x02}): &UTXO{
459                                                 OutputID:  bc.NewHash([32]byte{0x02}),
460                                                 AccountID: "testAccount",
461                                                 Amount:    5,
462                                         },
463                                         bc.NewHash([32]byte{0x03}): &UTXO{
464                                                 OutputID:  bc.NewHash([32]byte{0x03}),
465                                                 AccountID: "testAccount",
466                                                 Amount:    7,
467                                         },
468                                 },
469                                 reserved: map[bc.Hash]uint64{
470                                         bc.NewHash([32]byte{0x01}): 1,
471                                 },
472                                 reservations: map[uint64]*reservation{},
473                         },
474                         after: utxoKeeper{
475                                 db:            testDB,
476                                 currentHeight: currentHeight,
477                                 unconfirmed: map[bc.Hash]*UTXO{
478                                         bc.NewHash([32]byte{0x01}): &UTXO{
479                                                 OutputID:  bc.NewHash([32]byte{0x01}),
480                                                 AccountID: "testAccount",
481                                                 Amount:    3,
482                                         },
483                                         bc.NewHash([32]byte{0x02}): &UTXO{
484                                                 OutputID:  bc.NewHash([32]byte{0x02}),
485                                                 AccountID: "testAccount",
486                                                 Amount:    5,
487                                         },
488                                         bc.NewHash([32]byte{0x03}): &UTXO{
489                                                 OutputID:  bc.NewHash([32]byte{0x03}),
490                                                 AccountID: "testAccount",
491                                                 Amount:    7,
492                                         },
493                                 },
494                                 reserved: map[bc.Hash]uint64{
495                                         bc.NewHash([32]byte{0x01}): 1,
496                                         bc.NewHash([32]byte{0x02}): 2,
497                                         bc.NewHash([32]byte{0x03}): 2,
498                                 },
499                                 reservations: map[uint64]*reservation{
500                                         2: &reservation{
501                                                 id: 2,
502                                                 utxos: []*UTXO{
503                                                         &UTXO{
504                                                                 OutputID:  bc.NewHash([32]byte{0x03}),
505                                                                 AccountID: "testAccount",
506                                                                 Amount:    7,
507                                                         },
508                                                         &UTXO{
509                                                                 OutputID:  bc.NewHash([32]byte{0x02}),
510                                                                 AccountID: "testAccount",
511                                                                 Amount:    5,
512                                                         },
513                                                 },
514                                                 change: 4,
515                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
516                                         },
517                                 },
518                         },
519                         reserveAmount: 8,
520                         err:           nil,
521                         exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
522                 },
523                 {
524                         before: utxoKeeper{
525                                 db:            testDB,
526                                 currentHeight: currentHeight,
527                                 unconfirmed: map[bc.Hash]*UTXO{
528                                         bc.NewHash([32]byte{0x01}): &UTXO{
529                                                 OutputID:  bc.NewHash([32]byte{0x01}),
530                                                 AccountID: "testAccount",
531                                                 Amount:    3,
532                                                 Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
533                                         },
534                                 },
535                                 reserved:     map[bc.Hash]uint64{},
536                                 reservations: map[uint64]*reservation{},
537                         },
538                         after: utxoKeeper{
539                                 db:            testDB,
540                                 currentHeight: currentHeight,
541                                 unconfirmed: map[bc.Hash]*UTXO{
542                                         bc.NewHash([32]byte{0x01}): &UTXO{
543                                                 OutputID:  bc.NewHash([32]byte{0x01}),
544                                                 AccountID: "testAccount",
545                                                 Amount:    3,
546                                                 Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
547                                         },
548                                 },
549                                 reserved: map[bc.Hash]uint64{
550                                         bc.NewHash([32]byte{0x01}): 1,
551                                 },
552                                 reservations: map[uint64]*reservation{
553                                         1: &reservation{
554                                                 id: 1,
555                                                 utxos: []*UTXO{
556                                                         &UTXO{
557                                                                 OutputID:  bc.NewHash([32]byte{0x01}),
558                                                                 AccountID: "testAccount",
559                                                                 Amount:    3,
560                                                                 Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
561                                                         },
562                                                 },
563                                                 change: 1,
564                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
565                                         },
566                                 },
567                         },
568                         reserveAmount: 2,
569                         err:           nil,
570                         exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
571                         vote:          []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
572                 },
573         }
574
575         for i, c := range cases {
576                 if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.vote, c.exp); err != c.err {
577                         t.Errorf("case %d: got error %v want error %v", i, err, c.err)
578                 }
579                 checkUtxoKeeperEqual(t, i, &c.before, &c.after)
580         }
581 }
582
583 func TestReserveParticular(t *testing.T) {
584         currentHeight := func() uint64 { return 9527 }
585         testDB := dbm.NewDB("testdb", "leveldb", "temp")
586         defer os.RemoveAll("temp")
587
588         cases := []struct {
589                 before      utxoKeeper
590                 after       utxoKeeper
591                 err         error
592                 reserveHash bc.Hash
593                 exp         time.Time
594         }{
595                 {
596                         before: utxoKeeper{
597                                 db:            testDB,
598                                 currentHeight: currentHeight,
599                                 unconfirmed: map[bc.Hash]*UTXO{
600                                         bc.NewHash([32]byte{0x01}): &UTXO{
601                                                 OutputID:  bc.NewHash([32]byte{0x01}),
602                                                 AccountID: "testAccount",
603                                                 Amount:    3,
604                                         },
605                                 },
606                                 reserved: map[bc.Hash]uint64{
607                                         bc.NewHash([32]byte{0x01}): 0,
608                                 },
609                                 reservations: map[uint64]*reservation{},
610                         },
611                         after: utxoKeeper{
612                                 db:            testDB,
613                                 currentHeight: currentHeight,
614                                 unconfirmed: map[bc.Hash]*UTXO{
615                                         bc.NewHash([32]byte{0x01}): &UTXO{
616                                                 OutputID:  bc.NewHash([32]byte{0x01}),
617                                                 AccountID: "testAccount",
618                                                 Amount:    3,
619                                         },
620                                 },
621                                 reserved: map[bc.Hash]uint64{
622                                         bc.NewHash([32]byte{0x01}): 0,
623                                 },
624                                 reservations: map[uint64]*reservation{},
625                         },
626                         reserveHash: bc.NewHash([32]byte{0x01}),
627                         err:         ErrReserved,
628                 },
629                 {
630                         before: utxoKeeper{
631                                 db:            testDB,
632                                 currentHeight: currentHeight,
633                                 unconfirmed: map[bc.Hash]*UTXO{
634                                         bc.NewHash([32]byte{0x01}): &UTXO{
635                                                 OutputID:    bc.NewHash([32]byte{0x01}),
636                                                 AccountID:   "testAccount",
637                                                 Amount:      3,
638                                                 ValidHeight: 9528,
639                                         },
640                                 },
641                                 reserved:     map[bc.Hash]uint64{},
642                                 reservations: map[uint64]*reservation{},
643                         },
644                         after: utxoKeeper{
645                                 db:            testDB,
646                                 currentHeight: currentHeight,
647                                 unconfirmed: map[bc.Hash]*UTXO{
648                                         bc.NewHash([32]byte{0x01}): &UTXO{
649                                                 OutputID:    bc.NewHash([32]byte{0x01}),
650                                                 AccountID:   "testAccount",
651                                                 Amount:      3,
652                                                 ValidHeight: 9528,
653                                         },
654                                 },
655                                 reserved:     map[bc.Hash]uint64{},
656                                 reservations: map[uint64]*reservation{},
657                         },
658                         reserveHash: bc.NewHash([32]byte{0x01}),
659                         err:         ErrImmature,
660                 },
661                 {
662                         before: utxoKeeper{
663                                 db:            testDB,
664                                 currentHeight: currentHeight,
665                                 unconfirmed: map[bc.Hash]*UTXO{
666                                         bc.NewHash([32]byte{0x01}): &UTXO{
667                                                 OutputID:  bc.NewHash([32]byte{0x01}),
668                                                 AccountID: "testAccount",
669                                                 Amount:    3,
670                                         },
671                                 },
672                                 reserved:     map[bc.Hash]uint64{},
673                                 reservations: map[uint64]*reservation{},
674                         },
675                         after: utxoKeeper{
676                                 db:            testDB,
677                                 currentHeight: currentHeight,
678                                 unconfirmed: map[bc.Hash]*UTXO{
679                                         bc.NewHash([32]byte{0x01}): &UTXO{
680                                                 OutputID:  bc.NewHash([32]byte{0x01}),
681                                                 AccountID: "testAccount",
682                                                 Amount:    3,
683                                         },
684                                 },
685                                 reserved: map[bc.Hash]uint64{
686                                         bc.NewHash([32]byte{0x01}): 1,
687                                 },
688                                 reservations: map[uint64]*reservation{
689                                         1: &reservation{
690                                                 id: 1,
691                                                 utxos: []*UTXO{
692                                                         &UTXO{
693                                                                 OutputID:  bc.NewHash([32]byte{0x01}),
694                                                                 AccountID: "testAccount",
695                                                                 Amount:    3,
696                                                         },
697                                                 },
698                                                 change: 0,
699                                                 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
700                                         },
701                                 },
702                         },
703                         reserveHash: bc.NewHash([32]byte{0x01}),
704                         err:         nil,
705                         exp:         time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
706                 },
707         }
708
709         for i, c := range cases {
710                 if _, err := c.before.ReserveParticular(c.reserveHash, true, c.exp); err != c.err {
711                         t.Errorf("case %d: got error %v want error %v", i, err, c.err)
712                 }
713                 checkUtxoKeeperEqual(t, i, &c.before, &c.after)
714         }
715 }
716
717 func TestExpireReservation(t *testing.T) {
718         before := &utxoKeeper{
719                 reservations: map[uint64]*reservation{
720                         1: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)},
721                         2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
722                         3: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)},
723                         4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
724                         5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
725                 },
726         }
727         after := &utxoKeeper{
728                 reservations: map[uint64]*reservation{
729                         2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
730                         4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
731                         5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
732                 },
733         }
734         before.expireReservation(time.Date(2017, 8, 10, 0, 0, 0, 0, time.UTC))
735         checkUtxoKeeperEqual(t, 0, before, after)
736 }
737
738 func TestFindUtxos(t *testing.T) {
739         currentHeight := func() uint64 { return 9527 }
740         testDB := dbm.NewDB("testdb", "leveldb", "temp")
741         defer func() {
742                 testDB.Close()
743                 os.RemoveAll("temp")
744         }()
745
746         cases := []struct {
747                 uk             utxoKeeper
748                 dbUtxos        []*UTXO
749                 useUnconfirmed bool
750                 wantUtxos      []*UTXO
751                 immatureAmount uint64
752                 vote           []byte
753         }{
754                 {
755                         uk: utxoKeeper{
756                                 db:            testDB,
757                                 currentHeight: currentHeight,
758                                 unconfirmed:   map[bc.Hash]*UTXO{},
759                         },
760                         dbUtxos:        []*UTXO{},
761                         useUnconfirmed: true,
762                         wantUtxos:      []*UTXO{},
763                         immatureAmount: 0,
764                 },
765                 {
766                         uk: utxoKeeper{
767                                 db:            testDB,
768                                 currentHeight: currentHeight,
769                                 unconfirmed:   map[bc.Hash]*UTXO{},
770                         },
771                         dbUtxos: []*UTXO{
772                                 &UTXO{
773                                         OutputID:  bc.NewHash([32]byte{0x01}),
774                                         AccountID: "testAccount",
775                                         Amount:    3,
776                                 },
777                                 &UTXO{
778                                         OutputID:  bc.NewHash([32]byte{0x02}),
779                                         AccountID: "testAccount",
780                                         AssetID:   bc.AssetID{V0: 6},
781                                         Amount:    3,
782                                 },
783                         },
784                         useUnconfirmed: false,
785                         wantUtxos: []*UTXO{
786                                 &UTXO{
787                                         OutputID:  bc.NewHash([32]byte{0x01}),
788                                         AccountID: "testAccount",
789                                         Amount:    3,
790                                 },
791                         },
792                         immatureAmount: 0,
793                 },
794                 {
795                         uk: utxoKeeper{
796                                 db:            testDB,
797                                 currentHeight: currentHeight,
798                                 unconfirmed:   map[bc.Hash]*UTXO{},
799                         },
800                         dbUtxos: []*UTXO{
801                                 &UTXO{
802                                         OutputID:    bc.NewHash([32]byte{0x02}),
803                                         AccountID:   "testAccount",
804                                         Amount:      3,
805                                         ValidHeight: 9528,
806                                 },
807                         },
808                         useUnconfirmed: false,
809                         wantUtxos:      []*UTXO{},
810                         immatureAmount: 3,
811                 },
812                 {
813                         uk: utxoKeeper{
814                                 db:            testDB,
815                                 currentHeight: currentHeight,
816                                 unconfirmed: map[bc.Hash]*UTXO{
817                                         bc.NewHash([32]byte{0x01}): &UTXO{
818                                                 OutputID:  bc.NewHash([32]byte{0x01}),
819                                                 AccountID: "testAccount",
820                                                 Amount:    3,
821                                         },
822                                 },
823                         },
824                         dbUtxos: []*UTXO{
825                                 &UTXO{
826                                         OutputID:  bc.NewHash([32]byte{0x02}),
827                                         AccountID: "testAccount",
828                                         Amount:    3,
829                                 },
830                         },
831                         useUnconfirmed: false,
832                         wantUtxos: []*UTXO{
833                                 &UTXO{
834                                         OutputID:  bc.NewHash([32]byte{0x02}),
835                                         AccountID: "testAccount",
836                                         Amount:    3,
837                                 },
838                         },
839                         immatureAmount: 0,
840                 },
841                 {
842                         uk: utxoKeeper{
843                                 db:            testDB,
844                                 currentHeight: currentHeight,
845                                 unconfirmed: map[bc.Hash]*UTXO{
846                                         bc.NewHash([32]byte{0x11}): &UTXO{
847                                                 OutputID:  bc.NewHash([32]byte{0x01}),
848                                                 AccountID: "testAccount",
849                                                 Amount:    3,
850                                         },
851                                 },
852                         },
853                         dbUtxos: []*UTXO{
854                                 &UTXO{
855                                         OutputID:  bc.NewHash([32]byte{0x02}),
856                                         AccountID: "testAccount",
857                                         Amount:    3,
858                                 },
859                         },
860                         useUnconfirmed: true,
861                         wantUtxos: []*UTXO{
862                                 &UTXO{
863                                         OutputID:  bc.NewHash([32]byte{0x02}),
864                                         AccountID: "testAccount",
865                                         Amount:    3,
866                                 },
867                                 &UTXO{
868                                         OutputID:  bc.NewHash([32]byte{0x01}),
869                                         AccountID: "testAccount",
870                                         Amount:    3,
871                                 },
872                         },
873                         immatureAmount: 0,
874                 },
875                 {
876                         uk: utxoKeeper{
877                                 db:            testDB,
878                                 currentHeight: currentHeight,
879                                 unconfirmed: map[bc.Hash]*UTXO{
880                                         bc.NewHash([32]byte{0x01}): &UTXO{
881                                                 OutputID:  bc.NewHash([32]byte{0x01}),
882                                                 AccountID: "testAccount",
883                                                 Amount:    1,
884                                         },
885                                         bc.NewHash([32]byte{0x02}): &UTXO{
886                                                 OutputID:  bc.NewHash([32]byte{0x02}),
887                                                 AccountID: "notMe",
888                                                 Amount:    2,
889                                         },
890                                 },
891                         },
892                         dbUtxos: []*UTXO{
893                                 &UTXO{
894                                         OutputID:  bc.NewHash([32]byte{0x03}),
895                                         AccountID: "testAccount",
896                                         Amount:    3,
897                                 },
898                                 &UTXO{
899                                         OutputID:  bc.NewHash([32]byte{0x04}),
900                                         AccountID: "notMe",
901                                         Amount:    4,
902                                 },
903                         },
904                         useUnconfirmed: true,
905                         wantUtxos: []*UTXO{
906                                 &UTXO{
907                                         OutputID:  bc.NewHash([32]byte{0x03}),
908                                         AccountID: "testAccount",
909                                         Amount:    3,
910                                 },
911                                 &UTXO{
912                                         OutputID:  bc.NewHash([32]byte{0x01}),
913                                         AccountID: "testAccount",
914                                         Amount:    1,
915                                 },
916                         },
917                         immatureAmount: 0,
918                 },
919                 {
920                         uk: utxoKeeper{
921                                 db:            testDB,
922                                 currentHeight: currentHeight,
923                                 unconfirmed:   map[bc.Hash]*UTXO{},
924                         },
925                         dbUtxos: []*UTXO{
926                                 &UTXO{
927                                         OutputID:  bc.NewHash([32]byte{0x01}),
928                                         AccountID: "testAccount",
929                                         Amount:    6,
930                                         Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
931                                 },
932                         },
933                         useUnconfirmed: false,
934                         wantUtxos: []*UTXO{
935                                 &UTXO{
936                                         OutputID:  bc.NewHash([32]byte{0x01}),
937                                         AccountID: "testAccount",
938                                         Amount:    6,
939                                         Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
940                                 },
941                         },
942                         immatureAmount: 0,
943                         vote:           []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
944                 },
945         }
946
947         for i, c := range cases {
948                 for _, u := range c.dbUtxos {
949                         data, err := json.Marshal(u)
950                         if err != nil {
951                                 t.Error(err)
952                         }
953                         testDB.Set(StandardUTXOKey(u.OutputID), data)
954                 }
955
956                 gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed, c.vote)
957                 if !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
958                         t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
959                 }
960                 if immatureAmount != c.immatureAmount {
961                         t.Errorf("case %d: got %v want %v", i, immatureAmount, c.immatureAmount)
962                 }
963
964                 for _, u := range c.dbUtxos {
965                         testDB.Delete(StandardUTXOKey(u.OutputID))
966                 }
967         }
968 }
969
970 func TestFindUtxo(t *testing.T) {
971         currentHeight := func() uint64 { return 9527 }
972         testDB := dbm.NewDB("testdb", "leveldb", "temp")
973         defer os.RemoveAll("temp")
974
975         cases := []struct {
976                 uk             utxoKeeper
977                 dbUtxos        map[string]*UTXO
978                 outHash        bc.Hash
979                 useUnconfirmed bool
980                 wantUtxo       *UTXO
981                 err            error
982         }{
983                 {
984                         uk: utxoKeeper{
985                                 db:            testDB,
986                                 currentHeight: currentHeight,
987                                 unconfirmed:   map[bc.Hash]*UTXO{},
988                         },
989                         dbUtxos:  map[string]*UTXO{},
990                         outHash:  bc.NewHash([32]byte{0x01}),
991                         wantUtxo: nil,
992                         err:      ErrMatchUTXO,
993                 },
994                 {
995                         uk: utxoKeeper{
996                                 db:            testDB,
997                                 currentHeight: currentHeight,
998                                 unconfirmed: map[bc.Hash]*UTXO{
999                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1000                                 },
1001                         },
1002                         dbUtxos:        map[string]*UTXO{},
1003                         outHash:        bc.NewHash([32]byte{0x01}),
1004                         wantUtxo:       nil,
1005                         useUnconfirmed: false,
1006                         err:            ErrMatchUTXO,
1007                 },
1008                 {
1009                         uk: utxoKeeper{
1010                                 db:            testDB,
1011                                 currentHeight: currentHeight,
1012                                 unconfirmed: map[bc.Hash]*UTXO{
1013                                         bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1014                                 },
1015                         },
1016                         dbUtxos:        map[string]*UTXO{},
1017                         outHash:        bc.NewHash([32]byte{0x01}),
1018                         wantUtxo:       &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1019                         useUnconfirmed: true,
1020                         err:            nil,
1021                 },
1022                 {
1023                         uk: utxoKeeper{
1024                                 db:            testDB,
1025                                 currentHeight: currentHeight,
1026                                 unconfirmed:   map[bc.Hash]*UTXO{},
1027                         },
1028                         dbUtxos: map[string]*UTXO{
1029                                 string(StandardUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1030                         },
1031                         outHash:        bc.NewHash([32]byte{0x01}),
1032                         wantUtxo:       &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1033                         useUnconfirmed: false,
1034                         err:            nil,
1035                 },
1036                 {
1037                         uk: utxoKeeper{
1038                                 db:            testDB,
1039                                 currentHeight: currentHeight,
1040                                 unconfirmed:   map[bc.Hash]*UTXO{},
1041                         },
1042                         dbUtxos: map[string]*UTXO{
1043                                 string(ContractUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1044                         },
1045                         outHash:        bc.NewHash([32]byte{0x01}),
1046                         wantUtxo:       &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1047                         useUnconfirmed: false,
1048                         err:            nil,
1049                 },
1050         }
1051
1052         for i, c := range cases {
1053                 for k, u := range c.dbUtxos {
1054                         data, err := json.Marshal(u)
1055                         if err != nil {
1056                                 t.Error(err)
1057                         }
1058                         testDB.Set([]byte(k), data)
1059                 }
1060
1061                 gotUtxo, err := c.uk.findUtxo(c.outHash, c.useUnconfirmed)
1062                 if !testutil.DeepEqual(gotUtxo, c.wantUtxo) {
1063                         t.Errorf("case %d: got %v want %v", i, gotUtxo, c.wantUtxo)
1064                 }
1065                 if err != c.err {
1066                         t.Errorf("case %d: got %v want %v", i, err, c.err)
1067                 }
1068
1069                 for _, u := range c.dbUtxos {
1070                         testDB.Delete(StandardUTXOKey(u.OutputID))
1071                 }
1072         }
1073 }
1074
1075 func TestOptUTXOs(t *testing.T) {
1076         cases := []struct {
1077                 uk             utxoKeeper
1078                 input          []*UTXO
1079                 inputAmount    uint64
1080                 wantUtxos      []*UTXO
1081                 optAmount      uint64
1082                 reservedAmount uint64
1083         }{
1084                 {
1085                         uk: utxoKeeper{
1086                                 reserved: map[bc.Hash]uint64{
1087                                         bc.NewHash([32]byte{0x01}): 1,
1088                                 },
1089                         },
1090                         input:          []*UTXO{},
1091                         inputAmount:    13,
1092                         wantUtxos:      []*UTXO{},
1093                         optAmount:      0,
1094                         reservedAmount: 0,
1095                 },
1096                 {
1097                         uk: utxoKeeper{
1098                                 reserved: map[bc.Hash]uint64{
1099                                         bc.NewHash([32]byte{0x01}): 1,
1100                                 },
1101                         },
1102                         input: []*UTXO{
1103                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1104                         },
1105                         inputAmount:    13,
1106                         wantUtxos:      []*UTXO{},
1107                         optAmount:      0,
1108                         reservedAmount: 1,
1109                 },
1110                 {
1111                         uk: utxoKeeper{
1112                                 reserved: map[bc.Hash]uint64{
1113                                         bc.NewHash([32]byte{0x01}): 1,
1114                                 },
1115                         },
1116                         input: []*UTXO{
1117                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1118                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1119                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1120                         },
1121                         inputAmount: 13,
1122                         wantUtxos: []*UTXO{
1123                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1124                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1125                         },
1126                         optAmount:      8,
1127                         reservedAmount: 1,
1128                 },
1129                 {
1130                         uk: utxoKeeper{
1131                                 reserved: map[bc.Hash]uint64{
1132                                         bc.NewHash([32]byte{0x01}): 1,
1133                                         bc.NewHash([32]byte{0x02}): 2,
1134                                         bc.NewHash([32]byte{0x03}): 3,
1135                                 },
1136                         },
1137                         input: []*UTXO{
1138                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1139                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1140                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1141                         },
1142                         inputAmount:    1,
1143                         wantUtxos:      []*UTXO{},
1144                         optAmount:      0,
1145                         reservedAmount: 9,
1146                 },
1147                 {
1148                         uk: utxoKeeper{},
1149                         input: []*UTXO{
1150                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1151                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1152                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1153                         },
1154                         inputAmount: 1,
1155                         wantUtxos: []*UTXO{
1156                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1157                         },
1158                         optAmount:      1,
1159                         reservedAmount: 0,
1160                 },
1161                 {
1162                         uk: utxoKeeper{},
1163                         input: []*UTXO{
1164                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1165                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1166                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1167                         },
1168                         inputAmount: 5,
1169                         wantUtxos: []*UTXO{
1170                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1171                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1172                         },
1173                         optAmount:      5,
1174                         reservedAmount: 0,
1175                 },
1176                 {
1177                         uk: utxoKeeper{},
1178                         input: []*UTXO{
1179                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1180                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1},
1181                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
1182                                 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
1183                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
1184                                 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
1185                                 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
1186                         },
1187                         inputAmount: 6,
1188                         wantUtxos: []*UTXO{
1189                                 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
1190                         },
1191                         optAmount:      6,
1192                         reservedAmount: 0,
1193                 },
1194                 {
1195                         uk: utxoKeeper{},
1196                         input: []*UTXO{
1197                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1198                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1},
1199                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
1200                                 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
1201                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
1202                                 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
1203                                 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
1204                         },
1205                         inputAmount: 5,
1206                         wantUtxos: []*UTXO{
1207                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
1208                                 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
1209                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
1210                                 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
1211                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1212                         },
1213                         optAmount:      5,
1214                         reservedAmount: 0,
1215                 },
1216                 {
1217                         uk: utxoKeeper{},
1218                         input: []*UTXO{
1219                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1220                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1221                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1222                                 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
1223                                 &UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11},
1224                                 &UTXO{OutputID: bc.NewHash([32]byte{0x13}), Amount: 13},
1225                                 &UTXO{OutputID: bc.NewHash([32]byte{0x23}), Amount: 23},
1226                                 &UTXO{OutputID: bc.NewHash([32]byte{0x31}), Amount: 31},
1227                         },
1228                         inputAmount: 13,
1229                         wantUtxos: []*UTXO{
1230                                 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
1231                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1232                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1233                         },
1234                         optAmount:      15,
1235                         reservedAmount: 0,
1236                 },
1237                 {
1238                         uk: utxoKeeper{},
1239                         input: []*UTXO{
1240                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1241                         },
1242                         inputAmount: 1,
1243                         wantUtxos: []*UTXO{
1244                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1245                         },
1246                         optAmount:      1,
1247                         reservedAmount: 0,
1248                 },
1249                 {
1250                         uk: utxoKeeper{},
1251                         input: []*UTXO{
1252                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1253                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1254                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1255                                 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4},
1256                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1257                                 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 6},
1258                                 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
1259                                 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 8},
1260                                 &UTXO{OutputID: bc.NewHash([32]byte{0x09}), Amount: 9},
1261                                 &UTXO{OutputID: bc.NewHash([32]byte{0x10}), Amount: 10},
1262                                 &UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11},
1263                                 &UTXO{OutputID: bc.NewHash([32]byte{0x12}), Amount: 12},
1264                         },
1265                         inputAmount: 15,
1266                         wantUtxos: []*UTXO{
1267                                 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1268                                 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4},
1269                                 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1270                                 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1271                                 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1272                         },
1273                         optAmount:      15,
1274                         reservedAmount: 0,
1275                 },
1276         }
1277
1278         for i, c := range cases {
1279                 got, optAmount, reservedAmount := c.uk.optUTXOs(c.input, c.inputAmount)
1280                 if !testutil.DeepEqual(got, c.wantUtxos) {
1281                         t.Errorf("case %d: utxos got %v want %v", i, got, c.wantUtxos)
1282                 }
1283                 if optAmount != c.optAmount {
1284                         t.Errorf("case %d: utxos got %v want %v", i, optAmount, c.optAmount)
1285                 }
1286                 if reservedAmount != c.reservedAmount {
1287                         t.Errorf("case %d: reservedAmount got %v want %v", i, reservedAmount, c.reservedAmount)
1288                 }
1289         }
1290 }
1291
1292 func checkUtxoKeeperEqual(t *testing.T, i int, a, b *utxoKeeper) {
1293         if !testutil.DeepEqual(a.unconfirmed, b.unconfirmed) {
1294                 t.Errorf("case %d: unconfirmed got %v want %v", i, a.unconfirmed, b.unconfirmed)
1295         }
1296         if !testutil.DeepEqual(a.reserved, b.reserved) {
1297                 t.Errorf("case %d: reserved got %v want %v", i, a.reserved, b.reserved)
1298         }
1299         if !testutil.DeepEqual(a.reservations, b.reservations) {
1300                 t.Errorf("case %d: reservations got %v want %v", i, a.reservations, b.reservations)
1301         }
1302 }