github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/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 }