From d676b990d6039f35f4f63514ae8bc0d9a423a30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 29 Jan 2024 08:57:15 +0100 Subject: [PATCH] Fixes for params, serialization, claiming --- components/accounts/params.go | 10 +-- components/accounts/parse.go | 4 +- components/app/app.go | 2 +- pkg/accountmanager/accountdestruction.go | 2 +- pkg/accountmanager/claim.go | 99 +++++++++++++----------- pkg/accountmanager/manager.go | 10 ++- pkg/accountmanager/save.go | 4 +- pkg/accountmanager/wallet.go | 19 +++-- pkg/info/commands.go | 10 +-- 9 files changed, 84 insertions(+), 76 deletions(-) diff --git a/components/accounts/params.go b/components/accounts/params.go index 867378c..b956e1e 100644 --- a/components/accounts/params.go +++ b/components/accounts/params.go @@ -35,7 +35,7 @@ type ( EndEpoch int64 `default:"0" usage:"The end epoch of the account to stake"` } - ParametersRewards struct { + ParametersClaim struct { Alias string `default:"" usage:"The alias name of the wallet to get rewards for"` } @@ -54,21 +54,15 @@ type ( ExpirySlot int64 `default:"0" usage:"Update the expiry slot of the account"` } - ParameterAccountsInfo struct { - Alias string `default:"" usage:"Alias name of the account to get info"` - Verbose bool `default:"false" usage:"Verbose output"` - } - ParametersAccounts struct { Create ParametersAccountsCreate Convert ParametersAccountsConvert Destroy ParametersAccountsDestroy Allot ParametersAccountsAllot Stake ParametersAccountsStake - Rewards ParametersRewards + Claim ParametersClaim Delegate ParametersAccountsDelegate Update ParametersAccountsUpdate - Info ParameterAccountsInfo } ) diff --git a/components/accounts/parse.go b/components/accounts/parse.go index f5dc052..5da22e8 100644 --- a/components/accounts/parse.go +++ b/components/accounts/parse.go @@ -76,7 +76,7 @@ func parseAccountCommands(commands []string, paramsAccounts *ParametersAccounts) parsedCmds = append(parsedCmds, stakingAccountParams) case accountmanager.OperationClaim.String(): - rewardsParams, err := parseRewardsFlags(¶msAccounts.Rewards) + rewardsParams, err := parseRewardsFlags(¶msAccounts.Claim) if err != nil { continue } @@ -186,7 +186,7 @@ func parseStakeAccountFlags(paramsAccountStake *ParametersAccountsStake) (*accou }, nil } -func parseRewardsFlags(paramsRewards *ParametersRewards) (*accountmanager.ClaimAccountParams, error) { +func parseRewardsFlags(paramsRewards *ParametersClaim) (*accountmanager.ClaimAccountParams, error) { if paramsRewards == nil { return nil, ierrors.New("paramsRewards missing for rewards account") } diff --git a/components/app/app.go b/components/app/app.go index cf0abfd..db658b5 100644 --- a/components/app/app.go +++ b/components/app/app.go @@ -79,7 +79,7 @@ func getScript() (string, error) { } func initialize(_ *app.App) error { - if info.ScriptName == os.Args[1] { + if len(os.Args) > 1 && info.ScriptName == os.Args[1] { err := info.Run() if err != nil { return err diff --git a/pkg/accountmanager/accountdestruction.go b/pkg/accountmanager/accountdestruction.go index 09a49cc..f39f56a 100644 --- a/pkg/accountmanager/accountdestruction.go +++ b/pkg/accountmanager/accountdestruction.go @@ -30,7 +30,7 @@ func (m *Manager) destroyAccount(ctx context.Context, alias string) error { return nil } - keyManager, err := iotagowallet.NewKeyManager(wallet.seed[:], BIP32PathForIndex(accData.Index)) + keyManager, err := iotagowallet.NewKeyManager(wallet.Seed[:], BIP32PathForIndex(accData.Index)) if err != nil { return err } diff --git a/pkg/accountmanager/claim.go b/pkg/accountmanager/claim.go index cf94f01..dddc2ff 100644 --- a/pkg/accountmanager/claim.go +++ b/pkg/accountmanager/claim.go @@ -7,9 +7,11 @@ import ( "github.com/iotaledger/evil-tools/pkg/models" "github.com/iotaledger/evil-tools/pkg/utils" "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/lo" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/api" "github.com/iotaledger/iota.go/v4/builder" + "github.com/iotaledger/iota.go/v4/wallet" ) func (m *Manager) claim(ctx context.Context, params *ClaimAccountParams) error { @@ -19,16 +21,18 @@ func (m *Manager) claim(ctx context.Context, params *ClaimAccountParams) error { } w, err := m.GetWallet(params.Alias) if err != nil { - return ierrors.Wrapf(err, "could not get wallet and account for alias %s", params.Alias) + return ierrors.Wrapf(err, "could not get wallet for alias %s", params.Alias) } + // not all aliases have a corresponding account, as user could only delegate, in this case we allot to the genesis account + var account wallet.Account accData, err := m.GetAccount(params.Alias) if err != nil { - return ierrors.Wrapf(err, "could not get account for alias %s", params.Alias) + account = m.GenesisAccount() + } else { + account = accData.Account } - delegationInputs := make([]*models.OutputData, 0) - rewardsResponses := make([]*api.ManaRewardsResponse, 0) for _, delegation := range delegations { rewardsResp, err := m.Client.GetRewards(ctx, delegation.OutputID) if err != nil { @@ -44,68 +48,75 @@ func (m *Manager) claim(ctx context.Context, params *ClaimAccountParams) error { } outputData := w.createOutputDataForIndex(delegation.OutputID, delegation.AddressIndex, outputStruct) - delegationInputs = append(delegationInputs, outputData) - rewardsResponses = append(rewardsResponses, rewardsResp) - } - if len(delegationInputs) == 0 || len(rewardsResponses) == 0 { - m.LogErrorf("no delegations found for alias %s", params.Alias) + congestionResp, issuanceResp, version, err := m.RequestBlockIssuanceData(ctx, m.Client, m.GenesisAccount()) + if err != nil { + return ierrors.Wrapf(err, "failed to request block issuance data for alias %s", params.Alias) + } - return nil - } + signedTx, err := m.createClaimingTransaction(outputData, rewardsResp, w, account.ID(), issuanceResp.LatestCommitment.MustID()) + if err != nil { + return ierrors.Wrapf(err, "failed to create transaction with claiming to alias %s", params.Alias) + } - congestionResp, issuanceResp, version, err := m.RequestBlockIssuanceData(ctx, m.Client, m.GenesisAccount()) - if err != nil { - return ierrors.Wrapf(err, "failed to request block issuance data for alias %s", params.Alias) - } + blockID, err := m.PostWithBlock(ctx, m.Client, signedTx, m.GenesisAccount(), congestionResp, issuanceResp, version) + if err != nil { + return ierrors.Wrapf(err, "failed to post transaction with claiming to alias %s", params.Alias) + } - signedTx, err := m.createClaimingTransaction(delegationInputs, rewardsResponses, w, accData.Account.ID(), issuanceResp.LatestCommitment.MustID()) - if err != nil { - return ierrors.Wrapf(err, "failed to create transaction with claiming to alias %s", params.Alias) - } + m.LogInfof("Posted transaction with blockID %s: claiming rewards connected to alias %s", blockID.ToHex(), params.Alias) + txID := lo.PanicOnErr(signedTx.Transaction.ID()) + basicOutputID := iotago.OutputIDFromTransactionIDAndIndex(txID, 0) - blkID, err := m.PostWithBlock(ctx, m.Client, signedTx, m.GenesisAccount(), congestionResp, issuanceResp, version) - if err != nil { - return ierrors.Wrapf(err, "failed to post transaction with claiming to alias %s", params.Alias) + if err := utils.AwaitBlockAndPayloadAcceptance(ctx, m.Logger, m.Client, blockID); err != nil { + return ierrors.Wrapf(err, "failed to await block issuance for block %s", blockID.ToHex()) + } + + m.LogInfof("Block and Transaction accepted: blockID %s", blockID.ToHex()) + // check if the creation output exists + _, err = m.Client.Client().OutputByID(ctx, basicOutputID) + if err != nil { + m.LogDebugf("Failed to get output from node") + + return ierrors.Wrapf(err, "failed to get output from node") + } } - m.LogInfof("Posted transaction with blockID %s: claiming rewards connected to alias %s", blkID.ToHex(), params.Alias) + m.removeDelegations(params.Alias) return nil } -func (m *Manager) createClaimingTransaction(inputs []*models.OutputData, rewardsResponses []*api.ManaRewardsResponse, w *Wallet, accountID iotago.AccountID, commitmentID iotago.CommitmentID) (*iotago.SignedTransaction, error) { +func (m *Manager) createClaimingTransaction(input *models.OutputData, rewardsResponse *api.ManaRewardsResponse, w *Wallet, accountID iotago.AccountID, commitmentID iotago.CommitmentID) (*iotago.SignedTransaction, error) { currentTime := time.Now() currentSlot := m.API.TimeProvider().SlotFromTime(currentTime) apiForSlot := m.Client.APIForSlot(currentSlot) // transaction signer - addrSigner, err := w.GetAddrSignerForIndexes(inputs...) + addrSigner, err := w.GetAddrSignerForIndexes(input) if err != nil { return nil, ierrors.Wrap(err, "failed to get address signer") } txBuilder := builder.NewTransactionBuilder(apiForSlot) totalMana := iotago.Mana(0) - for i, output := range inputs { - potentialMana, err := iotago.PotentialMana(apiForSlot.ManaDecayProvider(), apiForSlot.StorageScoreStructure(), output.OutputStruct, output.OutputID.Slot(), currentSlot) - if err != nil { - return nil, ierrors.Wrap(err, "failed to get potential mana") - } - - totalMana += potentialMana - totalMana += rewardsResponses[i].Rewards - totalMana += output.OutputStruct.StoredMana() - txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: output.Address, - InputID: output.OutputID, - Input: output.OutputStruct, - }). - AddRewardInput(&iotago.RewardInput{Index: 0}, rewardsResponses[i].Rewards). - AddCommitmentInput(&iotago.CommitmentInput{ - CommitmentID: commitmentID, - }) + potentialMana, err := iotago.PotentialMana(apiForSlot.ManaDecayProvider(), apiForSlot.StorageScoreStructure(), input.OutputStruct, input.OutputID.Slot(), currentSlot) + if err != nil { + return nil, ierrors.Wrap(err, "failed to get potential mana") } - totalBalance := utils.SumOutputsBalance(inputs) + totalMana += potentialMana + totalMana += rewardsResponse.Rewards + totalMana += input.OutputStruct.StoredMana() + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: input.Address, + InputID: input.OutputID, + Input: input.OutputStruct, + }). + AddRewardInput(&iotago.RewardInput{Index: 0}, rewardsResponse.Rewards). + AddCommitmentInput(&iotago.CommitmentInput{ + CommitmentID: commitmentID, + }) + + totalBalance := input.OutputStruct.BaseTokenAmount() outputAddr, _, _ := w.getAddress(iotago.AddressEd25519) output := builder.NewBasicOutputBuilder(outputAddr, totalBalance). Mana(totalMana). diff --git a/pkg/accountmanager/manager.go b/pkg/accountmanager/manager.go index 70bc4a6..c464b5b 100644 --- a/pkg/accountmanager/manager.go +++ b/pkg/accountmanager/manager.go @@ -198,6 +198,13 @@ func (m *Manager) GetDelegations(alias string) ([]*Delegation, error) { return delegations, nil } +func (m *Manager) removeDelegations(alias string) { + m.Lock() + defer m.Unlock() + + delete(m.delegations, alias) +} + //nolint:all,unused func (m *Manager) registerAccount(alias string, accountID iotago.AccountID, outputID iotago.OutputID, index uint32, privateKey ed25519.PrivateKey) iotago.AccountID { m.Lock() @@ -216,9 +223,6 @@ func (m *Manager) registerAccount(alias string, accountID iotago.AccountID, outp m.LogDebugf("overwriting account %s with alias %s\noutputID: %s addr: %s\n", accountID.String(), alias, outputID.ToHex(), account.Address().String()) return accountID } - - m.wallets[alias] = m.newAccountWallet(alias) - return accountID } diff --git a/pkg/accountmanager/save.go b/pkg/accountmanager/save.go index 307c819..50abc6d 100644 --- a/pkg/accountmanager/save.go +++ b/pkg/accountmanager/save.go @@ -40,7 +40,7 @@ func (m *Manager) fromAccountState(state *AccountsState) { m.accounts[accState.Alias] = accState.ToAccountData() } for _, w := range state.Wallets { - m.wallets[w.alias] = w + m.wallets[w.Alias] = w } for _, d := range state.Delegation { @@ -103,7 +103,7 @@ func (m *Manager) LoadStateFromFile() (loaded bool, err error) { type AccountsState struct { AccountState []*AccountState `serix:"accounts,lenPrefix=uint8"` - Wallets []*Wallet `serix:"wallets,lenPrefix=uint8,inlined"` + Wallets []*Wallet `serix:"wallets,lenPrefix=uint8"` Delegation []*Delegation `serix:"delegations,lenPrefix=uint8"` RequestTokenAmount iotago.BaseToken `serix:"RequestTokenAmount"` RequestManaAmount iotago.Mana `serix:"RequestManaAmount"` diff --git a/pkg/accountmanager/wallet.go b/pkg/accountmanager/wallet.go index 878655a..acedbc4 100644 --- a/pkg/accountmanager/wallet.go +++ b/pkg/accountmanager/wallet.go @@ -4,8 +4,6 @@ import ( "crypto" "crypto/ed25519" - "go.uber.org/atomic" - "github.com/iotaledger/evil-tools/pkg/models" hiveEd25519 "github.com/iotaledger/hive.go/crypto/ed25519" "github.com/iotaledger/hive.go/ierrors" @@ -16,15 +14,15 @@ import ( ) type Wallet struct { - alias string `serix:"alias,lenPrefix=uint8"` - seed [32]byte `serix:"seed"` - latestUsedIndex atomic.Uint32 `serix:"latestUsedIndex"` + Alias string `serix:"alias,lenPrefix=uint8"` + Seed [32]byte `serix:"seed"` + LatestUsedIndex uint32 `serix:"LatestUsedIndex"` } func newAccountWallet(alias string) *Wallet { return &Wallet{ - alias: alias, - seed: tpkg.RandEd25519Seed(), + Alias: alias, + Seed: tpkg.RandEd25519Seed(), } } @@ -83,8 +81,9 @@ func (a *Wallet) getAccountPublicKeys(pubKey crypto.PublicKey) (iotago.BlockIssu } func (a *Wallet) getAddress(addressType iotago.AddressType) (iotago.DirectUnlockableAddress, ed25519.PrivateKey, uint32) { - newIndex := a.latestUsedIndex.Inc() - keyManager := lo.PanicOnErr(wallet.NewKeyManager(a.seed[:], BIP32PathForIndex(newIndex))) + a.LatestUsedIndex++ + newIndex := a.LatestUsedIndex + keyManager := lo.PanicOnErr(wallet.NewKeyManager(a.Seed[:], BIP32PathForIndex(newIndex))) privateKey, _ := keyManager.KeyPair() receiverAddr := keyManager.Address(addressType) @@ -92,7 +91,7 @@ func (a *Wallet) getAddress(addressType iotago.AddressType) (iotago.DirectUnlock } func (a *Wallet) getPrivateKeyForIndex(index uint32) ed25519.PrivateKey { - keyManager := lo.PanicOnErr(wallet.NewKeyManager(a.seed[:], BIP32PathForIndex(index))) + keyManager := lo.PanicOnErr(wallet.NewKeyManager(a.Seed[:], BIP32PathForIndex(index))) privateKey, _ := keyManager.KeyPair() return privateKey diff --git a/pkg/info/commands.go b/pkg/info/commands.go index 39e3d04..1bdad8e 100644 --- a/pkg/info/commands.go +++ b/pkg/info/commands.go @@ -36,15 +36,15 @@ func (m *Manager) AccountsInfo() error { func (m *Manager) DelegatorsInfo() error { delegationOutToAliasMap := m.accWallets.Delegators() - t := "### Delegators: \n" + t := "\n### Delegators: \n" for _, alias := range delegationOutToAliasMap { - t += fmt.Sprintf("Alias: %-12s", alias) + t += fmt.Sprintf("Alias: %-12s\n", alias) delegations, err := m.accWallets.GetDelegations(alias) if err != nil { m.LogInfof("Could not get delegations for alias %s: %v", alias, err.Error()) - for _, del := range delegations { - t += fmt.Sprintf("OutputID: %-12s, Amount: %-33d BechAddr: %-40s", del.OutputID.ToHex(), del.Amount, del.DelegatedToBechAddress) - } + } + for _, del := range delegations { + t += fmt.Sprintf("OutputID: %s, Amount: %d BechAddr: %s\n", del.OutputID.ToHex(), del.Amount, del.DelegatedToBechAddress) } }