github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/wallet/utxo_test.go (about)

     1  package wallet
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"sort"
     9  	"testing"
    10  
    11  	"github.com/bytom/bytom/account"
    12  	"github.com/bytom/bytom/consensus"
    13  	dbm "github.com/bytom/bytom/database/leveldb"
    14  	"github.com/bytom/bytom/protocol/bc"
    15  	"github.com/bytom/bytom/protocol/bc/types"
    16  	"github.com/bytom/bytom/testutil"
    17  )
    18  
    19  func TestGetAccountUtxos(t *testing.T) {
    20  	testDB := dbm.NewDB("testdb", "leveldb", "temp")
    21  	defer os.RemoveAll("temp")
    22  
    23  	cases := []struct {
    24  		dbUtxos          map[string]*account.UTXO
    25  		unconfirmedUtxos []*account.UTXO
    26  		id               string
    27  		unconfirmed      bool
    28  		isSmartContract  bool
    29  		wantUtxos        []*account.UTXO
    30  	}{
    31  		{
    32  			dbUtxos:         map[string]*account.UTXO{},
    33  			id:              "",
    34  			unconfirmed:     false,
    35  			isSmartContract: false,
    36  			wantUtxos:       []*account.UTXO{},
    37  		},
    38  		{
    39  			dbUtxos: map[string]*account.UTXO{
    40  				string(account.StandardUTXOKey(bc.Hash{V0: 1})): &account.UTXO{
    41  					OutputID: bc.Hash{V0: 1},
    42  				},
    43  				string(account.StandardUTXOKey(bc.Hash{V0: 2})): &account.UTXO{
    44  					OutputID: bc.Hash{V0: 2},
    45  				},
    46  				string(account.StandardUTXOKey(bc.Hash{V0: 3})): &account.UTXO{
    47  					OutputID: bc.Hash{V0: 3},
    48  				},
    49  				string(account.ContractUTXOKey(bc.Hash{V0: 4})): &account.UTXO{
    50  					OutputID: bc.Hash{V0: 4},
    51  				},
    52  			},
    53  			unconfirmedUtxos: []*account.UTXO{},
    54  			id:               "",
    55  			isSmartContract:  false,
    56  			wantUtxos: []*account.UTXO{
    57  				&account.UTXO{OutputID: bc.Hash{V0: 1}},
    58  				&account.UTXO{OutputID: bc.Hash{V0: 2}},
    59  				&account.UTXO{OutputID: bc.Hash{V0: 3}},
    60  			},
    61  		},
    62  		{
    63  			dbUtxos: map[string]*account.UTXO{
    64  				string(account.StandardUTXOKey(bc.Hash{V0: 1})): &account.UTXO{
    65  					OutputID: bc.Hash{V0: 1},
    66  				},
    67  				string(account.StandardUTXOKey(bc.Hash{V0: 2})): &account.UTXO{
    68  					OutputID: bc.Hash{V0: 2},
    69  				},
    70  				string(account.StandardUTXOKey(bc.Hash{V0: 3})): &account.UTXO{
    71  					OutputID: bc.Hash{V0: 3},
    72  				},
    73  				string(account.ContractUTXOKey(bc.Hash{V0: 4})): &account.UTXO{
    74  					OutputID: bc.Hash{V0: 4},
    75  				},
    76  			},
    77  			unconfirmedUtxos: []*account.UTXO{
    78  				&account.UTXO{
    79  					OutputID:       bc.Hash{V0: 5},
    80  					ControlProgram: []byte("smart contract"),
    81  				},
    82  			},
    83  			id:              "",
    84  			unconfirmed:     false,
    85  			isSmartContract: true,
    86  			wantUtxos: []*account.UTXO{
    87  				&account.UTXO{OutputID: bc.Hash{V0: 4}},
    88  			},
    89  		},
    90  		{
    91  			dbUtxos: map[string]*account.UTXO{
    92  				string(account.StandardUTXOKey(bc.Hash{V0: 1})): &account.UTXO{
    93  					OutputID: bc.Hash{V0: 1},
    94  				},
    95  				string(account.StandardUTXOKey(bc.Hash{V0: 1, V1: 2})): &account.UTXO{
    96  					OutputID: bc.Hash{V0: 1, V1: 2},
    97  				},
    98  				string(account.StandardUTXOKey(bc.Hash{V0: 2})): &account.UTXO{
    99  					OutputID: bc.Hash{V0: 2},
   100  				},
   101  				string(account.StandardUTXOKey(bc.Hash{V0: 2, V1: 2})): &account.UTXO{
   102  					OutputID: bc.Hash{V0: 2, V1: 2},
   103  				},
   104  			},
   105  			unconfirmedUtxos: []*account.UTXO{
   106  				&account.UTXO{
   107  					OutputID:       bc.Hash{V0: 6},
   108  					ControlProgram: []byte{0x51},
   109  				},
   110  			},
   111  			id:              "0000000000000002",
   112  			unconfirmed:     false,
   113  			isSmartContract: false,
   114  			wantUtxos: []*account.UTXO{
   115  				&account.UTXO{OutputID: bc.Hash{V0: 2}},
   116  				&account.UTXO{OutputID: bc.Hash{V0: 2, V1: 2}},
   117  			},
   118  		},
   119  		{
   120  			dbUtxos: map[string]*account.UTXO{
   121  				string(account.StandardUTXOKey(bc.Hash{V0: 3})): &account.UTXO{
   122  					OutputID: bc.Hash{V0: 3},
   123  				},
   124  				string(account.ContractUTXOKey(bc.Hash{V0: 4})): &account.UTXO{
   125  					OutputID: bc.Hash{V0: 4},
   126  				},
   127  			},
   128  			unconfirmedUtxos: []*account.UTXO{
   129  				&account.UTXO{
   130  					OutputID:       bc.Hash{V0: 5},
   131  					ControlProgram: []byte("smart contract"),
   132  				},
   133  				&account.UTXO{
   134  					OutputID:       bc.Hash{V0: 6},
   135  					ControlProgram: []byte{0x51},
   136  				},
   137  			},
   138  			id:              "",
   139  			unconfirmed:     true,
   140  			isSmartContract: true,
   141  			wantUtxos: []*account.UTXO{
   142  				&account.UTXO{
   143  					OutputID:       bc.Hash{V0: 5},
   144  					ControlProgram: []byte("smart contract"),
   145  				},
   146  				&account.UTXO{
   147  					OutputID: bc.Hash{V0: 4},
   148  				},
   149  			},
   150  		},
   151  		{
   152  			dbUtxos: map[string]*account.UTXO{
   153  				string(account.StandardUTXOKey(bc.Hash{V0: 3})): &account.UTXO{
   154  					OutputID: bc.Hash{V0: 3},
   155  				},
   156  				string(account.ContractUTXOKey(bc.Hash{V0: 4})): &account.UTXO{
   157  					OutputID: bc.Hash{V0: 4},
   158  				},
   159  			},
   160  			unconfirmedUtxos: []*account.UTXO{
   161  				&account.UTXO{
   162  					OutputID:       bc.Hash{V0: 5},
   163  					ControlProgram: []byte("smart contract"),
   164  				},
   165  				&account.UTXO{
   166  					OutputID:       bc.Hash{V0: 6},
   167  					ControlProgram: []byte{0x51},
   168  				},
   169  			},
   170  			id:              "",
   171  			unconfirmed:     true,
   172  			isSmartContract: false,
   173  			wantUtxos: []*account.UTXO{
   174  				&account.UTXO{
   175  					OutputID:       bc.Hash{V0: 6},
   176  					ControlProgram: []byte{0x51},
   177  				},
   178  				&account.UTXO{
   179  					OutputID: bc.Hash{V0: 3},
   180  				},
   181  			},
   182  		},
   183  	}
   184  
   185  	w := &Wallet{DB: testDB}
   186  	for i, c := range cases {
   187  		for k, u := range c.dbUtxos {
   188  			data, err := json.Marshal(u)
   189  			if err != nil {
   190  				t.Error(err)
   191  			}
   192  			testDB.Set([]byte(k), data)
   193  		}
   194  
   195  		w.AccountMgr = account.NewManager(testDB, nil)
   196  		w.AccountMgr.AddUnconfirmedUtxo(c.unconfirmedUtxos)
   197  		gotUtxos := w.GetAccountUtxos("", c.id, c.unconfirmed, c.isSmartContract, false)
   198  		if !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
   199  			t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
   200  		}
   201  
   202  		for k := range c.dbUtxos {
   203  			testDB.Delete([]byte(k))
   204  		}
   205  	}
   206  }
   207  
   208  //because can not pass by btm2.0 branch
   209  func TestFilterAccountUtxo(t *testing.T) {
   210  	testDB := dbm.NewDB("testdb", "leveldb", "temp")
   211  	defer os.RemoveAll("temp")
   212  
   213  	cases := []struct {
   214  		dbPrograms map[string]*account.CtrlProgram
   215  		input      []*account.UTXO
   216  		wantUtxos  []*account.UTXO
   217  	}{
   218  		{
   219  			dbPrograms: map[string]*account.CtrlProgram{},
   220  			input:      []*account.UTXO{},
   221  			wantUtxos:  []*account.UTXO{},
   222  		},
   223  		{
   224  			dbPrograms: map[string]*account.CtrlProgram{
   225  				"436f6e74726163743a2a37a64a4e15a772ab43bf3f5956d0d1f353946496788e7f40d0ff1796286a6f": &account.CtrlProgram{
   226  					AccountID: "testAccount",
   227  					Address:   "testAddress",
   228  					KeyIndex:  53,
   229  					Change:    true,
   230  				},
   231  			},
   232  			input: []*account.UTXO{
   233  				&account.UTXO{
   234  					ControlProgram: []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   235  					AssetID:        bc.AssetID{V0: 1},
   236  					Amount:         3,
   237  				},
   238  				&account.UTXO{
   239  					ControlProgram: []byte{0x91},
   240  					AssetID:        bc.AssetID{V0: 1},
   241  					Amount:         4,
   242  				},
   243  			},
   244  			wantUtxos: []*account.UTXO{
   245  				&account.UTXO{
   246  					ControlProgram:      []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   247  					AssetID:             bc.AssetID{V0: 1},
   248  					Amount:              3,
   249  					AccountID:           "testAccount",
   250  					Address:             "testAddress",
   251  					ControlProgramIndex: 53,
   252  					Change:              true,
   253  				},
   254  			},
   255  		},
   256  		{
   257  			dbPrograms: map[string]*account.CtrlProgram{},
   258  			input: []*account.UTXO{
   259  				&account.UTXO{
   260  					ControlProgram: []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   261  					AssetID:        bc.AssetID{V0: 1},
   262  					Amount:         3,
   263  				},
   264  				&account.UTXO{
   265  					ControlProgram: []byte{0x91},
   266  					AssetID:        bc.AssetID{V0: 1},
   267  					Amount:         3,
   268  				},
   269  			},
   270  			wantUtxos: []*account.UTXO{},
   271  		},
   272  		{
   273  			dbPrograms: map[string]*account.CtrlProgram{
   274  				"436f6e74726163743a2a37a64a4e15a772ab43bf3f5956d0d1f353946496788e7f40d0ff1796286a6f": &account.CtrlProgram{
   275  					AccountID: "testAccount",
   276  					Address:   "testAddress",
   277  					KeyIndex:  53,
   278  					Change:    true,
   279  				},
   280  				"436f6e74726163743adb4d86262c12ba70d50b3ca3ae102d5682436243bd1e8c79569603f75675036a": &account.CtrlProgram{
   281  					AccountID: "testAccount2",
   282  					Address:   "testAddress2",
   283  					KeyIndex:  72,
   284  					Change:    false,
   285  				},
   286  			},
   287  			input: []*account.UTXO{
   288  				&account.UTXO{
   289  					ControlProgram: []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   290  					AssetID:        bc.AssetID{V0: 1},
   291  					Amount:         3,
   292  				},
   293  				&account.UTXO{
   294  					ControlProgram: []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   295  					AssetID:        bc.AssetID{V0: 1},
   296  					Amount:         5,
   297  				},
   298  				&account.UTXO{
   299  					ControlProgram: []byte{0x00, 0x14, 0xc6, 0xbf, 0x22, 0x19, 0x64, 0x2a, 0xc5, 0x9e, 0x5b, 0xe4, 0xeb, 0xdf, 0x5b, 0x22, 0x49, 0x56, 0xa7, 0x98, 0xa4, 0xdf},
   300  					AssetID:        bc.AssetID{V0: 1},
   301  					Amount:         7,
   302  				},
   303  			},
   304  			wantUtxos: []*account.UTXO{
   305  				&account.UTXO{
   306  					ControlProgram:      []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   307  					AssetID:             bc.AssetID{V0: 1},
   308  					Amount:              3,
   309  					AccountID:           "testAccount",
   310  					Address:             "testAddress",
   311  					ControlProgramIndex: 53,
   312  					Change:              true,
   313  				},
   314  				&account.UTXO{
   315  					ControlProgram:      []byte{0x00, 0x14, 0x62, 0x50, 0x18, 0xb6, 0x85, 0x77, 0xba, 0x9b, 0x26, 0x19, 0xc8, 0x1d, 0x2e, 0x96, 0xba, 0x22, 0xbe, 0x77, 0x77, 0xd7},
   316  					AssetID:             bc.AssetID{V0: 1},
   317  					Amount:              5,
   318  					AccountID:           "testAccount",
   319  					Address:             "testAddress",
   320  					ControlProgramIndex: 53,
   321  					Change:              true,
   322  				},
   323  				&account.UTXO{
   324  					ControlProgram:      []byte{0x00, 0x14, 0xc6, 0xbf, 0x22, 0x19, 0x64, 0x2a, 0xc5, 0x9e, 0x5b, 0xe4, 0xeb, 0xdf, 0x5b, 0x22, 0x49, 0x56, 0xa7, 0x98, 0xa4, 0xdf},
   325  					AssetID:             bc.AssetID{V0: 1},
   326  					Amount:              7,
   327  					AccountID:           "testAccount2",
   328  					Address:             "testAddress2",
   329  					ControlProgramIndex: 72,
   330  					Change:              false,
   331  				},
   332  			},
   333  		},
   334  	}
   335  
   336  	w := &Wallet{DB: testDB}
   337  	for i, c := range cases {
   338  		for s, p := range c.dbPrograms {
   339  			data, err := json.Marshal(p)
   340  			if err != nil {
   341  				t.Error(err)
   342  			}
   343  			key, err := hex.DecodeString(s)
   344  			if err != nil {
   345  				t.Error(err)
   346  			}
   347  			testDB.Set(key, data)
   348  		}
   349  		gotUtxos := w.filterAccountUtxo(c.input)
   350  		sort.Slice(gotUtxos[:], func(i, j int) bool {
   351  			return gotUtxos[i].Amount < gotUtxos[j].Amount
   352  		})
   353  
   354  		if !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
   355  			t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
   356  		}
   357  		for s := range c.dbPrograms {
   358  			key, err := hex.DecodeString(s)
   359  			if err != nil {
   360  				t.Error(err)
   361  			}
   362  			testDB.Delete(key)
   363  		}
   364  	}
   365  }
   366  
   367  func TestTxInToUtxos(t *testing.T) {
   368  	cases := []struct {
   369  		tx         *types.Tx
   370  		statusFail bool
   371  		wantUtxos  []*account.UTXO
   372  	}{
   373  		{
   374  			tx: types.NewTx(types.TxData{
   375  				Inputs: []*types.TxInput{
   376  					types.NewCoinbaseInput([]byte{0x51}),
   377  				},
   378  				Outputs: []*types.TxOutput{
   379  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, []byte{0x51}, nil),
   380  				},
   381  			}),
   382  			statusFail: false,
   383  			wantUtxos:  []*account.UTXO{},
   384  		},
   385  		{
   386  			tx: types.NewTx(types.TxData{
   387  				Inputs: []*types.TxInput{
   388  					types.NewIssuanceInput([]byte{}, 4125, []byte{0x51}, [][]byte{}, []byte{}),
   389  				},
   390  				Outputs: []*types.TxOutput{
   391  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 4125, []byte{0x51}, nil),
   392  				},
   393  			}),
   394  			statusFail: false,
   395  			wantUtxos:  []*account.UTXO{},
   396  		},
   397  		{
   398  			tx: types.NewTx(types.TxData{
   399  				Inputs: []*types.TxInput{
   400  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 1, 1, []byte{0x51}, nil),
   401  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 2}, bc.AssetID{V0: 1}, 3, 2, []byte{0x52}, nil),
   402  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 3}, *consensus.BTMAssetID, 5, 3, []byte{0x53}, nil),
   403  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 4}, *consensus.BTMAssetID, 7, 4, []byte{0x54}, nil),
   404  				},
   405  				Outputs: []*types.TxOutput{
   406  					types.NewOriginalTxOutput(bc.AssetID{V0: 1}, 4, []byte{0x51}, nil),
   407  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 12, []byte{0x53}, nil),
   408  				},
   409  			}),
   410  			statusFail: false,
   411  			wantUtxos: []*account.UTXO{
   412  				&account.UTXO{
   413  					OutputID:       testutil.MustDecodeHash("d7317174b78e6efdd060f19031b9b4d8dfdc8218b8fe7d86324f8c35b9cc572c"),
   414  					AssetID:        bc.AssetID{V0: 1},
   415  					Amount:         1,
   416  					ControlProgram: []byte{0x51},
   417  					SourceID:       bc.Hash{V0: 1},
   418  					SourcePos:      1,
   419  				},
   420  				&account.UTXO{
   421  					OutputID:       testutil.MustDecodeHash("2170b5a9ed124f4c2f691292dc44cc9a5b834c286a39738aa159c646cce14d95"),
   422  					AssetID:        bc.AssetID{V0: 1},
   423  					Amount:         3,
   424  					ControlProgram: []byte{0x52},
   425  					SourceID:       bc.Hash{V0: 2},
   426  					SourcePos:      2,
   427  				},
   428  				&account.UTXO{
   429  					OutputID:       testutil.MustDecodeHash("e07a0c076fcee0faccf6fc329875c3273120faaee87d273ff1cea5c64b2fb1e3"),
   430  					AssetID:        *consensus.BTMAssetID,
   431  					Amount:         5,
   432  					ControlProgram: []byte{0x53},
   433  					SourceID:       bc.Hash{V0: 3},
   434  					SourcePos:      3,
   435  				},
   436  				&account.UTXO{
   437  					OutputID:       testutil.MustDecodeHash("30fe2e3180356a847f152ce2dabab99ebe8df97ebbf100881d9591527f9fd738"),
   438  					AssetID:        *consensus.BTMAssetID,
   439  					Amount:         7,
   440  					ControlProgram: []byte{0x54},
   441  					SourceID:       bc.Hash{V0: 4},
   442  					SourcePos:      4,
   443  				},
   444  			},
   445  		},
   446  		{
   447  			tx: types.NewTx(types.TxData{
   448  				Inputs: []*types.TxInput{
   449  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 3}, *consensus.BTMAssetID, 5, 3, []byte{0x53}, nil),
   450  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 4}, *consensus.BTMAssetID, 7, 4, []byte{0x54}, nil),
   451  				},
   452  				Outputs: []*types.TxOutput{
   453  					types.NewOriginalTxOutput(bc.AssetID{V0: 1}, 4, []byte{0x51}, nil),
   454  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 12, []byte{0x53}, nil),
   455  				},
   456  			}),
   457  			statusFail: true,
   458  			wantUtxos: []*account.UTXO{
   459  				&account.UTXO{
   460  					OutputID:       testutil.MustDecodeHash("e07a0c076fcee0faccf6fc329875c3273120faaee87d273ff1cea5c64b2fb1e3"),
   461  					AssetID:        *consensus.BTMAssetID,
   462  					Amount:         5,
   463  					ControlProgram: []byte{0x53},
   464  					SourceID:       bc.Hash{V0: 3},
   465  					SourcePos:      3,
   466  				},
   467  				&account.UTXO{
   468  					OutputID:       testutil.MustDecodeHash("30fe2e3180356a847f152ce2dabab99ebe8df97ebbf100881d9591527f9fd738"),
   469  					AssetID:        *consensus.BTMAssetID,
   470  					Amount:         7,
   471  					ControlProgram: []byte{0x54},
   472  					SourceID:       bc.Hash{V0: 4},
   473  					SourcePos:      4,
   474  				},
   475  			},
   476  		},
   477  	}
   478  
   479  	for i, c := range cases {
   480  		if gotUtxos := txInToUtxos(c.tx); !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
   481  			for k, v := range gotUtxos {
   482  				data, _ := json.Marshal(v)
   483  				fmt.Println(k, string(data))
   484  			}
   485  			for k, v := range c.wantUtxos {
   486  				data, _ := json.Marshal(v)
   487  				fmt.Println(k, string(data))
   488  			}
   489  
   490  			t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
   491  		}
   492  	}
   493  }
   494  
   495  func TestTxOutToUtxos(t *testing.T) {
   496  	cases := []struct {
   497  		tx          *types.Tx
   498  		statusFail  bool
   499  		blockHeight uint64
   500  		wantUtxos   []*account.UTXO
   501  	}{
   502  		{
   503  			tx: types.NewTx(types.TxData{
   504  				Inputs: []*types.TxInput{
   505  					types.NewCoinbaseInput([]byte{0x51}),
   506  				},
   507  				Outputs: []*types.TxOutput{
   508  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, []byte{0x51}, nil),
   509  				},
   510  			}),
   511  			statusFail:  false,
   512  			blockHeight: 0,
   513  			wantUtxos: []*account.UTXO{
   514  				&account.UTXO{
   515  					OutputID:       testutil.MustDecodeHash("5ad31f023737c301190026c6e97da10715d5455d9bb32ace3104454faefd2bb6"),
   516  					AssetID:        *consensus.BTMAssetID,
   517  					Amount:         41250000000,
   518  					ControlProgram: []byte{0x51},
   519  					SourceID:       bc.NewHash([32]byte{0xb4, 0x7e, 0x94, 0x31, 0x88, 0xfe, 0xd3, 0xe9, 0xac, 0x99, 0x7c, 0xfc, 0x99, 0x6d, 0xd7, 0x4d, 0x04, 0x10, 0x77, 0xcb, 0x1c, 0xf8, 0x95, 0x14, 0x00, 0xe3, 0x42, 0x00, 0x8d, 0x05, 0xec, 0xdc}),
   520  					SourcePos:      0,
   521  					ValidHeight:    10,
   522  				},
   523  			},
   524  		},
   525  		{
   526  			tx: types.NewTx(types.TxData{
   527  				Inputs: []*types.TxInput{
   528  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 5, 1, []byte{0x51}, nil),
   529  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 2}, *consensus.BTMAssetID, 7, 1, []byte{0x51}, nil),
   530  				},
   531  				Outputs: []*types.TxOutput{
   532  					types.NewOriginalTxOutput(bc.AssetID{V0: 1}, 2, []byte{0x51}, nil),
   533  					types.NewOriginalTxOutput(bc.AssetID{V0: 1}, 3, []byte{0x52}, nil),
   534  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 2, []byte{0x53}, nil),
   535  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 5, []byte{0x54}, nil),
   536  				},
   537  			}),
   538  			statusFail:  false,
   539  			blockHeight: 0,
   540  			wantUtxos: []*account.UTXO{
   541  				&account.UTXO{
   542  					OutputID:       testutil.MustDecodeHash("55de32fa7e96499be625063bc4c7f66bbe5d7b60f233d3a3d7265a9501c77e96"),
   543  					AssetID:        bc.AssetID{V0: 1},
   544  					Amount:         2,
   545  					ControlProgram: []byte{0x51},
   546  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   547  					SourcePos:      0,
   548  				},
   549  				&account.UTXO{
   550  					OutputID:       testutil.MustDecodeHash("f256f40aa36df9cf954fdf82d5835815adfd21579289063525c64cff59bc6d96"),
   551  					AssetID:        bc.AssetID{V0: 1},
   552  					Amount:         3,
   553  					ControlProgram: []byte{0x52},
   554  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   555  					SourcePos:      1,
   556  				},
   557  				&account.UTXO{
   558  					OutputID:       testutil.MustDecodeHash("60da633ce48a8bf995a23c040c1b52d543e5818abd7fc0b0faa355cf54acbcca"),
   559  					AssetID:        *consensus.BTMAssetID,
   560  					Amount:         2,
   561  					ControlProgram: []byte{0x53},
   562  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   563  					SourcePos:      2,
   564  				},
   565  				&account.UTXO{
   566  					OutputID:       testutil.MustDecodeHash("550c883fd09fdccd4a5671c698d0874de9d713fa0b194f0ddffeae8ae79b57fc"),
   567  					AssetID:        *consensus.BTMAssetID,
   568  					Amount:         5,
   569  					ControlProgram: []byte{0x54},
   570  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   571  					SourcePos:      3,
   572  				},
   573  			},
   574  		},
   575  		{
   576  			tx: types.NewTx(types.TxData{
   577  				Inputs: []*types.TxInput{
   578  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 5, 1, []byte{0x51}, nil),
   579  					types.NewSpendInput([][]byte{}, bc.Hash{V0: 2}, *consensus.BTMAssetID, 7, 1, []byte{0x51}, nil),
   580  				},
   581  				Outputs: []*types.TxOutput{
   582  					types.NewOriginalTxOutput(bc.AssetID{V0: 1}, 2, []byte{0x51}, nil),
   583  					types.NewOriginalTxOutput(bc.AssetID{V0: 1}, 3, []byte{0x52}, nil),
   584  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 2, []byte{0x53}, nil),
   585  					types.NewOriginalTxOutput(*consensus.BTMAssetID, 5, []byte{0x54}, nil),
   586  				},
   587  			}),
   588  			statusFail:  true,
   589  			blockHeight: 0,
   590  			wantUtxos: []*account.UTXO{
   591  				&account.UTXO{
   592  					OutputID:       testutil.MustDecodeHash("55de32fa7e96499be625063bc4c7f66bbe5d7b60f233d3a3d7265a9501c77e96"),
   593  					AssetID:        bc.AssetID{V0: 1},
   594  					Amount:         2,
   595  					ControlProgram: []byte{0x51},
   596  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   597  					SourcePos:      0,
   598  				},
   599  				&account.UTXO{
   600  					OutputID:       testutil.MustDecodeHash("f256f40aa36df9cf954fdf82d5835815adfd21579289063525c64cff59bc6d96"),
   601  					AssetID:        bc.AssetID{V0: 1},
   602  					Amount:         3,
   603  					ControlProgram: []byte{0x52},
   604  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   605  					SourcePos:      1,
   606  				},
   607  				&account.UTXO{
   608  					OutputID:       testutil.MustDecodeHash("60da633ce48a8bf995a23c040c1b52d543e5818abd7fc0b0faa355cf54acbcca"),
   609  					AssetID:        *consensus.BTMAssetID,
   610  					Amount:         2,
   611  					ControlProgram: []byte{0x53},
   612  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   613  					SourcePos:      2,
   614  				},
   615  				&account.UTXO{
   616  					OutputID:       testutil.MustDecodeHash("550c883fd09fdccd4a5671c698d0874de9d713fa0b194f0ddffeae8ae79b57fc"),
   617  					AssetID:        *consensus.BTMAssetID,
   618  					Amount:         5,
   619  					ControlProgram: []byte{0x54},
   620  					SourceID:       testutil.MustDecodeHash("c0e16f80a168dad26194f9ba5a4244d9d52e08e4636aa50aa58a5b8d65e969d4"),
   621  					SourcePos:      3,
   622  				},
   623  			},
   624  		},
   625  	}
   626  
   627  	for i, c := range cases {
   628  		if gotUtxos := txOutToUtxos(c.tx, c.blockHeight); !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
   629  			for k, v := range gotUtxos {
   630  				data, _ := json.Marshal(v)
   631  				fmt.Println("got:", k, string(data))
   632  			}
   633  			for k, v := range c.wantUtxos {
   634  				data, _ := json.Marshal(v)
   635  				fmt.Println("want:", k, string(data))
   636  			}
   637  
   638  			t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
   639  		}
   640  	}
   641  }