github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/account/utxo_keeper_test.go (about)

     1  package account
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/bytom/bytom/protocol/bc"
    10  	"github.com/bytom/bytom/testutil"
    11  	dbm "github.com/bytom/bytom/database/leveldb"
    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 os.RemoveAll("temp")
   277  
   278  	cases := []struct {
   279  		before        utxoKeeper
   280  		after         utxoKeeper
   281  		err           error
   282  		reserveAmount uint64
   283  		exp           time.Time
   284  	}{
   285  		{
   286  			before: utxoKeeper{
   287  				db:            testDB,
   288  				currentHeight: currentHeight,
   289  				reserved:      map[bc.Hash]uint64{},
   290  				reservations:  map[uint64]*reservation{},
   291  			},
   292  			after: utxoKeeper{
   293  				db:            testDB,
   294  				currentHeight: currentHeight,
   295  				reserved:      map[bc.Hash]uint64{},
   296  				reservations:  map[uint64]*reservation{},
   297  			},
   298  			reserveAmount: 1,
   299  			err:           ErrInsufficient,
   300  		},
   301  		{
   302  			before: utxoKeeper{
   303  				db:            testDB,
   304  				currentHeight: currentHeight,
   305  				unconfirmed: map[bc.Hash]*UTXO{
   306  					bc.NewHash([32]byte{0x01}): &UTXO{
   307  						OutputID:  bc.NewHash([32]byte{0x01}),
   308  						AccountID: "testAccount",
   309  						Amount:    3,
   310  					},
   311  				},
   312  				reserved:     map[bc.Hash]uint64{},
   313  				reservations: map[uint64]*reservation{},
   314  			},
   315  			after: utxoKeeper{
   316  				db:            testDB,
   317  				currentHeight: currentHeight,
   318  				unconfirmed: map[bc.Hash]*UTXO{
   319  					bc.NewHash([32]byte{0x01}): &UTXO{
   320  						OutputID:  bc.NewHash([32]byte{0x01}),
   321  						AccountID: "testAccount",
   322  						Amount:    3,
   323  					},
   324  				},
   325  				reserved:     map[bc.Hash]uint64{},
   326  				reservations: map[uint64]*reservation{},
   327  			},
   328  			reserveAmount: 4,
   329  			err:           ErrInsufficient,
   330  		},
   331  		{
   332  			before: utxoKeeper{
   333  				db:            testDB,
   334  				currentHeight: currentHeight,
   335  				unconfirmed: map[bc.Hash]*UTXO{
   336  					bc.NewHash([32]byte{0x01}): &UTXO{
   337  						OutputID:    bc.NewHash([32]byte{0x01}),
   338  						AccountID:   "testAccount",
   339  						Amount:      3,
   340  						ValidHeight: 9528,
   341  					},
   342  				},
   343  				reserved:     map[bc.Hash]uint64{},
   344  				reservations: map[uint64]*reservation{},
   345  			},
   346  			after: utxoKeeper{
   347  				db:            testDB,
   348  				currentHeight: currentHeight,
   349  				unconfirmed: map[bc.Hash]*UTXO{
   350  					bc.NewHash([32]byte{0x01}): &UTXO{
   351  						OutputID:    bc.NewHash([32]byte{0x01}),
   352  						AccountID:   "testAccount",
   353  						Amount:      3,
   354  						ValidHeight: 9528,
   355  					},
   356  				},
   357  				reserved:     map[bc.Hash]uint64{},
   358  				reservations: map[uint64]*reservation{},
   359  			},
   360  			reserveAmount: 3,
   361  			err:           ErrImmature,
   362  		},
   363  		{
   364  			before: utxoKeeper{
   365  				db:            testDB,
   366  				currentHeight: currentHeight,
   367  				unconfirmed: map[bc.Hash]*UTXO{
   368  					bc.NewHash([32]byte{0x01}): &UTXO{
   369  						OutputID:  bc.NewHash([32]byte{0x01}),
   370  						AccountID: "testAccount",
   371  						Amount:    3,
   372  					},
   373  				},
   374  				reserved: map[bc.Hash]uint64{
   375  					bc.NewHash([32]byte{0x01}): 0,
   376  				},
   377  				reservations: map[uint64]*reservation{},
   378  			},
   379  			after: utxoKeeper{
   380  				db:            testDB,
   381  				currentHeight: currentHeight,
   382  				unconfirmed: map[bc.Hash]*UTXO{
   383  					bc.NewHash([32]byte{0x01}): &UTXO{
   384  						OutputID:  bc.NewHash([32]byte{0x01}),
   385  						AccountID: "testAccount",
   386  						Amount:    3,
   387  					},
   388  				},
   389  				reserved: map[bc.Hash]uint64{
   390  					bc.NewHash([32]byte{0x01}): 0,
   391  				},
   392  				reservations: map[uint64]*reservation{},
   393  			},
   394  			reserveAmount: 3,
   395  			err:           ErrReserved,
   396  		},
   397  		{
   398  			before: utxoKeeper{
   399  				db:            testDB,
   400  				currentHeight: currentHeight,
   401  				unconfirmed: map[bc.Hash]*UTXO{
   402  					bc.NewHash([32]byte{0x01}): &UTXO{
   403  						OutputID:  bc.NewHash([32]byte{0x01}),
   404  						AccountID: "testAccount",
   405  						Amount:    3,
   406  					},
   407  				},
   408  				reserved:     map[bc.Hash]uint64{},
   409  				reservations: map[uint64]*reservation{},
   410  			},
   411  			after: utxoKeeper{
   412  				db:            testDB,
   413  				currentHeight: currentHeight,
   414  				unconfirmed: map[bc.Hash]*UTXO{
   415  					bc.NewHash([32]byte{0x01}): &UTXO{
   416  						OutputID:  bc.NewHash([32]byte{0x01}),
   417  						AccountID: "testAccount",
   418  						Amount:    3,
   419  					},
   420  				},
   421  				reserved: map[bc.Hash]uint64{
   422  					bc.NewHash([32]byte{0x01}): 1,
   423  				},
   424  				reservations: map[uint64]*reservation{
   425  					1: &reservation{
   426  						id: 1,
   427  						utxos: []*UTXO{
   428  							&UTXO{
   429  								OutputID:  bc.NewHash([32]byte{0x01}),
   430  								AccountID: "testAccount",
   431  								Amount:    3,
   432  							},
   433  						},
   434  						change: 1,
   435  						expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
   436  					},
   437  				},
   438  			},
   439  			reserveAmount: 2,
   440  			err:           nil,
   441  			exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
   442  		},
   443  		{
   444  			before: utxoKeeper{
   445  				db:            testDB,
   446  				currentHeight: currentHeight,
   447  				nextIndex:     1,
   448  				unconfirmed: map[bc.Hash]*UTXO{
   449  					bc.NewHash([32]byte{0x01}): &UTXO{
   450  						OutputID:  bc.NewHash([32]byte{0x01}),
   451  						AccountID: "testAccount",
   452  						Amount:    3,
   453  					},
   454  					bc.NewHash([32]byte{0x02}): &UTXO{
   455  						OutputID:  bc.NewHash([32]byte{0x02}),
   456  						AccountID: "testAccount",
   457  						Amount:    5,
   458  					},
   459  					bc.NewHash([32]byte{0x03}): &UTXO{
   460  						OutputID:  bc.NewHash([32]byte{0x03}),
   461  						AccountID: "testAccount",
   462  						Amount:    7,
   463  					},
   464  				},
   465  				reserved: map[bc.Hash]uint64{
   466  					bc.NewHash([32]byte{0x01}): 1,
   467  				},
   468  				reservations: map[uint64]*reservation{},
   469  			},
   470  			after: utxoKeeper{
   471  				db:            testDB,
   472  				currentHeight: currentHeight,
   473  				unconfirmed: map[bc.Hash]*UTXO{
   474  					bc.NewHash([32]byte{0x01}): &UTXO{
   475  						OutputID:  bc.NewHash([32]byte{0x01}),
   476  						AccountID: "testAccount",
   477  						Amount:    3,
   478  					},
   479  					bc.NewHash([32]byte{0x02}): &UTXO{
   480  						OutputID:  bc.NewHash([32]byte{0x02}),
   481  						AccountID: "testAccount",
   482  						Amount:    5,
   483  					},
   484  					bc.NewHash([32]byte{0x03}): &UTXO{
   485  						OutputID:  bc.NewHash([32]byte{0x03}),
   486  						AccountID: "testAccount",
   487  						Amount:    7,
   488  					},
   489  				},
   490  				reserved: map[bc.Hash]uint64{
   491  					bc.NewHash([32]byte{0x01}): 1,
   492  					bc.NewHash([32]byte{0x02}): 2,
   493  					bc.NewHash([32]byte{0x03}): 2,
   494  				},
   495  				reservations: map[uint64]*reservation{
   496  					2: &reservation{
   497  						id: 2,
   498  						utxos: []*UTXO{
   499  							&UTXO{
   500  								OutputID:  bc.NewHash([32]byte{0x03}),
   501  								AccountID: "testAccount",
   502  								Amount:    7,
   503  							},
   504  							&UTXO{
   505  								OutputID:  bc.NewHash([32]byte{0x02}),
   506  								AccountID: "testAccount",
   507  								Amount:    5,
   508  							},
   509  						},
   510  						change: 4,
   511  						expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
   512  					},
   513  				},
   514  			},
   515  			reserveAmount: 8,
   516  			err:           nil,
   517  			exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
   518  		},
   519  	}
   520  
   521  	for i, c := range cases {
   522  		if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.exp); err != c.err {
   523  			t.Errorf("case %d: got error %v want error %v", i, err, c.err)
   524  		}
   525  		checkUtxoKeeperEqual(t, i, &c.before, &c.after)
   526  	}
   527  }
   528  
   529  func TestReserveParticular(t *testing.T) {
   530  	currentHeight := func() uint64 { return 9527 }
   531  	testDB := dbm.NewDB("testdb", "leveldb", "temp")
   532  	defer os.RemoveAll("temp")
   533  
   534  	cases := []struct {
   535  		before      utxoKeeper
   536  		after       utxoKeeper
   537  		err         error
   538  		reserveHash bc.Hash
   539  		exp         time.Time
   540  	}{
   541  		{
   542  			before: utxoKeeper{
   543  				db:            testDB,
   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  					},
   551  				},
   552  				reserved: map[bc.Hash]uint64{
   553  					bc.NewHash([32]byte{0x01}): 0,
   554  				},
   555  				reservations: map[uint64]*reservation{},
   556  			},
   557  			after: utxoKeeper{
   558  				db:            testDB,
   559  				currentHeight: currentHeight,
   560  				unconfirmed: map[bc.Hash]*UTXO{
   561  					bc.NewHash([32]byte{0x01}): &UTXO{
   562  						OutputID:  bc.NewHash([32]byte{0x01}),
   563  						AccountID: "testAccount",
   564  						Amount:    3,
   565  					},
   566  				},
   567  				reserved: map[bc.Hash]uint64{
   568  					bc.NewHash([32]byte{0x01}): 0,
   569  				},
   570  				reservations: map[uint64]*reservation{},
   571  			},
   572  			reserveHash: bc.NewHash([32]byte{0x01}),
   573  			err:         ErrReserved,
   574  		},
   575  		{
   576  			before: utxoKeeper{
   577  				db:            testDB,
   578  				currentHeight: currentHeight,
   579  				unconfirmed: map[bc.Hash]*UTXO{
   580  					bc.NewHash([32]byte{0x01}): &UTXO{
   581  						OutputID:    bc.NewHash([32]byte{0x01}),
   582  						AccountID:   "testAccount",
   583  						Amount:      3,
   584  						ValidHeight: 9528,
   585  					},
   586  				},
   587  				reserved:     map[bc.Hash]uint64{},
   588  				reservations: map[uint64]*reservation{},
   589  			},
   590  			after: utxoKeeper{
   591  				db:            testDB,
   592  				currentHeight: currentHeight,
   593  				unconfirmed: map[bc.Hash]*UTXO{
   594  					bc.NewHash([32]byte{0x01}): &UTXO{
   595  						OutputID:    bc.NewHash([32]byte{0x01}),
   596  						AccountID:   "testAccount",
   597  						Amount:      3,
   598  						ValidHeight: 9528,
   599  					},
   600  				},
   601  				reserved:     map[bc.Hash]uint64{},
   602  				reservations: map[uint64]*reservation{},
   603  			},
   604  			reserveHash: bc.NewHash([32]byte{0x01}),
   605  			err:         ErrImmature,
   606  		},
   607  		{
   608  			before: utxoKeeper{
   609  				db:            testDB,
   610  				currentHeight: currentHeight,
   611  				unconfirmed: map[bc.Hash]*UTXO{
   612  					bc.NewHash([32]byte{0x01}): &UTXO{
   613  						OutputID:  bc.NewHash([32]byte{0x01}),
   614  						AccountID: "testAccount",
   615  						Amount:    3,
   616  					},
   617  				},
   618  				reserved:     map[bc.Hash]uint64{},
   619  				reservations: map[uint64]*reservation{},
   620  			},
   621  			after: utxoKeeper{
   622  				db:            testDB,
   623  				currentHeight: currentHeight,
   624  				unconfirmed: map[bc.Hash]*UTXO{
   625  					bc.NewHash([32]byte{0x01}): &UTXO{
   626  						OutputID:  bc.NewHash([32]byte{0x01}),
   627  						AccountID: "testAccount",
   628  						Amount:    3,
   629  					},
   630  				},
   631  				reserved: map[bc.Hash]uint64{
   632  					bc.NewHash([32]byte{0x01}): 1,
   633  				},
   634  				reservations: map[uint64]*reservation{
   635  					1: &reservation{
   636  						id: 1,
   637  						utxos: []*UTXO{
   638  							&UTXO{
   639  								OutputID:  bc.NewHash([32]byte{0x01}),
   640  								AccountID: "testAccount",
   641  								Amount:    3,
   642  							},
   643  						},
   644  						change: 0,
   645  						expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
   646  					},
   647  				},
   648  			},
   649  			reserveHash: bc.NewHash([32]byte{0x01}),
   650  			err:         nil,
   651  			exp:         time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
   652  		},
   653  	}
   654  
   655  	for i, c := range cases {
   656  		if _, err := c.before.ReserveParticular(c.reserveHash, true, c.exp); err != c.err {
   657  			t.Errorf("case %d: got error %v want error %v", i, err, c.err)
   658  		}
   659  		checkUtxoKeeperEqual(t, i, &c.before, &c.after)
   660  	}
   661  }
   662  
   663  func TestExpireReservation(t *testing.T) {
   664  	before := &utxoKeeper{
   665  		reservations: map[uint64]*reservation{
   666  			1: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)},
   667  			2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
   668  			3: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)},
   669  			4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
   670  			5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
   671  		},
   672  	}
   673  	after := &utxoKeeper{
   674  		reservations: map[uint64]*reservation{
   675  			2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
   676  			4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
   677  			5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
   678  		},
   679  	}
   680  	before.expireReservation(time.Date(2017, 8, 10, 0, 0, 0, 0, time.UTC))
   681  	checkUtxoKeeperEqual(t, 0, before, after)
   682  }
   683  
   684  func TestFindUtxos(t *testing.T) {
   685  	currentHeight := func() uint64 { return 9527 }
   686  	testDB := dbm.NewDB("testdb", "leveldb", "temp")
   687  	defer os.RemoveAll("temp")
   688  
   689  	cases := []struct {
   690  		uk             utxoKeeper
   691  		dbUtxos        []*UTXO
   692  		useUnconfirmed bool
   693  		wantUtxos      []*UTXO
   694  		immatureAmount uint64
   695  	}{
   696  		{
   697  			uk: utxoKeeper{
   698  				db:            testDB,
   699  				currentHeight: currentHeight,
   700  				unconfirmed:   map[bc.Hash]*UTXO{},
   701  			},
   702  			dbUtxos:        []*UTXO{},
   703  			useUnconfirmed: true,
   704  			wantUtxos:      []*UTXO{},
   705  			immatureAmount: 0,
   706  		},
   707  		{
   708  			uk: utxoKeeper{
   709  				db:            testDB,
   710  				currentHeight: currentHeight,
   711  				unconfirmed:   map[bc.Hash]*UTXO{},
   712  			},
   713  			dbUtxos: []*UTXO{
   714  				&UTXO{
   715  					OutputID:  bc.NewHash([32]byte{0x01}),
   716  					AccountID: "testAccount",
   717  					Amount:    3,
   718  				},
   719  				&UTXO{
   720  					OutputID:  bc.NewHash([32]byte{0x02}),
   721  					AccountID: "testAccount",
   722  					AssetID:   bc.AssetID{V0: 6},
   723  					Amount:    3,
   724  				},
   725  			},
   726  			useUnconfirmed: false,
   727  			wantUtxos: []*UTXO{
   728  				&UTXO{
   729  					OutputID:  bc.NewHash([32]byte{0x01}),
   730  					AccountID: "testAccount",
   731  					Amount:    3,
   732  				},
   733  			},
   734  			immatureAmount: 0,
   735  		},
   736  		{
   737  			uk: utxoKeeper{
   738  				db:            testDB,
   739  				currentHeight: currentHeight,
   740  				unconfirmed:   map[bc.Hash]*UTXO{},
   741  			},
   742  			dbUtxos: []*UTXO{
   743  				&UTXO{
   744  					OutputID:    bc.NewHash([32]byte{0x02}),
   745  					AccountID:   "testAccount",
   746  					Amount:      3,
   747  					ValidHeight: 9528,
   748  				},
   749  			},
   750  			useUnconfirmed: false,
   751  			wantUtxos:      []*UTXO{},
   752  			immatureAmount: 3,
   753  		},
   754  		{
   755  			uk: utxoKeeper{
   756  				db:            testDB,
   757  				currentHeight: currentHeight,
   758  				unconfirmed: map[bc.Hash]*UTXO{
   759  					bc.NewHash([32]byte{0x01}): &UTXO{
   760  						OutputID:  bc.NewHash([32]byte{0x01}),
   761  						AccountID: "testAccount",
   762  						Amount:    3,
   763  					},
   764  				},
   765  			},
   766  			dbUtxos: []*UTXO{
   767  				&UTXO{
   768  					OutputID:  bc.NewHash([32]byte{0x02}),
   769  					AccountID: "testAccount",
   770  					Amount:    3,
   771  				},
   772  			},
   773  			useUnconfirmed: false,
   774  			wantUtxos: []*UTXO{
   775  				&UTXO{
   776  					OutputID:  bc.NewHash([32]byte{0x02}),
   777  					AccountID: "testAccount",
   778  					Amount:    3,
   779  				},
   780  			},
   781  			immatureAmount: 0,
   782  		},
   783  		{
   784  			uk: utxoKeeper{
   785  				db:            testDB,
   786  				currentHeight: currentHeight,
   787  				unconfirmed: map[bc.Hash]*UTXO{
   788  					bc.NewHash([32]byte{0x11}): &UTXO{
   789  						OutputID:  bc.NewHash([32]byte{0x01}),
   790  						AccountID: "testAccount",
   791  						Amount:    3,
   792  					},
   793  				},
   794  			},
   795  			dbUtxos: []*UTXO{
   796  				&UTXO{
   797  					OutputID:  bc.NewHash([32]byte{0x02}),
   798  					AccountID: "testAccount",
   799  					Amount:    3,
   800  				},
   801  			},
   802  			useUnconfirmed: true,
   803  			wantUtxos: []*UTXO{
   804  				&UTXO{
   805  					OutputID:  bc.NewHash([32]byte{0x02}),
   806  					AccountID: "testAccount",
   807  					Amount:    3,
   808  				},
   809  				&UTXO{
   810  					OutputID:  bc.NewHash([32]byte{0x01}),
   811  					AccountID: "testAccount",
   812  					Amount:    3,
   813  				},
   814  			},
   815  			immatureAmount: 0,
   816  		},
   817  		{
   818  			uk: utxoKeeper{
   819  				db:            testDB,
   820  				currentHeight: currentHeight,
   821  				unconfirmed: map[bc.Hash]*UTXO{
   822  					bc.NewHash([32]byte{0x01}): &UTXO{
   823  						OutputID:  bc.NewHash([32]byte{0x01}),
   824  						AccountID: "testAccount",
   825  						Amount:    1,
   826  					},
   827  					bc.NewHash([32]byte{0x02}): &UTXO{
   828  						OutputID:  bc.NewHash([32]byte{0x02}),
   829  						AccountID: "notMe",
   830  						Amount:    2,
   831  					},
   832  				},
   833  			},
   834  			dbUtxos: []*UTXO{
   835  				&UTXO{
   836  					OutputID:  bc.NewHash([32]byte{0x03}),
   837  					AccountID: "testAccount",
   838  					Amount:    3,
   839  				},
   840  				&UTXO{
   841  					OutputID:  bc.NewHash([32]byte{0x04}),
   842  					AccountID: "notMe",
   843  					Amount:    4,
   844  				},
   845  			},
   846  			useUnconfirmed: true,
   847  			wantUtxos: []*UTXO{
   848  				&UTXO{
   849  					OutputID:  bc.NewHash([32]byte{0x03}),
   850  					AccountID: "testAccount",
   851  					Amount:    3,
   852  				},
   853  				&UTXO{
   854  					OutputID:  bc.NewHash([32]byte{0x01}),
   855  					AccountID: "testAccount",
   856  					Amount:    1,
   857  				},
   858  			},
   859  			immatureAmount: 0,
   860  		},
   861  	}
   862  
   863  	for i, c := range cases {
   864  		for _, u := range c.dbUtxos {
   865  			data, err := json.Marshal(u)
   866  			if err != nil {
   867  				t.Error(err)
   868  			}
   869  			testDB.Set(StandardUTXOKey(u.OutputID), data)
   870  		}
   871  
   872  		gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed)
   873  		if !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
   874  			t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
   875  		}
   876  		if immatureAmount != c.immatureAmount {
   877  			t.Errorf("case %d: got %v want %v", i, immatureAmount, c.immatureAmount)
   878  		}
   879  
   880  		for _, u := range c.dbUtxos {
   881  			testDB.Delete(StandardUTXOKey(u.OutputID))
   882  		}
   883  	}
   884  }
   885  
   886  func TestFindUtxo(t *testing.T) {
   887  	currentHeight := func() uint64 { return 9527 }
   888  	testDB := dbm.NewDB("testdb", "leveldb", "temp")
   889  	defer os.RemoveAll("temp")
   890  
   891  	cases := []struct {
   892  		uk             utxoKeeper
   893  		dbUtxos        map[string]*UTXO
   894  		outHash        bc.Hash
   895  		useUnconfirmed bool
   896  		wantUtxo       *UTXO
   897  		err            error
   898  	}{
   899  		{
   900  			uk: utxoKeeper{
   901  				db:            testDB,
   902  				currentHeight: currentHeight,
   903  				unconfirmed:   map[bc.Hash]*UTXO{},
   904  			},
   905  			dbUtxos:  map[string]*UTXO{},
   906  			outHash:  bc.NewHash([32]byte{0x01}),
   907  			wantUtxo: nil,
   908  			err:      ErrMatchUTXO,
   909  		},
   910  		{
   911  			uk: utxoKeeper{
   912  				db:            testDB,
   913  				currentHeight: currentHeight,
   914  				unconfirmed: map[bc.Hash]*UTXO{
   915  					bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   916  				},
   917  			},
   918  			dbUtxos:        map[string]*UTXO{},
   919  			outHash:        bc.NewHash([32]byte{0x01}),
   920  			wantUtxo:       nil,
   921  			useUnconfirmed: false,
   922  			err:            ErrMatchUTXO,
   923  		},
   924  		{
   925  			uk: utxoKeeper{
   926  				db:            testDB,
   927  				currentHeight: currentHeight,
   928  				unconfirmed: map[bc.Hash]*UTXO{
   929  					bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   930  				},
   931  			},
   932  			dbUtxos:        map[string]*UTXO{},
   933  			outHash:        bc.NewHash([32]byte{0x01}),
   934  			wantUtxo:       &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   935  			useUnconfirmed: true,
   936  			err:            nil,
   937  		},
   938  		{
   939  			uk: utxoKeeper{
   940  				db:            testDB,
   941  				currentHeight: currentHeight,
   942  				unconfirmed:   map[bc.Hash]*UTXO{},
   943  			},
   944  			dbUtxos: map[string]*UTXO{
   945  				string(StandardUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   946  			},
   947  			outHash:        bc.NewHash([32]byte{0x01}),
   948  			wantUtxo:       &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   949  			useUnconfirmed: false,
   950  			err:            nil,
   951  		},
   952  		{
   953  			uk: utxoKeeper{
   954  				db:            testDB,
   955  				currentHeight: currentHeight,
   956  				unconfirmed:   map[bc.Hash]*UTXO{},
   957  			},
   958  			dbUtxos: map[string]*UTXO{
   959  				string(ContractUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   960  			},
   961  			outHash:        bc.NewHash([32]byte{0x01}),
   962  			wantUtxo:       &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
   963  			useUnconfirmed: false,
   964  			err:            nil,
   965  		},
   966  	}
   967  
   968  	for i, c := range cases {
   969  		for k, u := range c.dbUtxos {
   970  			data, err := json.Marshal(u)
   971  			if err != nil {
   972  				t.Error(err)
   973  			}
   974  			testDB.Set([]byte(k), data)
   975  		}
   976  
   977  		gotUtxo, err := c.uk.findUtxo(c.outHash, c.useUnconfirmed)
   978  		if !testutil.DeepEqual(gotUtxo, c.wantUtxo) {
   979  			t.Errorf("case %d: got %v want %v", i, gotUtxo, c.wantUtxo)
   980  		}
   981  		if err != c.err {
   982  			t.Errorf("case %d: got %v want %v", i, err, c.err)
   983  		}
   984  
   985  		for _, u := range c.dbUtxos {
   986  			testDB.Delete(StandardUTXOKey(u.OutputID))
   987  		}
   988  	}
   989  }
   990  
   991  func TestOptUTXOs(t *testing.T) {
   992  	cases := []struct {
   993  		uk             utxoKeeper
   994  		input          []*UTXO
   995  		inputAmount    uint64
   996  		wantUtxos      []*UTXO
   997  		optAmount      uint64
   998  		reservedAmount uint64
   999  	}{
  1000  		{
  1001  			uk: utxoKeeper{
  1002  				reserved: map[bc.Hash]uint64{
  1003  					bc.NewHash([32]byte{0x01}): 1,
  1004  				},
  1005  			},
  1006  			input:          []*UTXO{},
  1007  			inputAmount:    13,
  1008  			wantUtxos:      []*UTXO{},
  1009  			optAmount:      0,
  1010  			reservedAmount: 0,
  1011  		},
  1012  		{
  1013  			uk: utxoKeeper{
  1014  				reserved: map[bc.Hash]uint64{
  1015  					bc.NewHash([32]byte{0x01}): 1,
  1016  				},
  1017  			},
  1018  			input: []*UTXO{
  1019  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1020  			},
  1021  			inputAmount:    13,
  1022  			wantUtxos:      []*UTXO{},
  1023  			optAmount:      0,
  1024  			reservedAmount: 1,
  1025  		},
  1026  		{
  1027  			uk: utxoKeeper{
  1028  				reserved: map[bc.Hash]uint64{
  1029  					bc.NewHash([32]byte{0x01}): 1,
  1030  				},
  1031  			},
  1032  			input: []*UTXO{
  1033  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1034  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
  1035  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
  1036  			},
  1037  			inputAmount: 13,
  1038  			wantUtxos: []*UTXO{
  1039  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
  1040  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
  1041  			},
  1042  			optAmount:      8,
  1043  			reservedAmount: 1,
  1044  		},
  1045  		{
  1046  			uk: utxoKeeper{
  1047  				reserved: map[bc.Hash]uint64{
  1048  					bc.NewHash([32]byte{0x01}): 1,
  1049  					bc.NewHash([32]byte{0x02}): 2,
  1050  					bc.NewHash([32]byte{0x03}): 3,
  1051  				},
  1052  			},
  1053  			input: []*UTXO{
  1054  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1055  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
  1056  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
  1057  			},
  1058  			inputAmount:    1,
  1059  			wantUtxos:      []*UTXO{},
  1060  			optAmount:      0,
  1061  			reservedAmount: 9,
  1062  		},
  1063  		{
  1064  			uk: utxoKeeper{},
  1065  			input: []*UTXO{
  1066  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1067  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
  1068  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
  1069  			},
  1070  			inputAmount: 1,
  1071  			wantUtxos: []*UTXO{
  1072  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1073  			},
  1074  			optAmount:      1,
  1075  			reservedAmount: 0,
  1076  		},
  1077  		{
  1078  			uk: utxoKeeper{},
  1079  			input: []*UTXO{
  1080  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
  1081  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
  1082  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
  1083  			},
  1084  			inputAmount: 5,
  1085  			wantUtxos: []*UTXO{
  1086  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
  1087  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
  1088  			},
  1089  			optAmount:      5,
  1090  			reservedAmount: 0,
  1091  		},
  1092  		{
  1093  			uk: utxoKeeper{},
  1094  			input: []*UTXO{
  1095  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1096  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1},
  1097  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
  1098  				&UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
  1099  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
  1100  				&UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
  1101  				&UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
  1102  			},
  1103  			inputAmount: 6,
  1104  			wantUtxos: []*UTXO{
  1105  				&UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
  1106  			},
  1107  			optAmount:      6,
  1108  			reservedAmount: 0,
  1109  		},
  1110  		{
  1111  			uk: utxoKeeper{},
  1112  			input: []*UTXO{
  1113  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1114  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1},
  1115  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
  1116  				&UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
  1117  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
  1118  				&UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
  1119  				&UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
  1120  			},
  1121  			inputAmount: 5,
  1122  			wantUtxos: []*UTXO{
  1123  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
  1124  				&UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
  1125  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
  1126  				&UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
  1127  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1128  			},
  1129  			optAmount:      5,
  1130  			reservedAmount: 0,
  1131  		},
  1132  		{
  1133  			uk: utxoKeeper{},
  1134  			input: []*UTXO{
  1135  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1136  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
  1137  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
  1138  				&UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
  1139  				&UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11},
  1140  				&UTXO{OutputID: bc.NewHash([32]byte{0x13}), Amount: 13},
  1141  				&UTXO{OutputID: bc.NewHash([32]byte{0x23}), Amount: 23},
  1142  				&UTXO{OutputID: bc.NewHash([32]byte{0x31}), Amount: 31},
  1143  			},
  1144  			inputAmount: 13,
  1145  			wantUtxos: []*UTXO{
  1146  				&UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
  1147  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
  1148  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
  1149  			},
  1150  			optAmount:      15,
  1151  			reservedAmount: 0,
  1152  		},
  1153  		{
  1154  			uk: utxoKeeper{},
  1155  			input: []*UTXO{
  1156  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1157  			},
  1158  			inputAmount: 1,
  1159  			wantUtxos: []*UTXO{
  1160  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1161  			},
  1162  			optAmount:      1,
  1163  			reservedAmount: 0,
  1164  		},
  1165  		{
  1166  			uk: utxoKeeper{},
  1167  			input: []*UTXO{
  1168  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1169  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
  1170  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
  1171  				&UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4},
  1172  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
  1173  				&UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 6},
  1174  				&UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
  1175  				&UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 8},
  1176  				&UTXO{OutputID: bc.NewHash([32]byte{0x09}), Amount: 9},
  1177  				&UTXO{OutputID: bc.NewHash([32]byte{0x10}), Amount: 10},
  1178  				&UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11},
  1179  				&UTXO{OutputID: bc.NewHash([32]byte{0x12}), Amount: 12},
  1180  			},
  1181  			inputAmount: 15,
  1182  			wantUtxos: []*UTXO{
  1183  				&UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
  1184  				&UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4},
  1185  				&UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
  1186  				&UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
  1187  				&UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
  1188  			},
  1189  			optAmount:      15,
  1190  			reservedAmount: 0,
  1191  		},
  1192  	}
  1193  
  1194  	for i, c := range cases {
  1195  		got, optAmount, reservedAmount := c.uk.optUTXOs(c.input, c.inputAmount)
  1196  		if !testutil.DeepEqual(got, c.wantUtxos) {
  1197  			t.Errorf("case %d: utxos got %v want %v", i, got, c.wantUtxos)
  1198  		}
  1199  		if optAmount != c.optAmount {
  1200  			t.Errorf("case %d: utxos got %v want %v", i, optAmount, c.optAmount)
  1201  		}
  1202  		if reservedAmount != c.reservedAmount {
  1203  			t.Errorf("case %d: reservedAmount got %v want %v", i, reservedAmount, c.reservedAmount)
  1204  		}
  1205  	}
  1206  }
  1207  
  1208  func checkUtxoKeeperEqual(t *testing.T, i int, a, b *utxoKeeper) {
  1209  	if !testutil.DeepEqual(a.unconfirmed, b.unconfirmed) {
  1210  		t.Errorf("case %d: unconfirmed got %v want %v", i, a.unconfirmed, b.unconfirmed)
  1211  	}
  1212  	if !testutil.DeepEqual(a.reserved, b.reserved) {
  1213  		t.Errorf("case %d: reserved got %v want %v", i, a.reserved, b.reserved)
  1214  	}
  1215  	if !testutil.DeepEqual(a.reservations, b.reservations) {
  1216  		t.Errorf("case %d: reservations got %v want %v", i, a.reservations, b.reservations)
  1217  	}
  1218  }