github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/account/builder_test.go (about)

     1  package account
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/bytom/bytom/blockchain/signers"
     9  	"github.com/bytom/bytom/blockchain/txbuilder"
    10  	"github.com/bytom/bytom/consensus"
    11  	"github.com/bytom/bytom/crypto/ed25519/chainkd"
    12  	"github.com/bytom/bytom/protocol/bc"
    13  	"github.com/bytom/bytom/testutil"
    14  )
    15  
    16  func TestReserveBtmUtxoChain(t *testing.T) {
    17  	txbuilder.ChainTxUtxoNum = 3
    18  	utxos := []*UTXO{}
    19  	m := mockAccountManager(t)
    20  	for i := uint64(1); i <= 20; i++ {
    21  		utxo := &UTXO{
    22  			OutputID:  bc.Hash{V0: i},
    23  			AccountID: "TestAccountID",
    24  			AssetID:   *consensus.BTMAssetID,
    25  			Amount:    i * txbuilder.ChainTxMergeGas,
    26  		}
    27  		utxos = append(utxos, utxo)
    28  
    29  		data, err := json.Marshal(utxo)
    30  		if err != nil {
    31  			t.Fatal(err)
    32  		}
    33  
    34  		m.db.Set(StandardUTXOKey(utxo.OutputID), data)
    35  	}
    36  
    37  	cases := []struct {
    38  		amount uint64
    39  		want   []uint64
    40  		err    bool
    41  	}{
    42  		{
    43  			amount: 1 * txbuilder.ChainTxMergeGas,
    44  			want:   []uint64{1},
    45  		},
    46  		{
    47  			amount: 888888 * txbuilder.ChainTxMergeGas,
    48  			want:   []uint64{},
    49  			err:    true,
    50  		},
    51  		{
    52  			amount: 7 * txbuilder.ChainTxMergeGas,
    53  			want:   []uint64{4, 3, 1},
    54  		},
    55  		{
    56  			amount: 15 * txbuilder.ChainTxMergeGas,
    57  			want:   []uint64{5, 4, 3, 2, 1, 6},
    58  		},
    59  		{
    60  			amount: 163 * txbuilder.ChainTxMergeGas,
    61  			want:   []uint64{20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 2, 1, 3},
    62  		},
    63  	}
    64  
    65  	for i, c := range cases {
    66  		m.utxoKeeper.expireReservation(time.Unix(999999999, 0))
    67  		utxos, err := m.reserveBtmUtxoChain(&txbuilder.TemplateBuilder{}, "TestAccountID", c.amount, false)
    68  
    69  		if err != nil != c.err {
    70  			t.Fatalf("case %d got err %v want err = %v", i, err, c.err)
    71  		}
    72  
    73  		got := []uint64{}
    74  		for _, utxo := range utxos {
    75  			got = append(got, utxo.Amount/txbuilder.ChainTxMergeGas)
    76  		}
    77  
    78  		if !testutil.DeepEqual(got, c.want) {
    79  			t.Fatalf("case %d got %d want %d", i, got, c.want)
    80  		}
    81  	}
    82  
    83  }
    84  
    85  func TestBuildBtmTxChain(t *testing.T) {
    86  	txbuilder.ChainTxUtxoNum = 3
    87  	m := mockAccountManager(t)
    88  	cases := []struct {
    89  		inputUtxo  []uint64
    90  		wantInput  [][]uint64
    91  		wantOutput [][]uint64
    92  		wantUtxo   uint64
    93  	}{
    94  		{
    95  			inputUtxo:  []uint64{5},
    96  			wantInput:  [][]uint64{},
    97  			wantOutput: [][]uint64{},
    98  			wantUtxo:   5 * txbuilder.ChainTxMergeGas,
    99  		},
   100  		{
   101  			inputUtxo: []uint64{5, 4},
   102  			wantInput: [][]uint64{
   103  				[]uint64{5, 4},
   104  			},
   105  			wantOutput: [][]uint64{
   106  				[]uint64{8},
   107  			},
   108  			wantUtxo: 8 * txbuilder.ChainTxMergeGas,
   109  		},
   110  		{
   111  			inputUtxo: []uint64{5, 4, 1, 1},
   112  			wantInput: [][]uint64{
   113  				[]uint64{5, 4, 1},
   114  				[]uint64{1, 9},
   115  			},
   116  			wantOutput: [][]uint64{
   117  				[]uint64{9},
   118  				[]uint64{9},
   119  			},
   120  			wantUtxo: 9 * txbuilder.ChainTxMergeGas,
   121  		},
   122  		{
   123  			inputUtxo: []uint64{22, 123, 53, 234, 23, 4, 2423, 24, 23, 43, 34, 234, 234, 24},
   124  			wantInput: [][]uint64{
   125  				[]uint64{22, 123, 53},
   126  				[]uint64{234, 23, 4},
   127  				[]uint64{2423, 24, 23},
   128  				[]uint64{43, 34, 234},
   129  				[]uint64{234, 24, 197},
   130  				[]uint64{260, 2469, 310},
   131  				[]uint64{454, 3038},
   132  			},
   133  			wantOutput: [][]uint64{
   134  				[]uint64{197},
   135  				[]uint64{260},
   136  				[]uint64{2469},
   137  				[]uint64{310},
   138  				[]uint64{454},
   139  				[]uint64{3038},
   140  				[]uint64{3491},
   141  			},
   142  			wantUtxo: 3491 * txbuilder.ChainTxMergeGas,
   143  		},
   144  	}
   145  
   146  	acct, err := m.Create([]chainkd.XPub{testutil.TestXPub}, 1, "testAccount", signers.BIP0044)
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  
   151  	acp, err := m.CreateAddress(acct.ID, false)
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	for caseIndex, c := range cases {
   157  		utxos := []*UTXO{}
   158  		for _, amount := range c.inputUtxo {
   159  			utxos = append(utxos, &UTXO{
   160  				Amount:         amount * txbuilder.ChainTxMergeGas,
   161  				AssetID:        *consensus.BTMAssetID,
   162  				Address:        acp.Address,
   163  				ControlProgram: acp.ControlProgram,
   164  			})
   165  		}
   166  
   167  		tpls, gotUtxo, err := m.buildBtmTxChain(utxos, acct.Signer)
   168  		if err != nil {
   169  			t.Fatal(err)
   170  		}
   171  
   172  		for i, tpl := range tpls {
   173  			gotInput := []uint64{}
   174  			for _, input := range tpl.Transaction.Inputs {
   175  				gotInput = append(gotInput, input.Amount()/txbuilder.ChainTxMergeGas)
   176  			}
   177  
   178  			gotOutput := []uint64{}
   179  			for _, output := range tpl.Transaction.Outputs {
   180  				gotOutput = append(gotOutput, output.Amount/txbuilder.ChainTxMergeGas)
   181  			}
   182  
   183  			if !testutil.DeepEqual(c.wantInput[i], gotInput) {
   184  				t.Fatalf("case %d tx %d input got %d want %d", caseIndex, i, gotInput, c.wantInput[i])
   185  			}
   186  			if !testutil.DeepEqual(c.wantOutput[i], gotOutput) {
   187  				t.Fatalf("case %d tx %d output got %d want %d", caseIndex, i, gotOutput, c.wantOutput[i])
   188  			}
   189  		}
   190  
   191  		if c.wantUtxo != gotUtxo.Amount {
   192  			t.Fatalf("case %d got utxo=%d want utxo=%d", caseIndex, gotUtxo.Amount, c.wantUtxo)
   193  		}
   194  	}
   195  
   196  }
   197  
   198  func TestMergeSpendAction(t *testing.T) {
   199  	testBTM := &bc.AssetID{}
   200  	if err := testBTM.UnmarshalText([]byte("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); err != nil {
   201  		t.Fatal(err)
   202  	}
   203  
   204  	testAssetID1 := &bc.AssetID{}
   205  	if err := testAssetID1.UnmarshalText([]byte("50ec80b6bc48073f6aa8fa045131a71213c33f3681203b15ddc2e4b81f1f4730")); err != nil {
   206  		t.Fatal(err)
   207  	}
   208  
   209  	testAssetID2 := &bc.AssetID{}
   210  	if err := testAssetID2.UnmarshalText([]byte("43c6946d092b2959c1a82e90b282c68fca63e66de289048f6acd6cea9383c79c")); err != nil {
   211  		t.Fatal(err)
   212  	}
   213  
   214  	cases := []struct {
   215  		testActions     []txbuilder.Action
   216  		wantActions     []txbuilder.Action
   217  		testActionCount int
   218  		wantActionCount int
   219  	}{
   220  		{
   221  			testActions: []txbuilder.Action{
   222  				txbuilder.Action(&spendAction{
   223  					AssetAmount: bc.AssetAmount{
   224  						AssetId: testBTM,
   225  						Amount:  100,
   226  					},
   227  					AccountID: "test_account",
   228  				}),
   229  				txbuilder.Action(&spendAction{
   230  					AssetAmount: bc.AssetAmount{
   231  						AssetId: testBTM,
   232  						Amount:  200,
   233  					},
   234  					AccountID: "test_account",
   235  				}),
   236  				txbuilder.Action(&spendAction{
   237  					AssetAmount: bc.AssetAmount{
   238  						AssetId: testBTM,
   239  						Amount:  300,
   240  					},
   241  					AccountID: "test_account",
   242  				}),
   243  				txbuilder.Action(&spendAction{
   244  					AssetAmount: bc.AssetAmount{
   245  						AssetId: testAssetID1,
   246  						Amount:  300,
   247  					},
   248  					AccountID: "test_account",
   249  				}),
   250  			},
   251  			wantActions: []txbuilder.Action{
   252  				txbuilder.Action(&spendAction{
   253  					AssetAmount: bc.AssetAmount{
   254  						AssetId: testBTM,
   255  						Amount:  600,
   256  					},
   257  					AccountID: "test_account",
   258  				}),
   259  				txbuilder.Action(&spendAction{
   260  					AssetAmount: bc.AssetAmount{
   261  						AssetId: testAssetID1,
   262  						Amount:  300,
   263  					},
   264  					AccountID: "test_account",
   265  				}),
   266  			},
   267  			testActionCount: 4,
   268  			wantActionCount: 2,
   269  		},
   270  		{
   271  			testActions: []txbuilder.Action{
   272  				txbuilder.Action(&spendAction{
   273  					AssetAmount: bc.AssetAmount{
   274  						AssetId: testBTM,
   275  						Amount:  100,
   276  					},
   277  					AccountID: "test_account",
   278  				}),
   279  				txbuilder.Action(&spendAction{
   280  					AssetAmount: bc.AssetAmount{
   281  						AssetId: testAssetID1,
   282  						Amount:  200,
   283  					},
   284  					AccountID: "test_account",
   285  				}),
   286  				txbuilder.Action(&spendAction{
   287  					AssetAmount: bc.AssetAmount{
   288  						AssetId: testBTM,
   289  						Amount:  500,
   290  					},
   291  					AccountID: "test_account",
   292  				}),
   293  				txbuilder.Action(&spendAction{
   294  					AssetAmount: bc.AssetAmount{
   295  						AssetId: testAssetID1,
   296  						Amount:  300,
   297  					},
   298  					AccountID: "test_account",
   299  				}),
   300  			},
   301  			wantActions: []txbuilder.Action{
   302  				txbuilder.Action(&spendAction{
   303  					AssetAmount: bc.AssetAmount{
   304  						AssetId: testBTM,
   305  						Amount:  600,
   306  					},
   307  					AccountID: "test_account",
   308  				}),
   309  				txbuilder.Action(&spendAction{
   310  					AssetAmount: bc.AssetAmount{
   311  						AssetId: testAssetID1,
   312  						Amount:  500,
   313  					},
   314  					AccountID: "test_account",
   315  				}),
   316  			},
   317  			testActionCount: 4,
   318  			wantActionCount: 2,
   319  		},
   320  		{
   321  			testActions: []txbuilder.Action{
   322  				txbuilder.Action(&spendAction{
   323  					AssetAmount: bc.AssetAmount{
   324  						AssetId: testBTM,
   325  						Amount:  100,
   326  					},
   327  					AccountID: "test_account",
   328  				}),
   329  				txbuilder.Action(&spendAction{
   330  					AssetAmount: bc.AssetAmount{
   331  						AssetId: testAssetID1,
   332  						Amount:  200,
   333  					},
   334  					AccountID: "test_account",
   335  				}),
   336  				txbuilder.Action(&spendAction{
   337  					AssetAmount: bc.AssetAmount{
   338  						AssetId: testAssetID2,
   339  						Amount:  300,
   340  					},
   341  					AccountID: "test_account",
   342  				}),
   343  				txbuilder.Action(&spendAction{
   344  					AssetAmount: bc.AssetAmount{
   345  						AssetId: testAssetID1,
   346  						Amount:  300,
   347  					},
   348  					AccountID: "test_account",
   349  				}),
   350  				txbuilder.Action(&spendAction{
   351  					AssetAmount: bc.AssetAmount{
   352  						AssetId: testAssetID2,
   353  						Amount:  500,
   354  					},
   355  					AccountID: "test_account",
   356  				}),
   357  			},
   358  			wantActions: []txbuilder.Action{
   359  				txbuilder.Action(&spendAction{
   360  					AssetAmount: bc.AssetAmount{
   361  						AssetId: testBTM,
   362  						Amount:  100,
   363  					},
   364  					AccountID: "test_account",
   365  				}),
   366  				txbuilder.Action(&spendAction{
   367  					AssetAmount: bc.AssetAmount{
   368  						AssetId: testAssetID1,
   369  						Amount:  500,
   370  					},
   371  					AccountID: "test_account",
   372  				}),
   373  				txbuilder.Action(&spendAction{
   374  					AssetAmount: bc.AssetAmount{
   375  						AssetId: testAssetID2,
   376  						Amount:  800,
   377  					},
   378  					AccountID: "test_account",
   379  				}),
   380  			},
   381  			testActionCount: 5,
   382  			wantActionCount: 3,
   383  		},
   384  		{
   385  			testActions: []txbuilder.Action{
   386  				txbuilder.Action(&spendAction{
   387  					AssetAmount: bc.AssetAmount{
   388  						AssetId: testBTM,
   389  						Amount:  100,
   390  					},
   391  					AccountID: "test_account",
   392  				}),
   393  				txbuilder.Action(&spendAction{
   394  					AssetAmount: bc.AssetAmount{
   395  						AssetId: testBTM,
   396  						Amount:  200,
   397  					},
   398  					AccountID: "test_account1",
   399  				}),
   400  				txbuilder.Action(&spendAction{
   401  					AssetAmount: bc.AssetAmount{
   402  						AssetId: testBTM,
   403  						Amount:  500,
   404  					},
   405  					AccountID: "test_account",
   406  				}),
   407  				txbuilder.Action(&spendAction{
   408  					AssetAmount: bc.AssetAmount{
   409  						AssetId: testAssetID1,
   410  						Amount:  300,
   411  					},
   412  					AccountID: "test_account1",
   413  				}),
   414  			},
   415  			wantActions: []txbuilder.Action{
   416  				txbuilder.Action(&spendAction{
   417  					AssetAmount: bc.AssetAmount{
   418  						AssetId: testBTM,
   419  						Amount:  600,
   420  					},
   421  					AccountID: "test_account",
   422  				}),
   423  				txbuilder.Action(&spendAction{
   424  					AssetAmount: bc.AssetAmount{
   425  						AssetId: testBTM,
   426  						Amount:  200,
   427  					},
   428  					AccountID: "test_account1",
   429  				}),
   430  				txbuilder.Action(&spendAction{
   431  					AssetAmount: bc.AssetAmount{
   432  						AssetId: testAssetID1,
   433  						Amount:  300,
   434  					},
   435  					AccountID: "test_account1",
   436  				}),
   437  			},
   438  			testActionCount: 4,
   439  			wantActionCount: 3,
   440  		},
   441  		{
   442  			testActions: []txbuilder.Action{
   443  				txbuilder.Action(&spendUTXOAction{
   444  					OutputID: &bc.Hash{V0: 128},
   445  				}),
   446  				txbuilder.Action(&spendAction{
   447  					AssetAmount: bc.AssetAmount{
   448  						AssetId: testBTM,
   449  						Amount:  100,
   450  					},
   451  					AccountID: "test_account",
   452  				}),
   453  				txbuilder.Action(&spendAction{
   454  					AssetAmount: bc.AssetAmount{
   455  						AssetId: testAssetID1,
   456  						Amount:  200,
   457  					},
   458  					AccountID: "test_account1",
   459  				}),
   460  				txbuilder.Action(&spendUTXOAction{
   461  					OutputID: &bc.Hash{V0: 256},
   462  				}),
   463  				txbuilder.Action(&spendAction{
   464  					AssetAmount: bc.AssetAmount{
   465  						AssetId: testAssetID2,
   466  						Amount:  300,
   467  					},
   468  					AccountID: "test_account2",
   469  				}),
   470  			},
   471  			wantActions: []txbuilder.Action{
   472  				txbuilder.Action(&spendUTXOAction{
   473  					OutputID: &bc.Hash{V0: 128},
   474  				}),
   475  				txbuilder.Action(&spendAction{
   476  					AssetAmount: bc.AssetAmount{
   477  						AssetId: testBTM,
   478  						Amount:  100,
   479  					},
   480  					AccountID: "test_account",
   481  				}),
   482  				txbuilder.Action(&spendAction{
   483  					AssetAmount: bc.AssetAmount{
   484  						AssetId: testAssetID1,
   485  						Amount:  200,
   486  					},
   487  					AccountID: "test_account1",
   488  				}),
   489  				txbuilder.Action(&spendUTXOAction{
   490  					OutputID: &bc.Hash{V0: 256},
   491  				}),
   492  				txbuilder.Action(&spendAction{
   493  					AssetAmount: bc.AssetAmount{
   494  						AssetId: testAssetID2,
   495  						Amount:  300,
   496  					},
   497  					AccountID: "test_account2",
   498  				}),
   499  			},
   500  			testActionCount: 5,
   501  			wantActionCount: 5,
   502  		},
   503  	}
   504  
   505  	for _, c := range cases {
   506  		gotActions := MergeSpendAction(c.testActions)
   507  
   508  		gotMap := make(map[string]uint64)
   509  		wantMap := make(map[string]uint64)
   510  		for _, got := range gotActions {
   511  			switch got := got.(type) {
   512  			case *spendAction:
   513  				gotKey := got.AssetId.String() + got.AccountID
   514  				gotMap[gotKey] = got.Amount
   515  			default:
   516  				continue
   517  			}
   518  		}
   519  
   520  		for _, want := range c.wantActions {
   521  			switch want := want.(type) {
   522  			case *spendAction:
   523  				wantKey := want.AssetId.String() + want.AccountID
   524  				wantMap[wantKey] = want.Amount
   525  			default:
   526  				continue
   527  			}
   528  		}
   529  
   530  		for key := range gotMap {
   531  			if gotMap[key] != wantMap[key] {
   532  				t.Fatalf("gotMap[%s]=%v, wantMap[%s]=%v", key, gotMap[key], key, wantMap[key])
   533  			}
   534  		}
   535  
   536  		if len(gotActions) != c.wantActionCount {
   537  			t.Fatalf("number of gotActions=%d, wantActions=%d", len(gotActions), c.wantActionCount)
   538  		}
   539  	}
   540  }
   541  
   542  func TestCalcMergeGas(t *testing.T) {
   543  	txbuilder.ChainTxUtxoNum = 10
   544  	cases := []struct {
   545  		utxoNum int
   546  		gas     uint64
   547  	}{
   548  		{
   549  			utxoNum: 0,
   550  			gas:     0,
   551  		},
   552  		{
   553  			utxoNum: 1,
   554  			gas:     0,
   555  		},
   556  		{
   557  			utxoNum: 9,
   558  			gas:     txbuilder.ChainTxMergeGas,
   559  		},
   560  		{
   561  			utxoNum: 10,
   562  			gas:     txbuilder.ChainTxMergeGas,
   563  		},
   564  		{
   565  			utxoNum: 11,
   566  			gas:     txbuilder.ChainTxMergeGas * 2,
   567  		},
   568  		{
   569  			utxoNum: 20,
   570  			gas:     txbuilder.ChainTxMergeGas * 3,
   571  		},
   572  		{
   573  			utxoNum: 21,
   574  			gas:     txbuilder.ChainTxMergeGas * 3,
   575  		},
   576  		{
   577  			utxoNum: 74,
   578  			gas:     txbuilder.ChainTxMergeGas * 9,
   579  		},
   580  	}
   581  
   582  	for i, c := range cases {
   583  		gas := calcMergeGas(c.utxoNum)
   584  		if gas != c.gas {
   585  			t.Fatalf("case %d got %d want %d", i, gas, c.gas)
   586  		}
   587  	}
   588  }