OSDN Git Service

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