|
7 | 7 | "crypto/ed25519"
|
8 | 8 | "fmt"
|
9 | 9 | "log"
|
| 10 | + "math/big" |
10 | 11 | "os/exec"
|
11 | 12 | "sort"
|
12 | 13 | "strings"
|
@@ -61,6 +62,8 @@ type Account struct {
|
61 | 62 | AccountID iotago.AccountID
|
62 | 63 | AccountAddress *iotago.AccountAddress
|
63 | 64 | BlockIssuerKey ed25519.PrivateKey
|
| 65 | + AccountOutput *iotago.AccountOutput |
| 66 | + OutputID iotago.OutputID |
64 | 67 | }
|
65 | 68 |
|
66 | 69 | type DockerTestFramework struct {
|
@@ -375,6 +378,8 @@ func (d *DockerTestFramework) CreateAccount(opts ...options.Option[builder.Accou
|
375 | 378 | AccountID: accountID,
|
376 | 379 | AccountAddress: accountAddress,
|
377 | 380 | BlockIssuerKey: accPrivateKey,
|
| 381 | + AccountOutput: accountOutput, |
| 382 | + OutputID: accOutputID, |
378 | 383 | }
|
379 | 384 | }
|
380 | 385 |
|
@@ -425,6 +430,135 @@ func (d *DockerTestFramework) DelegateToValidator(from *Account, validator *Node
|
425 | 430 | return delegationOutput.StartEpoch
|
426 | 431 | }
|
427 | 432 |
|
| 433 | +// AllotManaTo allots amount of mana from one account to another. |
| 434 | +func (d *DockerTestFramework) AllotManaTo(from *Account, to *Account, manaToAllot iotago.Mana) { |
| 435 | + // requesting faucet funds for allotment |
| 436 | + ctx := context.TODO() |
| 437 | + fundsAddr, privateKey := d.getAddress(iotago.AddressEd25519) |
| 438 | + fundsOutputID, fundsUTXOOutput := d.RequestFaucetFunds(ctx, fundsAddr) |
| 439 | + fundsAddrSigner := iotago.NewInMemoryAddressSigner(iotago.NewAddressKeysForEd25519Address(fundsAddr.(*iotago.Ed25519Address), privateKey)) |
| 440 | + |
| 441 | + clt := d.Node("V1").Client |
| 442 | + currentSlot := clt.LatestAPI().TimeProvider().SlotFromTime(time.Now()) |
| 443 | + apiForSlot := clt.APIForSlot(currentSlot) |
| 444 | + |
| 445 | + basicOutput, ok := fundsUTXOOutput.(*iotago.BasicOutput) |
| 446 | + require.True(d.Testing, ok) |
| 447 | + |
| 448 | + // Subtract stored mana from source outputs to fund Allotment. |
| 449 | + outputBuilder := builder.NewBasicOutputBuilderFromPrevious(basicOutput) |
| 450 | + actualAllottedMana := manaToAllot |
| 451 | + if manaToAllot >= basicOutput.StoredMana() { |
| 452 | + actualAllottedMana = basicOutput.StoredMana() |
| 453 | + outputBuilder.Mana(0) |
| 454 | + } else { |
| 455 | + outputBuilder.Mana(basicOutput.StoredMana() - manaToAllot) |
| 456 | + } |
| 457 | + |
| 458 | + issuerResp, err := clt.BlockIssuance(ctx) |
| 459 | + require.NoError(d.Testing, err) |
| 460 | + |
| 461 | + congestionResp, err := clt.Congestion(ctx, from.AccountAddress, lo.PanicOnErr(issuerResp.LatestCommitment.ID())) |
| 462 | + require.NoError(d.Testing, err) |
| 463 | + |
| 464 | + signedTx, err := builder.NewTransactionBuilder(apiForSlot). |
| 465 | + AddInput(&builder.TxInput{ |
| 466 | + UnlockTarget: fundsAddr, |
| 467 | + InputID: fundsOutputID, |
| 468 | + Input: fundsUTXOOutput, |
| 469 | + }). |
| 470 | + IncreaseAllotment(to.AccountID, actualAllottedMana). |
| 471 | + AddOutput(basicOutput). |
| 472 | + SetCreationSlot(currentSlot). |
| 473 | + AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: lo.Return1(issuerResp.LatestCommitment.ID())}). |
| 474 | + WithTransactionCapabilities(iotago.TransactionCapabilitiesBitMaskWithCapabilities(iotago.WithTransactionCanDoAnything())). |
| 475 | + Build(fundsAddrSigner) |
| 476 | + require.NoError(d.Testing, err) |
| 477 | + |
| 478 | + blkID := d.SubmitPayload(ctx, signedTx, wallet.NewEd25519Account(from.AccountID, from.BlockIssuerKey), congestionResp, issuerResp) |
| 479 | + |
| 480 | + d.AwaitTransactionPayloadAccepted(ctx, blkID) |
| 481 | +} |
| 482 | + |
| 483 | +func (d *DockerTestFramework) CreateNativeToken(from *Account) (updatedAccount *Account) { |
| 484 | + // requesting faucet funds for native token creation |
| 485 | + ctx := context.TODO() |
| 486 | + fundsAddr, privateKey := d.getAddress(iotago.AddressEd25519) |
| 487 | + fundsOutputID, fundsUTXOOutput := d.RequestFaucetFunds(ctx, fundsAddr) |
| 488 | + |
| 489 | + mintedAmount := fundsUTXOOutput.BaseTokenAmount() |
| 490 | + |
| 491 | + clt := d.Node("V1").Client |
| 492 | + currentSlot := clt.LatestAPI().TimeProvider().SlotFromTime(time.Now()) |
| 493 | + apiForSlot := clt.APIForSlot(currentSlot) |
| 494 | + |
| 495 | + // increase foundry counter |
| 496 | + accTransitionOutput := builder.NewAccountOutputBuilderFromPrevious(from.AccountOutput). |
| 497 | + FoundriesToGenerate(1).MustBuild() |
| 498 | + |
| 499 | + // build foundry output, consume all amount from the UTXO output |
| 500 | + foundryID, _ := iotago.FoundryIDFromAddressAndSerialNumberAndTokenScheme(from.AccountAddress, accTransitionOutput.FoundryCounter, iotago.TokenSchemeSimple) |
| 501 | + tokenScheme := &iotago.SimpleTokenScheme{ |
| 502 | + MintedTokens: big.NewInt(int64(mintedAmount)), |
| 503 | + MaximumSupply: big.NewInt(int64(mintedAmount)), |
| 504 | + MeltedTokens: big.NewInt(0), |
| 505 | + } |
| 506 | + |
| 507 | + foundryOutput := builder.NewFoundryOutputBuilder(from.AccountAddress, tokenScheme, mintedAmount). |
| 508 | + NativeToken(&iotago.NativeTokenFeature{ |
| 509 | + ID: foundryID, |
| 510 | + Amount: big.NewInt(int64(mintedAmount)), |
| 511 | + }). |
| 512 | + SerialNumber(accTransitionOutput.FoundryCounter).MustBuild() |
| 513 | + |
| 514 | + // prepare transaction |
| 515 | + issuerResp, err := clt.BlockIssuance(ctx) |
| 516 | + require.NoError(d.Testing, err) |
| 517 | + |
| 518 | + congestionResp, err := clt.Congestion(ctx, from.AccountAddress, lo.PanicOnErr(issuerResp.LatestCommitment.ID())) |
| 519 | + require.NoError(d.Testing, err) |
| 520 | + |
| 521 | + signer := iotago.NewInMemoryAddressSigner(iotago.NewAddressKeysForEd25519Address(fundsAddr.(*iotago.Ed25519Address), privateKey), |
| 522 | + iotago.NewAddressKeysForEd25519Address(from.AccountOutput.UnlockConditionSet().Address().Address.(*iotago.Ed25519Address), from.BlockIssuerKey)) |
| 523 | + |
| 524 | + signedTx, err := builder.NewTransactionBuilder(apiForSlot). |
| 525 | + AddInput(&builder.TxInput{ |
| 526 | + UnlockTarget: fundsAddr, |
| 527 | + InputID: fundsOutputID, |
| 528 | + Input: fundsUTXOOutput, |
| 529 | + }). |
| 530 | + AddInput(&builder.TxInput{ |
| 531 | + UnlockTarget: from.AccountOutput.UnlockConditionSet().Address().Address, |
| 532 | + InputID: from.OutputID, |
| 533 | + Input: from.AccountOutput, |
| 534 | + }). |
| 535 | + AddOutput(accTransitionOutput). |
| 536 | + AddOutput(foundryOutput). |
| 537 | + SetCreationSlot(currentSlot). |
| 538 | + AddBlockIssuanceCreditInput(&iotago.BlockIssuanceCreditInput{AccountID: from.AccountID}). |
| 539 | + AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: lo.Return1(issuerResp.LatestCommitment.ID())}). |
| 540 | + WithTransactionCapabilities(iotago.TransactionCapabilitiesBitMaskWithCapabilities(iotago.WithTransactionCanDoAnything())). |
| 541 | + AllotAllMana(currentSlot, from.AccountID). |
| 542 | + Build(signer) |
| 543 | + require.NoError(d.Testing, err) |
| 544 | + |
| 545 | + blkID := d.SubmitPayload(ctx, signedTx, wallet.NewEd25519Account(from.AccountID, from.BlockIssuerKey), congestionResp, issuerResp) |
| 546 | + |
| 547 | + updatedAccount = &Account{ |
| 548 | + AccountID: from.AccountID, |
| 549 | + AccountAddress: from.AccountAddress, |
| 550 | + BlockIssuerKey: from.BlockIssuerKey, |
| 551 | + AccountOutput: accTransitionOutput, |
| 552 | + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 0), |
| 553 | + } |
| 554 | + |
| 555 | + d.AwaitTransactionPayloadAccepted(ctx, blkID) |
| 556 | + d.AssertIndexerAccount(updatedAccount) |
| 557 | + d.AssertIndexerFoundry(foundryID) |
| 558 | + |
| 559 | + return updatedAccount |
| 560 | +} |
| 561 | + |
428 | 562 | func (d *DockerTestFramework) CheckAccountStatus(ctx context.Context, blkID iotago.BlockID, txID iotago.TransactionID, creationOutputID iotago.OutputID, accountAddress *iotago.AccountAddress, checkIndexer ...bool) {
|
429 | 563 | // request by blockID if provided, otherwise use txID
|
430 | 564 | // we take the slot from the blockID in case the tx is created earlier than the block.
|
@@ -469,6 +603,43 @@ func (d *DockerTestFramework) RequestFaucetFunds(ctx context.Context, receiveAdd
|
469 | 603 | return outputID, output
|
470 | 604 | }
|
471 | 605 |
|
| 606 | +func (d *DockerTestFramework) AssertIndexerAccount(account *Account) { |
| 607 | + d.Eventually(func() error { |
| 608 | + ctx := context.TODO() |
| 609 | + indexerClt, err := d.Node("V1").Client.Indexer(ctx) |
| 610 | + if err != nil { |
| 611 | + return err |
| 612 | + } |
| 613 | + |
| 614 | + outputID, output, _, err := indexerClt.Account(ctx, account.AccountAddress) |
| 615 | + if err != nil { |
| 616 | + return err |
| 617 | + } |
| 618 | + |
| 619 | + require.EqualValues(d.Testing, account.OutputID, outputID) |
| 620 | + require.EqualValues(d.Testing, account.AccountOutput, output) |
| 621 | + |
| 622 | + return nil |
| 623 | + }) |
| 624 | +} |
| 625 | + |
| 626 | +func (d *DockerTestFramework) AssertIndexerFoundry(foundryID iotago.FoundryID) { |
| 627 | + d.Eventually(func() error { |
| 628 | + ctx := context.TODO() |
| 629 | + indexerClt, err := d.Node("V1").Client.Indexer(ctx) |
| 630 | + if err != nil { |
| 631 | + return err |
| 632 | + } |
| 633 | + |
| 634 | + _, _, _, err = indexerClt.Foundry(ctx, foundryID) |
| 635 | + if err != nil { |
| 636 | + return err |
| 637 | + } |
| 638 | + |
| 639 | + return nil |
| 640 | + }) |
| 641 | +} |
| 642 | + |
472 | 643 | func (d *DockerTestFramework) AssertValidatorExists(accountAddr *iotago.AccountAddress) {
|
473 | 644 | d.Eventually(func() error {
|
474 | 645 | for _, node := range d.nodes {
|
|
0 commit comments