Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implicit account creation #344

Merged
merged 31 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
64f5d33
add implicit account to accounts manager and check for their signatur…
cyberphysic4l Sep 15, 2023
b612ea0
fix commitment filter bug
cyberphysic4l Sep 15, 2023
1a176a5
track consumed implicit accounts
cyberphysic4l Sep 18, 2023
d564fbd
test implicit account creation
cyberphysic4l Sep 19, 2023
f64fb8b
fix commitment filter
cyberphysic4l Sep 19, 2023
03ecb8b
start accounts test additions
cyberphysic4l Sep 20, 2023
27ea6be
Fix transaction framework for implicit accounts
muXxer Sep 20, 2023
74473aa
fixes for account test
cyberphysic4l Sep 20, 2023
413298a
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 22, 2023
d976f5f
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 25, 2023
ec314bf
align with iota.go
cyberphysic4l Sep 26, 2023
dd85e27
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 26, 2023
192c415
fix merge errors
cyberphysic4l Sep 27, 2023
b15799e
use block issuer key constructor
cyberphysic4l Sep 27, 2023
2c642e8
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 27, 2023
08d48e2
update to implicit account block issuer key type to pubkeyhash in iotago
cyberphysic4l Sep 27, 2023
9f2a0d4
Document filter rules and increase resiliency
PhilippGackstatter Sep 27, 2023
c886ac1
Add comment on type assertion
PhilippGackstatter Sep 27, 2023
f7bffc7
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 27, 2023
d22c94c
go mod tidy
cyberphysic4l Sep 27, 2023
524a367
fix accounts test
cyberphysic4l Sep 27, 2023
fb6af98
remove print from accounts test
cyberphysic4l Sep 27, 2023
0242a84
go mod tidy
cyberphysic4l Sep 27, 2023
a27c9bc
state index implicit account = 0
cyberphysic4l Sep 28, 2023
7e08eb5
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 28, 2023
a94accc
go mod tidy
cyberphysic4l Sep 28, 2023
88eca77
merge errors
cyberphysic4l Sep 28, 2023
ded2b4f
Merge branch 'develop' into feat/implicit-accounts
cyberphysic4l Sep 28, 2023
51eccbc
use new account builder
cyberphysic4l Sep 28, 2023
6dab42a
Remove stray fmt printf
PhilippGackstatter Sep 28, 2023
e51ea10
Remove fmt import
PhilippGackstatter Sep 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ require (
github.com/iotaledger/hive.go/stringify v0.0.0-20230926122307-d671b36a4a65
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20230925153303-c7fbe63a0ab4
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20230925152824-4bfa09b8c132
github.com/iotaledger/iota.go/v4 v4.0.0-20230926171759-340cfc7c2478
github.com/iotaledger/iota.go/v4 v4.0.0-20230927105604-ea84bcb2c9d4
github.com/labstack/echo/v4 v4.11.1
github.com/labstack/gommon v0.4.0
github.com/libp2p/go-libp2p v0.30.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ github.com/iotaledger/inx-app v1.0.0-rc.3.0.20230925153303-c7fbe63a0ab4 h1:pbw/e
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20230925153303-c7fbe63a0ab4/go.mod h1:KbmEuxbhax3fyVrxF4RjBD1/MWLFxHLNDFBnDYUzok4=
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20230925152824-4bfa09b8c132 h1:YHvgNY3/TRx84UxqizkFe7vVUxAMQB2DOuEL8wjHxpg=
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20230925152824-4bfa09b8c132/go.mod h1:DIFr5lt73HLIyn/Lg2jtzfakwhIT0mMZjMFFji3GXeI=
github.com/iotaledger/iota.go/v4 v4.0.0-20230926171759-340cfc7c2478 h1:sAjTMFvLwABCiYSh4JJehpwY5Tz20BgzGtgVbkwpyf4=
github.com/iotaledger/iota.go/v4 v4.0.0-20230926171759-340cfc7c2478/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo=
github.com/iotaledger/iota.go/v4 v4.0.0-20230927105604-ea84bcb2c9d4 h1:ZKaBVOWDzsM+Iq46l73VYp+wfhp/BytplvCsDQbkgTA=
github.com/iotaledger/iota.go/v4 v4.0.0-20230927105604-ea84bcb2c9d4/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo=
github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY=
github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM=
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
Expand Down
2 changes: 1 addition & 1 deletion pkg/model/account_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func readBlockIssuerKey(reader io.ReadSeeker) (iotago.BlockIssuerKey, int, error
// return nil, bytesConsumed, ierrors.Errorf("unable to read ed25519 address key in account diff: %w", err)
// }
//
// return iotago.Ed25519AddressBlockIssuerKeyFromAddress(ed25519Address), bytesConsumed, nil
// return iotago.Ed25519PublicKeyHashBlockIssuerKeyFromAddress(ed25519Address), bytesConsumed, nil

default:
return nil, bytesConsumed, ierrors.Errorf("unsupported block issuer key type %d in account diff", blockIssuerKeyType)
Expand Down
8 changes: 8 additions & 0 deletions pkg/protocol/engine/accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ func (a *AccountData) readFromReadSeeker(reader io.ReadSeeker) (int, error) {
}
bytesConsumed += bytesRead
a.BlockIssuerKeys.Add(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519PublicKey))
case iotago.BlockIssuerKeyEd25519Address:
var implicitAccountCreationAddress iotago.ImplicitAccountCreationAddress
bytesRead, err = io.ReadFull(reader, implicitAccountCreationAddress[:])
if err != nil {
return bytesConsumed, ierrors.Wrapf(err, "unable to read address %d for accountID %s", i, a.ID)
}
bytesConsumed += bytesRead
a.BlockIssuerKeys.Add(iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(&implicitAccountCreationAddress))
default:
return bytesConsumed, ierrors.Wrapf(err, "unsupported block issuer key type %d for accountID %s at offset %d", blockIssuerKeyType, a.ID, i)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/protocol/engine/accounts/mana/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (m *Manager) GetManaOnAccount(accountID iotago.AccountID, currentSlot iotag
if err != nil {
return 0, ierrors.Errorf("failed to resolve AccountOutput for %s in slot %s: %w", accountID, currentSlot, err)
}
minDeposit := m.apiProvider.CurrentAPI().ProtocolParameters().RentStructure().MinDeposit(output.Output())
minDeposit := m.apiProvider.CurrentAPI().RentStructure().MinDeposit(output.Output())
if output.BaseTokenAmount() <= minDeposit {
mana = accounts.NewMana(output.StoredMana(), 0, output.SlotCreated())
} else {
Expand Down Expand Up @@ -92,7 +92,7 @@ func (m *Manager) ApplyDiff(slotIndex iotago.SlotIndex, destroyedAccounts ds.Set
for accountID, output := range accountOutputs {
mana, exists := m.manaVectorCache.Get(accountID)
if exists {
minDeposit := m.apiProvider.CurrentAPI().ProtocolParameters().RentStructure().MinDeposit(output.Output())
minDeposit := m.apiProvider.CurrentAPI().RentStructure().MinDeposit(output.Output())
if output.BaseTokenAmount() <= minDeposit {
mana.Update(output.StoredMana(), 0, slotIndex)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,22 @@ func (c *CommitmentFilter) evaluateBlock(block *blocks.Block) {
switch signature := block.ProtocolBlock().Signature.(type) {
case *iotago.Ed25519Signature:
if !accountData.BlockIssuerKeys.Has(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(signature.PublicKey)) {
c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{
Block: block,
Reason: ierrors.Wrapf(ErrInvalidSignature, "block issuer account %s does not have public key %s in slot %d", block.ProtocolBlock().IssuerID, signature.PublicKey, block.ProtocolBlock().SlotCommitmentID.Index()),
})

return
// If the block issuer does not have the public key in the slot commitment, check if it is an implicit account with the corresponding address.
// There must be at least one block issuer key on any account, so extracting index 0 is fine.
// For implicit accounts there is exactly one key, so we do not have to check any other indices.
blockIssuerKey := accountData.BlockIssuerKeys[0]
// Implicit Accounts can only have Block Issuer Keys of type Ed25519PublicKeyHashBlockIssuerKey.
bikPubKeyHash, isBikPubKeyHash := blockIssuerKey.(*iotago.Ed25519PublicKeyHashBlockIssuerKey)

// Filter the block if it's not a Block Issuer Key from an Implicit Account or if the Pub Key Hashes do not match.
if !isBikPubKeyHash || bikPubKeyHash.PublicKeyHash != iotago.Ed25519PublicKeyHashBlockIssuerKeyFromPublicKey(signature.PublicKey[:]).PublicKeyHash {
c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{
Block: block,
Reason: ierrors.Wrapf(ErrInvalidSignature, "block issuer account %s does not have block issuer key corresponding to public key %s in slot %d", block.ProtocolBlock().IssuerID, signature.PublicKey, block.ProtocolBlock().SlotCommitmentID.Index()),
})

return
}
}
signingMessage, err := block.ProtocolBlock().SigningMessage()
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func TestCommitmentFilter_NoAccount(t *testing.T) {

tf.CommitmentFilter.events.BlockFiltered.Hook(func(event *commitmentfilter.BlockFilteredEvent) {
require.NotEqual(t, "withAccount", event.Block.ID().Alias())
require.NotEqual(t, "withImplicitAccount", event.Block.ID().Alias())
})

keyPair := ed25519.GenerateKeyPair()
Expand All @@ -153,7 +154,7 @@ func TestCommitmentFilter_NoAccount(t *testing.T) {
addr := iotago.Ed25519AddressFromPubKey(keyPair.PublicKey[:])
accountID := iotago.AccountID(addr[:])

// register the account in the proxy account manager
// register the accounts in the proxy account manager
tf.AddAccountData(
accountID,
accounts.NewAccountData(
Expand All @@ -162,13 +163,26 @@ func TestCommitmentFilter_NoAccount(t *testing.T) {
accounts.WithBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(keyPair.PublicKey)),
),
)
keyPairImplicitAccount := ed25519.GenerateKeyPair()
implicitAddress := iotago.ImplicitAccountCreationAddressFromPubKey(keyPairImplicitAccount.PublicKey[:])
implicitAccountID := iotago.AccountID(implicitAddress[:])
tf.AddAccountData(
implicitAccountID,
accounts.NewAccountData(
implicitAccountID,
accounts.WithExpirySlot(iotago.MaxSlotIndex),
accounts.WithBlockIssuerKeys(iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(implicitAddress)),
),
)

tf.AddRMCData(currentSlot-currentAPI.ProtocolParameters().MaxCommittableAge(), iotago.Mana(0))

tf.IssueSignedBlockAtSlot("withAccount", currentSlot, commitmentID, keyPair)

otherKeyPair := ed25519.GenerateKeyPair()
tf.IssueSignedBlockAtSlot("noAccount", currentSlot, commitmentID, otherKeyPair)
keyPairNoAccount := ed25519.GenerateKeyPair()
tf.IssueSignedBlockAtSlot("noAccount", currentSlot, commitmentID, keyPairNoAccount)

tf.IssueSignedBlockAtSlot("withImplicitAccount", currentSlot, commitmentID, keyPairImplicitAccount)
}

func TestCommitmentFilter_BurnedMana(t *testing.T) {
Expand Down
55 changes: 45 additions & 10 deletions pkg/protocol/engine/ledger/ledger/ledger.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ledger

import (
"fmt"
"io"

"github.com/iotaledger/hive.go/core/safemath"
Expand Down Expand Up @@ -382,11 +383,19 @@ func (l *Ledger) prepareAccountDiffs(accountDiffs map[iotago.AccountID]*model.Ac
// case 1.
continue
}
accountDiff.NewOutputID = createdOutput.OutputID()
accountDiff.PreviousOutputID = consumedOutput.OutputID()

// case 2.
// created output can never be an implicit account as these can not be transitioned, but consumed output can be.
switch consumedOutput.Output().Type() {
case iotago.OutputAccount:
accountDiff.PreviousExpirySlot = consumedOutput.Output().FeatureSet().BlockIssuer().ExpirySlot
case iotago.OutputBasic:
accountDiff.PreviousExpirySlot = iotago.MaxSlotIndex
}

accountDiff.PreviousOutputID = consumedOutput.OutputID()
accountDiff.NewOutputID = createdOutput.OutputID()
accountDiff.NewExpirySlot = createdOutput.Output().FeatureSet().BlockIssuer().ExpirySlot
accountDiff.PreviousExpirySlot = consumedOutput.Output().FeatureSet().BlockIssuer().ExpirySlot

oldPubKeysSet := accountData.BlockIssuerKeys
newPubKeysSet := iotago.NewBlockIssuerKeys()
Expand Down Expand Up @@ -438,15 +447,26 @@ func (l *Ledger) prepareAccountDiffs(accountDiffs map[iotago.AccountID]*model.Ac
// have some values from the allotment, so no need to set them explicitly.
accountDiff.NewOutputID = createdOutput.OutputID()
accountDiff.PreviousOutputID = iotago.EmptyOutputID
accountDiff.NewExpirySlot = createdOutput.Output().FeatureSet().BlockIssuer().ExpirySlot
accountDiff.PreviousExpirySlot = 0
accountDiff.BlockIssuerKeysAdded = createdOutput.Output().FeatureSet().BlockIssuer().BlockIssuerKeys

if stakingFeature := createdOutput.Output().FeatureSet().Staking(); stakingFeature != nil {
accountDiff.ValidatorStakeChange = int64(stakingFeature.StakedAmount)
accountDiff.StakeEndEpochChange = int64(stakingFeature.EndEpoch)
accountDiff.FixedCostChange = int64(stakingFeature.FixedCost)
switch createdOutput.Output().Type() {
// for account outputs, get block issuer keys from the block issuer feature, and check for staking info.
case iotago.OutputAccount:
accountDiff.BlockIssuerKeysAdded = createdOutput.Output().FeatureSet().BlockIssuer().BlockIssuerKeys
accountDiff.NewExpirySlot = createdOutput.Output().FeatureSet().BlockIssuer().ExpirySlot
if stakingFeature := createdOutput.Output().FeatureSet().Staking(); stakingFeature != nil {
accountDiff.ValidatorStakeChange = int64(stakingFeature.StakedAmount)
accountDiff.StakeEndEpochChange = int64(stakingFeature.EndEpoch)
accountDiff.FixedCostChange = int64(stakingFeature.FixedCost)
}
// for basic outputs (implicit accounts), get block issuer keys from the address in the unlock conditions.
case iotago.OutputBasic:
// If the Output is a Basic Output it can only be here if the address is an ImplicitAccountCreationAddress.
address, _ := createdOutput.Output().UnlockConditionSet().Address().Address.(*iotago.ImplicitAccountCreationAddress)
PhilippGackstatter marked this conversation as resolved.
Show resolved Hide resolved
accountDiff.BlockIssuerKeysAdded = iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(address))
accountDiff.NewExpirySlot = iotago.MaxSlotIndex
}
fmt.Printf("account diff for %s: %+v\n", createdAccountID, accountDiff)
PhilippGackstatter marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -486,6 +506,14 @@ func (l *Ledger) processCreatedAndConsumedAccountOutputs(stateDiff mempool.State
// the delegation output was created => determine later if we need to add the stake to the validator
delegation, _ := createdOutput.Output().(*iotago.DelegationOutput)
createdAccountDelegation[delegation.DelegationID] = delegation

case iotago.OutputBasic:
// if a basic output is sent to an implicit account creation address, we need to create the account
if createdOutput.Output().UnlockConditionSet().Address().Address.Type() == iotago.AddressImplicitAccountCreation {
accountID := iotago.AccountIDFromOutputID(outputID)
l.events.AccountCreated.Trigger(accountID)
createdAccounts[accountID] = createdOutput
}
}

return true
Expand All @@ -506,7 +534,7 @@ func (l *Ledger) processCreatedAndConsumedAccountOutputs(stateDiff mempool.State
switch spentOutput.OutputType() {
case iotago.OutputAccount:
consumedAccount, _ := spentOutput.Output().(*iotago.AccountOutput)
// if we transition / destroy an account that doesn't have a block issuer feature or staking, we don't need to track the changes.
// if we transition / destroy an account output that doesn't have a block issuer feature or staking, we don't need to track the changes.
if consumedAccount.FeatureSet().BlockIssuer() == nil && consumedAccount.FeatureSet().Staking() == nil {
return true
}
Expand All @@ -529,6 +557,13 @@ func (l *Ledger) processCreatedAndConsumedAccountOutputs(stateDiff mempool.State
accountDiff := getAccountDiff(accountDiffs, delegationOutput.ValidatorAddress.AccountID())
accountDiff.DelegationStakeChange -= int64(delegationOutput.DelegatedAmount)
}

case iotago.OutputBasic:
// if a basic output (implicit account) is consumed, get the accountID as hash of the output ID.
if spentOutput.Output().UnlockConditionSet().Address().Address.Type() == iotago.AddressImplicitAccountCreation {
accountID := iotago.AccountIDFromOutputID(outputID)
consumedAccounts[accountID] = spentOutput
}
}

return true
Expand Down
4 changes: 2 additions & 2 deletions pkg/protocol/snapshotcreator/snapshotcreator.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func createGenesisOutput(genesisTokenAmount iotago.BaseToken, genesisSeed []byte
genesisWallet := mock.NewHDWallet("genesis", genesisSeed, 0)
output := createOutput(genesisWallet.Address(), genesisTokenAmount)

if _, err := engineInstance.CurrentAPI().ProtocolParameters().RentStructure().CoversMinDeposit(output, genesisTokenAmount); err != nil {
if _, err := engineInstance.CurrentAPI().RentStructure().CoversMinDeposit(output, genesisTokenAmount); err != nil {
return ierrors.Wrap(err, "min rent not covered by Genesis output with index 0")
}

Expand All @@ -153,7 +153,7 @@ func createGenesisAccounts(accounts []AccountDetails, engineInstance *engine.Eng
for idx, genesisAccount := range accounts {
output := createAccount(genesisAccount.AccountID, genesisAccount.Address, genesisAccount.Amount, genesisAccount.Mana, genesisAccount.IssuerKey, genesisAccount.ExpirySlot, genesisAccount.StakedAmount, genesisAccount.StakingEpochEnd, genesisAccount.FixedCost)

if _, err := engineInstance.CurrentAPI().ProtocolParameters().RentStructure().CoversMinDeposit(output, genesisAccount.Amount); err != nil {
if _, err := engineInstance.CurrentAPI().RentStructure().CoversMinDeposit(output, genesisAccount.Amount); err != nil {
return ierrors.Wrapf(err, "min rent not covered by account output with index %d", idx+1)
}

Expand Down
83 changes: 81 additions & 2 deletions pkg/tests/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func Test_TransitionAccount(t *testing.T) {
testsuite.AddBlockIssuerKey(newGenesisOutputKey),
testsuite.WithBlockIssuerExpirySlot(1),
)
consumedInputs, equalOutputs, equalWallets := ts.TransactionFramework.CreateBasicOutputsEqually(2, "Genesis:0")
consumedInputs, equalOutputs, equalWallets := ts.TransactionFramework.CreateBasicOutputsEqually(4, "Genesis:0")

tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateTransactionWithOptions("TX1", append(accountWallets, equalWallets...),
testsuite.WithAccountInput(accountInput, true),
Expand Down Expand Up @@ -276,7 +276,7 @@ func Test_TransitionAccount(t *testing.T) {

block4 := ts.IssueBlockAtSlotWithOptions("block4", slotIndexBlock4, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node1, tx4, blockfactory.WithStrongParents(latestParent.ID()))

_ = ts.CommitUntilSlot(slotIndexBlock4, activeNodes, block4)
latestParent = ts.CommitUntilSlot(slotIndexBlock4, activeNodes, block4)

ts.AssertAccountDiff(newAccountOutput.AccountID, slotIndexBlock4, &model.AccountDiff{
BICChange: 0,
Expand All @@ -303,6 +303,85 @@ func Test_TransitionAccount(t *testing.T) {
ValidatorStake: 10000,
}, ts.Nodes()...)

// CREATE IMPLICIT ACCOUNT FROM BASIC UTXO
inputForImplicitAccount, outputsForImplicitAccount, implicitAccountAddress, implicitWallet := ts.TransactionFramework.CreateImplicitAccountFromInput("TX1:3")

tx5 := lo.PanicOnErr(ts.TransactionFramework.CreateTransactionWithOptions("TX5", implicitWallet,
testsuite.WithInputs(inputForImplicitAccount),
testsuite.WithOutputs(outputsForImplicitAccount),
))

implicitAccountOutput := ts.TransactionFramework.Output("TX5:0")
implicitAccountOutputID := implicitAccountOutput.OutputID()
implicitAccountID := iotago.AccountIDFromOutputID(implicitAccountOutputID)

slotIndexBlock5 := latestParent.ID().Index()

block5 := ts.IssueBlockAtSlotWithOptions("block5", slotIndexBlock5, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node1, tx5, blockfactory.WithStrongParents(latestParent.ID()))

latestParent = ts.CommitUntilSlot(slotIndexBlock5, activeNodes, block5)

var implicitBlockIssuerKey iotago.BlockIssuerKey = iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(implicitAccountAddress)

ts.AssertAccountData(&accounts.AccountData{
ID: implicitAccountID,
Credits: accounts.NewBlockIssuanceCredits(0, slotIndexBlock5),
ExpirySlot: iotago.MaxSlotIndex,
OutputID: implicitAccountOutputID,
BlockIssuerKeys: iotago.NewBlockIssuerKeys(implicitBlockIssuerKey),
}, ts.Nodes()...)

// TRANSITION IMPLICIT ACCOUNT TO ACCOUNT OUTPUT

fullAccountBlockIssuerKey := utils.RandBlockIssuerKey()

inputForImplicitAccountTransition, outputsForImplicitAccountTransition, fullAccountWallet := ts.TransactionFramework.TransitionImplicitAccountToAccountOutput(
"TX5:0",
testsuite.WithBlockIssuerFeature(&iotago.BlockIssuerFeature{
BlockIssuerKeys: iotago.BlockIssuerKeys{fullAccountBlockIssuerKey},
ExpirySlot: iotago.MaxSlotIndex,
}),
)

tx6 := lo.PanicOnErr(ts.TransactionFramework.CreateTransactionWithOptions("TX6", fullAccountWallet,
testsuite.WithInputs(inputForImplicitAccountTransition),
testsuite.WithOutputs(outputsForImplicitAccountTransition),
testsuite.WithContextInputs(iotago.TxEssenceContextInputs{
&iotago.CommitmentInput{
CommitmentID: node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(),
},
}),
))

slotIndexBlock6 := latestParent.ID().Index()

block6 := ts.IssueBlockAtSlotWithOptions("block6", slotIndexBlock6, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node1, tx6, blockfactory.WithStrongParents(latestParent.ID()))

latestParent = ts.CommitUntilSlot(slotIndexBlock6, activeNodes, block6)

fullAccountOutputID := ts.TransactionFramework.Output("TX6:0").OutputID()

ts.AssertAccountDiff(implicitAccountID, slotIndexBlock6, &model.AccountDiff{
BICChange: 0,
PreviousUpdatedTime: 0,
NewOutputID: fullAccountOutputID,
PreviousOutputID: implicitAccountOutputID,
BlockIssuerKeysAdded: iotago.BlockIssuerKeys{fullAccountBlockIssuerKey},
BlockIssuerKeysRemoved: iotago.BlockIssuerKeys{implicitBlockIssuerKey},
ValidatorStakeChange: 0,
StakeEndEpochChange: 0,
FixedCostChange: 0,
DelegationStakeChange: 0,
}, false, ts.Nodes()...)

ts.AssertAccountData(&accounts.AccountData{
ID: implicitAccountID,
Credits: accounts.NewBlockIssuanceCredits(0, slotIndexBlock6),
ExpirySlot: iotago.MaxSlotIndex,
OutputID: fullAccountOutputID,
BlockIssuerKeys: iotago.NewBlockIssuerKeys(fullAccountBlockIssuerKey),
}, ts.Nodes()...)

ts.Wait(ts.Nodes()...)
}

Expand Down
Loading