From 32ba9f982ca06634563bd1227fd87dd3bc275b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 22 Sep 2023 14:04:52 +0200 Subject: [PATCH 01/84] Add account spam to the basic spammer --- tools/evil-spammer/basic.go | 35 ++++++++ tools/evil-spammer/interactive.go | 1 + .../spammer/spamming_functions.go | 15 ++++ tools/evil-spammer/wallet/evilscenario.go | 4 + tools/evil-spammer/wallet/evilwallet.go | 78 +++++++++-------- tools/evil-spammer/wallet/options.go | 83 ++++++++----------- 6 files changed, 129 insertions(+), 87 deletions(-) diff --git a/tools/evil-spammer/basic.go b/tools/evil-spammer/basic.go index f04af73a7..98fb7f41c 100644 --- a/tools/evil-spammer/basic.go +++ b/tools/evil-spammer/basic.go @@ -35,6 +35,7 @@ func CustomSpam(params *CustomSpamParams) { w := wallet.NewEvilWallet(wallet.WithClients(params.ClientURLs...), wallet.WithFaucetOutputID(outputID)) wg := sync.WaitGroup{} + // funds are requested fro all spam types except SpammerTypeBlock fundsNeeded := false for _, st := range params.SpamTypes { if st != SpammerTypeBlock { @@ -92,6 +93,17 @@ func CustomSpam(params *CustomSpamParams) { go func() { defer wg.Done() }() + case SpammerTypeAccounts: + wg.Add(1) + go func() { + defer wg.Done() + + s := SpamAccounts(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.EnableRateSetter) + if s == nil { + return + } + s.Spam() + }() default: log.Warn("Spamming type not recognized. Try one of following: tx, ds, blk, custom, commitments") @@ -210,3 +222,26 @@ func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration return spammer.NewSpammer(options...) } + +func SpamAccounts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, enableRateSetter bool) *spammer.Spammer { + if w.NumOfClient() < 1 { + printer.NotEnoughClientsWarning(1) + } + scenarioOptions := []wallet.ScenarioOption{ + wallet.WithScenarioCustomConflicts(wallet.SingleTransactionBatch()), + wallet.WithCreateAccounts(), + } + + scenarioAccount := wallet.NewEvilScenario(scenarioOptions...) + + options := []spammer.Options{ + spammer.WithSpamRate(rate, timeUnit), + spammer.WithSpamDuration(duration), + spammer.WithRateSetter(enableRateSetter), + spammer.WithEvilWallet(w), + spammer.WithSpammingFunc(spammer.AccountSpammingFunction), + spammer.WithEvilScenario(scenarioAccount), + } + + return spammer.NewSpammer(options...) +} diff --git a/tools/evil-spammer/interactive.go b/tools/evil-spammer/interactive.go index 3bd43c694..95fdd4ad9 100644 --- a/tools/evil-spammer/interactive.go +++ b/tools/evil-spammer/interactive.go @@ -36,6 +36,7 @@ const ( SpammerTypeDs = "ds" SpammerTypeCustom = "custom" SpammerTypeCommitments = "commitments" + SpammerTypeAccounts = "accounts" ) var ( diff --git a/tools/evil-spammer/spammer/spamming_functions.go b/tools/evil-spammer/spammer/spamming_functions.go index 1473ce8cb..618886593 100644 --- a/tools/evil-spammer/spammer/spamming_functions.go +++ b/tools/evil-spammer/spammer/spamming_functions.go @@ -69,6 +69,21 @@ func CustomConflictSpammingFunc(s *Spammer) { s.CheckIfAllSent() } +func AccountSpammingFunction(s *Spammer) { + clt := s.Clients.GetClient() + // update scenario + tx, aliases, err := s.EvilWallet.PrepareAccountSpam(s.EvilScenario) + if err != nil { + s.log.Debugf(ierrors.Wrap(ErrFailToPrepareBatch, err.Error()).Error()) + s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) + } + s.PostTransaction(tx, clt) + + s.State.batchPrepared.Add(1) + s.EvilWallet.ClearAliases(aliases) + s.CheckIfAllSent() +} + // func CommitmentsSpammingFunction(s *Spammer) { // clt := s.Clients.GetClient() // p := payload.NewGenericDataPayload([]byte("SPAM")) diff --git a/tools/evil-spammer/wallet/evilscenario.go b/tools/evil-spammer/wallet/evilscenario.go index bd7c04805..32dd1109c 100644 --- a/tools/evil-spammer/wallet/evilscenario.go +++ b/tools/evil-spammer/wallet/evilscenario.go @@ -8,6 +8,7 @@ import ( "go.uber.org/atomic" "github.com/iotaledger/hive.go/ds/types" + iotago "github.com/iotaledger/iota.go/v4" ) // The custom conflict in spammer can be provided like this: @@ -41,6 +42,8 @@ type EvilScenario struct { ConflictBatch EvilBatch // determines whether outputs of the batch should be reused during the spam to create deep UTXO tree structure. Reuse bool + // specifies the output type of the spam, if not provided, defaults to BasicOutput + OutputType iotago.OutputType // if provided, the outputs from the spam will be saved into this wallet, accepted types of wallet: Reuse, RestrictedReuse. // if type == Reuse, then wallet is available for reuse spamming scenarios that did not provide RestrictedWallet. OutputWallet *Wallet @@ -56,6 +59,7 @@ func NewEvilScenario(options ...ScenarioOption) *EvilScenario { scenario := &EvilScenario{ ConflictBatch: SingleTransactionBatch(), Reuse: false, + OutputType: iotago.OutputBasic, OutputWallet: NewWallet(), BatchesCreated: atomic.NewUint64(0), } diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index ebc03cdb4..0a0f5b0b2 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -27,8 +27,6 @@ const ( awaitConfirmationSleep = 3 * time.Second awaitSolidificationSleep = time.Millisecond * 500 - - WaitForTxSolid = 150 * time.Second ) var ( @@ -367,8 +365,8 @@ func (e *EvilWallet) ClearAllAliases() { func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conflictBatch [][]*iotago.Transaction, err error) { for _, conflictMap := range conflictsMaps { var txs []*iotago.Transaction - for _, options := range conflictMap { - tx, err2 := e.CreateTransaction(options...) + for _, opts := range conflictMap { + tx, err2 := e.CreateTransaction(opts...) if err2 != nil { return nil, err2 } @@ -380,36 +378,6 @@ func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conf return } -// SendCustomConflicts sends transactions with the given conflictsMaps. -func (e *EvilWallet) SendCustomConflicts(conflictsMaps []ConflictSlice) (err error) { - conflictBatch, err := e.PrepareCustomConflicts(conflictsMaps) - if err != nil { - return err - } - for _, txs := range conflictBatch { - clients := e.connector.GetClients(len(txs)) - if len(txs) > len(clients) { - return ierrors.New("insufficient clients to send conflicts") - } - - // send transactions in parallel - wg := sync.WaitGroup{} - for i, tx := range txs { - wg.Add(1) - go func(clt Client, tx *iotago.Transaction) { - defer wg.Done() - _, _ = clt.PostTransaction(tx) - }(clients[i], tx) - } - wg.Wait() - - // wait until transactions are solid - time.Sleep(WaitForTxSolid) - } - - return -} - // CreateTransaction creates a transaction based on provided options. If no input wallet is provided, the next non-empty faucet wallet is used. // Inputs of the transaction are determined in three ways: // 1 - inputs are provided directly without associated alias, 2- alias is provided, and input is already stored in an alias manager, @@ -748,6 +716,14 @@ func (e *EvilWallet) PrepareCustomConflictsSpam(scenario *EvilScenario) (txs [][ return } +func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario) (*iotago.Transaction, ScenarioAlias, error) { + accountSpamOptions, allAliases := e.prepareFlatOptionsForAccountScenario(scenario) + + tx, err := e.CreateTransaction(accountSpamOptions...) + + return tx, allAliases, err +} + func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (conflictSlice []ConflictSlice, allAliases ScenarioAlias) { genOutputOptions := func(aliases []string) []*OutputOption { outputOptions := make([]*OutputOption, 0) @@ -783,6 +759,34 @@ func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (co return } +func (e *EvilWallet) prepareFlatOptionsForAccountScenario(scenario *EvilScenario) ([]Option, ScenarioAlias) { + // we do not care about batchedOutputs, because we do not support saving account spam result in evil wallet for now + prefixedBatch, allAliases, _ := scenario.ConflictBatchWithPrefix() + if len(prefixedBatch) != 1 { + panic("invalid scenario, cannot prepare flat option structure with deep scenario, EvilBatch should have only one element") + } + evilBatch := prefixedBatch[0] + if len(evilBatch) != 1 { + panic("invalid scenario, cannot prepare flat option structure with deep scenario, EvilBatch should have only one element") + } + + genOutputOptions := func(aliases []string) []*OutputOption { + outputOptions := make([]*OutputOption, 0) + for _, o := range aliases { + outputOptions = append(outputOptions, &OutputOption{ + aliasName: o, + outputType: iotago.OutputAccount, + }) + } + + return outputOptions + } + scenarioAlias := evilBatch[0] + outs := genOutputOptions(scenarioAlias.Outputs) + + return []Option{WithInputs(scenarioAlias.Inputs), WithOutputs(outs)}, allAliases +} + // AwaitInputsSolidity waits for all inputs to be solid for client clt. // func (e *EvilWallet) AwaitInputsSolidity(inputs devnetvm.Inputs, clt Client) (allSolid bool) { // awaitSolid := make([]string, 0) @@ -813,12 +817,6 @@ func (e *EvilWallet) SetTxOutputsSolid(outputs iotago.OutputIDs, clientID string // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// -func WithFaucetSeed(seed []byte) options.Option[EvilWallet] { - return func(opts *EvilWallet) { - copy(opts.optFaucetSeed[:], seed[:]) - } -} - func WithFaucetOutputID(id iotago.OutputID) options.Option[EvilWallet] { return func(opts *EvilWallet) { opts.optFaucetUnspentOutputID = id diff --git a/tools/evil-spammer/wallet/options.go b/tools/evil-spammer/wallet/options.go index a59259d2b..18756e2ec 100644 --- a/tools/evil-spammer/wallet/options.go +++ b/tools/evil-spammer/wallet/options.go @@ -7,6 +7,7 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/builder" ) // region Options /////////////////////////////////////////////////////////////////////////// @@ -22,21 +23,25 @@ type Options struct { outputBatchAliases map[string]types.Empty reuse bool issuingTime time.Time + // maps input alias to desired output type, used to create account output types + specialOutputTypes map[string]iotago.OutputType } type OutputOption struct { - aliasName string - amount iotago.BaseToken - address *iotago.Ed25519Address + aliasName string + amount iotago.BaseToken + address *iotago.Ed25519Address + outputType iotago.OutputType } // NewOptions is the constructor for the tx creation. func NewOptions(options ...Option) (option *Options, err error) { option = &Options{ - aliasInputs: make(map[string]types.Empty), - inputs: make([]*Output, 0), - aliasOutputs: make(map[string]iotago.Output), - outputs: make([]iotago.Output, 0), + aliasInputs: make(map[string]types.Empty), + inputs: make([]*Output, 0), + aliasOutputs: make(map[string]iotago.Output), + outputs: make([]iotago.Output, 0), + specialOutputTypes: make(map[string]iotago.OutputType), } for _, opt := range options { @@ -135,51 +140,29 @@ func WithInputs(inputs interface{}) Option { } } -// WithOutput returns an Option that is used to define a non-colored Output for the Transaction in the Block. -func WithOutput(output *OutputOption) Option { +// WithOutputs returns an Option that is used to define a non-colored Outputs for the Transaction in the Block. +func WithOutputs(outputsOptions []*OutputOption) Option { return func(options *Options) { - if output.amount == 0 || output.address == nil { - fmt.Println("output invalid") - return - } + for _, outputOptions := range outputsOptions { + if outputOptions.amount == 0 || outputOptions.address == nil { + fmt.Println("output invalid, amount or address not set") + return + } - if output.aliasName != "" { - fmt.Println(output.aliasName) - options.aliasOutputs[output.aliasName] = &iotago.BasicOutput{ - Amount: output.amount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: output.address}, - }, + var output iotago.Output + switch outputOptions.outputType { + case iotago.OutputBasic: + outputBuilder := builder.NewBasicOutputBuilder(outputOptions.address, outputOptions.amount) + output = outputBuilder.MustBuild() + case iotago.OutputAccount: + outputBuilder := builder.NewAccountOutputBuilder(outputOptions.address, outputOptions.address, outputOptions.amount) + output = outputBuilder.MustBuild() } - } else { - options.outputs = append(options.outputs, &iotago.BasicOutput{ - Amount: output.amount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: output.address}, - }, - }) - } - } -} -// WithOutputs returns an Option that is used to define a non-colored Outputs for the Transaction in the Block. -func WithOutputs(outputs []*OutputOption) Option { - return func(options *Options) { - for _, output := range outputs { - if output.aliasName != "" { - options.aliasOutputs[output.aliasName] = &iotago.BasicOutput{ - Amount: output.amount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: output.address}, - }, - } + if outputOptions.aliasName != "" { + options.aliasOutputs[outputOptions.aliasName] = output } else { - options.outputs = append(options.outputs, &iotago.BasicOutput{ - Amount: output.amount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: output.address}, - }, - }) + options.outputs = append(options.outputs, output) } } } @@ -299,4 +282,10 @@ func WithScenarioInputWalletForDeepSpam(wallet *Wallet) ScenarioOption { } } +func WithCreateAccounts() ScenarioOption { + return func(options *EvilScenario) { + options.OutputType = iotago.OutputAccount + } +} + // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// From e1dbe76b7f525d3da1f4dc95758f158c16c7a9bd Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Fri, 22 Sep 2023 21:09:24 +0800 Subject: [PATCH 02/84] Add outputType to all outputoptions --- tools/evil-spammer/wallet/evilwallet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index 0a0f5b0b2..c41f5d81a 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -342,7 +342,7 @@ func (e *EvilWallet) handleInputOutputDuringSplitOutputs(splitOutput *Output, sp balances := SplitBalanceEqually(splitNumber, input.Balance) for _, bal := range balances { - outputs = append(outputs, &OutputOption{amount: bal, address: receiveWallet.Address()}) + outputs = append(outputs, &OutputOption{amount: bal, address: receiveWallet.Address(), outputType: iotago.OutputBasic}) } return @@ -728,7 +728,7 @@ func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (co genOutputOptions := func(aliases []string) []*OutputOption { outputOptions := make([]*OutputOption, 0) for _, o := range aliases { - outputOptions = append(outputOptions, &OutputOption{aliasName: o}) + outputOptions = append(outputOptions, &OutputOption{aliasName: o, outputType: iotago.OutputBasic}) } return outputOptions From b9c984b133bb703dd040006d67823e09fdea943a Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Fri, 22 Sep 2023 21:40:45 +0800 Subject: [PATCH 03/84] Remove outputOption check --- tools/evil-spammer/wallet/options.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/evil-spammer/wallet/options.go b/tools/evil-spammer/wallet/options.go index 18756e2ec..74a0cd012 100644 --- a/tools/evil-spammer/wallet/options.go +++ b/tools/evil-spammer/wallet/options.go @@ -1,7 +1,6 @@ package wallet import ( - "fmt" "time" "github.com/iotaledger/hive.go/ds/types" @@ -144,11 +143,6 @@ func WithInputs(inputs interface{}) Option { func WithOutputs(outputsOptions []*OutputOption) Option { return func(options *Options) { for _, outputOptions := range outputsOptions { - if outputOptions.amount == 0 || outputOptions.address == nil { - fmt.Println("output invalid, amount or address not set") - return - } - var output iotago.Output switch outputOptions.outputType { case iotago.OutputBasic: From 6ca7381526c438a9e46e0a0261b967f440dbf69b Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 25 Sep 2023 14:08:31 +0800 Subject: [PATCH 04/84] Fix account output spam --- tools/evil-spammer/wallet/evilwallet.go | 37 +++++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index c41f5d81a..71685bd57 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -427,6 +427,11 @@ func (e *EvilWallet) CreateTransaction(options ...Option) (tx *iotago.Transactio // addOutputsToOutputManager adds output to the OutputManager if. func (e *EvilWallet) addOutputsToOutputManager(tx *iotago.Transaction, outWallet, tmpWallet *Wallet, tempAddresses map[string]types.Empty) { for idx, o := range tx.Essence.Outputs { + if o.UnlockConditionSet().Address() == nil { + continue + } + + // register UnlockConditionAddress only (skip account outputs) addr := o.UnlockConditionSet().Address().Address out := &Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(tx.ID(e.Connector().GetClient().CurrentAPI())), uint16(idx)), @@ -474,6 +479,9 @@ func (e *EvilWallet) registerOutputAliases(tx *iotago.Transaction, addrAliasMap for idx := range tx.Essence.Outputs { id := iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(tx.ID(e.Connector().GetClient().CurrentAPI())), uint16(idx)) out := e.outputManager.GetOutput(id) + if out == nil { + continue + } // register output alias e.aliasManager.AddOutputAlias(out, addrAliasMap[out.Address.String()]) @@ -584,12 +592,16 @@ func (e *EvilWallet) matchOutputsWithAliases(buildOptions *Options, tempWallet * tempAddresses[addr.String()] = types.Void } - outputs = append(outputs, &iotago.BasicOutput{ - Amount: output.BaseTokenAmount(), - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: addr}, - }, - }) + switch output.Type() { + case iotago.OutputBasic: + outputBuilder := builder.NewBasicOutputBuilder(addr, output.BaseTokenAmount()) + outputs = append(outputs, outputBuilder.MustBuild()) + case iotago.OutputAccount: + outputBuilder := builder.NewAccountOutputBuilder(addr, addr, output.BaseTokenAmount()) + outputs = append(outputs, outputBuilder.MustBuild()) + fmt.Println("having accout output", outputBuilder.MustBuild()) + } + addrAliasMap[addr.String()] = alias } @@ -664,9 +676,16 @@ func (e *EvilWallet) updateOutputBalances(buildOptions *Options) (err error) { } balances := SplitBalanceEqually(len(buildOptions.outputs)+len(buildOptions.aliasOutputs), totalBalance) i := 0 - for out := range buildOptions.aliasOutputs { - buildOptions.aliasOutputs[out] = &iotago.BasicOutput{ - Amount: balances[i], + for out, output := range buildOptions.aliasOutputs { + switch output.Type() { + case iotago.OutputBasic: + buildOptions.aliasOutputs[out] = &iotago.BasicOutput{ + Amount: balances[i], + } + case iotago.OutputAccount: + buildOptions.aliasOutputs[out] = &iotago.AccountOutput{ + Amount: balances[i], + } } i++ } From 59df4d62a744db045fe4de52abfc3f80a567ec08 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Wed, 27 Sep 2023 20:07:04 +0800 Subject: [PATCH 05/84] Update iota.go --- go.mod | 2 +- go.sum | 4 ++-- tools/evil-spammer/go.mod | 2 +- tools/evil-spammer/go.sum | 4 ++-- tools/gendoc/go.mod | 2 +- tools/gendoc/go.sum | 4 ++-- tools/genesis-snapshot/go.mod | 2 +- tools/genesis-snapshot/go.sum | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 0b81ce6b8..d08239046 100644 --- a/go.mod +++ b/go.mod @@ -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-20230927081440-4c25f83b8c40 + github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 github.com/labstack/echo/v4 v4.11.1 github.com/labstack/gommon v0.4.0 github.com/libp2p/go-libp2p v0.30.0 diff --git a/go.sum b/go.sum index dc5d2bf54..c0c774890 100644 --- a/go.sum +++ b/go.sum @@ -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-20230927081440-4c25f83b8c40 h1:NwmJf+JBVNZX/EUqRbdzIvfY2taGYJVRqvv7jzsuB3Y= -github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 h1:0ofS8G16U+IBoXjqufCzx10Qgw9koQtzUqu4cXnD2xA= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7/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= diff --git a/tools/evil-spammer/go.mod b/tools/evil-spammer/go.mod index bf95e2459..d5e37943c 100644 --- a/tools/evil-spammer/go.mod +++ b/tools/evil-spammer/go.mod @@ -17,7 +17,7 @@ require ( github.com/iotaledger/hive.go/runtime v0.0.0-20230926122307-d671b36a4a65 github.com/iotaledger/iota-core v0.0.0-00010101000000-000000000000 github.com/iotaledger/iota-core/tools/genesis-snapshot v0.0.0-00010101000000-000000000000 - github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40 + github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 github.com/mr-tron/base58 v1.2.0 go.uber.org/atomic v1.11.0 ) diff --git a/tools/evil-spammer/go.sum b/tools/evil-spammer/go.sum index 1e45bac47..6c87e4f10 100644 --- a/tools/evil-spammer/go.sum +++ b/tools/evil-spammer/go.sum @@ -195,8 +195,8 @@ github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230926122307-d671b36 github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230926122307-d671b36a4a65/go.mod h1:IJgaaxbgKCsNat18jlJJEAxCY2oVYR3F30B+M4vJ89I= github.com/iotaledger/hive.go/stringify v0.0.0-20230926122307-d671b36a4a65 h1:3OmUR8yYlCENhbosY99eM3bIJQJCiLijtebt+Q6sQEs= github.com/iotaledger/hive.go/stringify v0.0.0-20230926122307-d671b36a4a65/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40 h1:NwmJf+JBVNZX/EUqRbdzIvfY2taGYJVRqvv7jzsuB3Y= -github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 h1:0ofS8G16U+IBoXjqufCzx10Qgw9koQtzUqu4cXnD2xA= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= diff --git a/tools/gendoc/go.mod b/tools/gendoc/go.mod index 8e6677a89..d1fc86bad 100644 --- a/tools/gendoc/go.mod +++ b/tools/gendoc/go.mod @@ -72,7 +72,7 @@ require ( github.com/iotaledger/hive.go/stringify v0.0.0-20230926122307-d671b36a4a65 // indirect github.com/iotaledger/inx-app v1.0.0-rc.3.0.20230925153303-c7fbe63a0ab4 // indirect github.com/iotaledger/inx/go v1.0.0-rc.2.0.20230925152824-4bfa09b8c132 // indirect - github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40 // indirect + github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 // indirect github.com/ipfs/boxo v0.10.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect diff --git a/tools/gendoc/go.sum b/tools/gendoc/go.sum index e8eae9a30..7e01f1d7d 100644 --- a/tools/gendoc/go.sum +++ b/tools/gendoc/go.sum @@ -311,8 +311,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-20230927081440-4c25f83b8c40 h1:NwmJf+JBVNZX/EUqRbdzIvfY2taGYJVRqvv7jzsuB3Y= -github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 h1:0ofS8G16U+IBoXjqufCzx10Qgw9koQtzUqu4cXnD2xA= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7/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= diff --git a/tools/genesis-snapshot/go.mod b/tools/genesis-snapshot/go.mod index 15ccfb9ad..efc9e9ef7 100644 --- a/tools/genesis-snapshot/go.mod +++ b/tools/genesis-snapshot/go.mod @@ -10,7 +10,7 @@ require ( github.com/iotaledger/hive.go/lo v0.0.0-20230926122307-d671b36a4a65 github.com/iotaledger/hive.go/runtime v0.0.0-20230926122307-d671b36a4a65 github.com/iotaledger/iota-core v0.0.0-00010101000000-000000000000 - github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40 + github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 github.com/mr-tron/base58 v1.2.0 github.com/spf13/pflag v1.0.5 golang.org/x/crypto v0.13.0 diff --git a/tools/genesis-snapshot/go.sum b/tools/genesis-snapshot/go.sum index 96060b9a3..3d48e7240 100644 --- a/tools/genesis-snapshot/go.sum +++ b/tools/genesis-snapshot/go.sum @@ -50,8 +50,8 @@ github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230926122307-d671b36 github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230926122307-d671b36a4a65/go.mod h1:IJgaaxbgKCsNat18jlJJEAxCY2oVYR3F30B+M4vJ89I= github.com/iotaledger/hive.go/stringify v0.0.0-20230926122307-d671b36a4a65 h1:3OmUR8yYlCENhbosY99eM3bIJQJCiLijtebt+Q6sQEs= github.com/iotaledger/hive.go/stringify v0.0.0-20230926122307-d671b36a4a65/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40 h1:NwmJf+JBVNZX/EUqRbdzIvfY2taGYJVRqvv7jzsuB3Y= -github.com/iotaledger/iota.go/v4 v4.0.0-20230927081440-4c25f83b8c40/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7 h1:0ofS8G16U+IBoXjqufCzx10Qgw9koQtzUqu4cXnD2xA= +github.com/iotaledger/iota.go/v4 v4.0.0-20230927120336-ea2ee8c85df7/go.mod h1:wR9xBbsofns9hFyRHFZ2bDYIb861qsfmQPVMBKcPvDo= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= From aab6dfd5b3c0286d56a6e70a78a653d6473b3e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 28 Sep 2023 12:27:08 +0200 Subject: [PATCH 06/84] Restructure evil wallet package --- tools/evil-spammer/config.go | 8 +- .../{ => interactive}/interactive.go | 7 +- tools/evil-spammer/{ => interactive}/menu.go | 2 +- .../evil-spammer/{ => interactive}/survey.go | 2 +- tools/evil-spammer/main.go | 71 ++-------------- .../{ => programs}/commitments.go | 2 +- tools/evil-spammer/programs/params.go | 83 +++++++++++++++++++ .../evil-spammer/{ => programs}/quick-test.go | 2 +- .../{basic.go => programs/spammers.go} | 52 +++++------- 9 files changed, 124 insertions(+), 105 deletions(-) rename tools/evil-spammer/{ => interactive}/interactive.go (98%) rename tools/evil-spammer/{ => interactive}/menu.go (99%) rename tools/evil-spammer/{ => interactive}/survey.go (99%) rename tools/evil-spammer/{ => programs}/commitments.go (98%) create mode 100644 tools/evil-spammer/programs/params.go rename tools/evil-spammer/{ => programs}/quick-test.go (99%) rename tools/evil-spammer/{basic.go => programs/spammers.go} (86%) diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index 3bd2c1f34..3cd994b61 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -3,6 +3,8 @@ package main import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" + "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" ) @@ -16,9 +18,9 @@ var ( var ( Script = "basic" - customSpamParams = CustomSpamParams{ + customSpamParams = programs.CustomSpamParams{ ClientURLs: urls, - SpamTypes: []string{SpammerTypeBlock}, + SpamTypes: []string{interactive.SpammerTypeBlock}, Rates: []int{1}, Durations: []time.Duration{time.Second * 20}, BlkToBeSent: []int{0}, @@ -29,7 +31,7 @@ var ( DeepSpam: false, EnableRateSetter: false, } - quickTestParams = QuickTestParams{ + quickTestParams = programs.QuickTestParams{ ClientURLs: urls, Rate: 100, Duration: time.Second * 30, diff --git a/tools/evil-spammer/interactive.go b/tools/evil-spammer/interactive/interactive.go similarity index 98% rename from tools/evil-spammer/interactive.go rename to tools/evil-spammer/interactive/interactive.go index 95fdd4ad9..bea2969c9 100644 --- a/tools/evil-spammer/interactive.go +++ b/tools/evil-spammer/interactive/interactive.go @@ -1,4 +1,4 @@ -package main +package interactive import ( "encoding/json" @@ -15,6 +15,7 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/runtime/syncutils" + "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" "github.com/iotaledger/iota.go/v4/nodeclient" @@ -451,10 +452,10 @@ func (m *Mode) startSpam() { var s *spammer.Spammer if m.Config.Scenario == SpammerTypeBlock { - s = SpamBlocks(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, 0, m.Config.UseRateSetter) + s = programs.SpamBlocks(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, 0, m.Config.UseRateSetter) } else { scenario, _ := wallet.GetScenario(m.Config.Scenario) - s = SpamNestedConflicts(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, scenario, m.Config.Deep, m.Config.Reuse, m.Config.UseRateSetter) + s = programs.SpamNestedConflicts(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, scenario, m.Config.Deep, m.Config.Reuse, m.Config.UseRateSetter) if s == nil { return } diff --git a/tools/evil-spammer/menu.go b/tools/evil-spammer/interactive/menu.go similarity index 99% rename from tools/evil-spammer/menu.go rename to tools/evil-spammer/interactive/menu.go index f9b478b85..38bda5f01 100644 --- a/tools/evil-spammer/menu.go +++ b/tools/evil-spammer/interactive/menu.go @@ -1,4 +1,4 @@ -package main +package interactive import ( "fmt" diff --git a/tools/evil-spammer/survey.go b/tools/evil-spammer/interactive/survey.go similarity index 99% rename from tools/evil-spammer/survey.go rename to tools/evil-spammer/interactive/survey.go index 824c5239b..04d0530b4 100644 --- a/tools/evil-spammer/survey.go +++ b/tools/evil-spammer/interactive/survey.go @@ -1,4 +1,4 @@ -package main +package interactive import ( "strconv" diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 99193c3bb..a3d0441fc 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "flag" "fmt" "os" @@ -9,7 +8,9 @@ import ( "strings" "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" + "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" ) @@ -33,11 +34,13 @@ func main() { // run selected test scenario switch Script { case "interactive": - Run() + interactive.Run() case "basic": - CustomSpam(&customSpamParams) + programs.CustomSpam(&customSpamParams) + case "accounts": + //AccountWalletRun() case "quick": - QuickTest(&quickTestParams) + programs.QuickTest(&quickTestParams) // case SpammerTypeCommitments: // CommitmentsSpam(&commitmentsSpamParams) default: @@ -133,7 +136,7 @@ func parseBasicSpamFlags() { customSpamParams.BlkToBeSent = make([]int, len(customSpamParams.Durations)) } - customSpamParams.config = loadBasicConfig() + customSpamParams.Config = programs.LoadBasicConfig() } func parseQuickTestFlags() { @@ -204,61 +207,3 @@ func parseDurations(durations string) []time.Duration { return parsed } - -type BasicConfig struct { - LastFaucetUnspentOutputID string `json:"lastFaucetUnspentOutputId"` -} - -var basicConfigJSON = `{ - "lastFaucetUnspentOutputId": "" -}` - -var basicConfigFile = "basic_config.json" - -// load the config file. -func loadBasicConfig() *BasicConfig { - // open config file - config := new(BasicConfig) - file, err := os.Open(basicConfigFile) - if err != nil { - if !os.IsNotExist(err) { - panic(err) - } - - //nolint:gosec // users should be able to read the file - if err = os.WriteFile(basicConfigFile, []byte(basicConfigJSON), 0o644); err != nil { - panic(err) - } - if file, err = os.Open(basicConfigFile); err != nil { - panic(err) - } - } - defer file.Close() - - // decode config file - if err = json.NewDecoder(file).Decode(config); err != nil { - panic(err) - } - - return config -} - -func saveConfigsToFile(config *BasicConfig) { - // open config file - file, err := os.Open(basicConfigFile) - if err != nil { - panic(err) - } - defer file.Close() - - jsonConfigs, err := json.MarshalIndent(config, "", " ") - - if err != nil { - log.Errorf("failed to write configs to file %s", err) - } - - //nolint:gosec // users should be able to read the file - if err = os.WriteFile(basicConfigFile, jsonConfigs, 0o644); err != nil { - panic(err) - } -} diff --git a/tools/evil-spammer/commitments.go b/tools/evil-spammer/programs/commitments.go similarity index 98% rename from tools/evil-spammer/commitments.go rename to tools/evil-spammer/programs/commitments.go index b97dc205b..5083b8552 100644 --- a/tools/evil-spammer/commitments.go +++ b/tools/evil-spammer/programs/commitments.go @@ -1,4 +1,4 @@ -package main +package programs // import ( // "time" diff --git a/tools/evil-spammer/programs/params.go b/tools/evil-spammer/programs/params.go new file mode 100644 index 000000000..2d87ebe9b --- /dev/null +++ b/tools/evil-spammer/programs/params.go @@ -0,0 +1,83 @@ +package programs + +import ( + "encoding/json" + "os" + "time" + + "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" +) + +type CustomSpamParams struct { + ClientURLs []string + SpamTypes []string + Rates []int + Durations []time.Duration + BlkToBeSent []int + TimeUnit time.Duration + DelayBetweenConflicts time.Duration + NSpend int + Scenario wallet.EvilBatch + DeepSpam bool + EnableRateSetter bool + + Config *BasicConfig +} + +type BasicConfig struct { + LastFaucetUnspentOutputID string `json:"lastFaucetUnspentOutputId"` +} + +var basicConfigFile = "basic_config.json" + +var basicConfigJSON = `{ + "lastFaucetUnspentOutputId": "" +}` + +// LoadBasicConfig loads the config file. +func LoadBasicConfig() *BasicConfig { + // open config file + config := new(BasicConfig) + file, err := os.Open(basicConfigFile) + if err != nil { + if !os.IsNotExist(err) { + panic(err) + } + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(basicConfigFile, []byte(basicConfigJSON), 0o644); err != nil { + panic(err) + } + if file, err = os.Open(basicConfigFile); err != nil { + panic(err) + } + } + defer file.Close() + + // decode config file + if err = json.NewDecoder(file).Decode(config); err != nil { + panic(err) + } + + return config +} + +func SaveConfigsToFile(config *BasicConfig) { + // open config file + file, err := os.Open(basicConfigFile) + if err != nil { + panic(err) + } + defer file.Close() + + jsonConfigs, err := json.MarshalIndent(config, "", " ") + + if err != nil { + log.Errorf("failed to write configs to file %s", err) + } + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(basicConfigFile, jsonConfigs, 0o644); err != nil { + panic(err) + } +} diff --git a/tools/evil-spammer/quick-test.go b/tools/evil-spammer/programs/quick-test.go similarity index 99% rename from tools/evil-spammer/quick-test.go rename to tools/evil-spammer/programs/quick-test.go index 14a7e4b1f..942f74de7 100644 --- a/tools/evil-spammer/quick-test.go +++ b/tools/evil-spammer/programs/quick-test.go @@ -1,4 +1,4 @@ -package main +package programs import ( "time" diff --git a/tools/evil-spammer/basic.go b/tools/evil-spammer/programs/spammers.go similarity index 86% rename from tools/evil-spammer/basic.go rename to tools/evil-spammer/programs/spammers.go index 98fb7f41c..ba8965b73 100644 --- a/tools/evil-spammer/basic.go +++ b/tools/evil-spammer/programs/spammers.go @@ -1,35 +1,23 @@ -package main +package programs import ( "sync" "time" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" + "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" - iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4" ) -type CustomSpamParams struct { - ClientURLs []string - SpamTypes []string - Rates []int - Durations []time.Duration - BlkToBeSent []int - TimeUnit time.Duration - DelayBetweenConflicts time.Duration - NSpend int - Scenario wallet.EvilBatch - DeepSpam bool - EnableRateSetter bool - - config *BasicConfig -} +var log = logger.New("customSpam") func CustomSpam(params *CustomSpamParams) { outputID := iotago.OutputIDFromTransactionIDAndIndex(snapshotcreator.GenesisTransactionID, 0) - if params.config.LastFaucetUnspentOutputID != "" { - outputID, _ = iotago.OutputIDFromHex(params.config.LastFaucetUnspentOutputID) + if params.Config.LastFaucetUnspentOutputID != "" { + outputID, _ = iotago.OutputIDFromHex(params.Config.LastFaucetUnspentOutputID) } w := wallet.NewEvilWallet(wallet.WithClients(params.ClientURLs...), wallet.WithFaucetOutputID(outputID)) @@ -38,7 +26,7 @@ func CustomSpam(params *CustomSpamParams) { // funds are requested fro all spam types except SpammerTypeBlock fundsNeeded := false for _, st := range params.SpamTypes { - if st != SpammerTypeBlock { + if st != interactive.SpammerTypeBlock { fundsNeeded = true } } @@ -47,7 +35,7 @@ func CustomSpam(params *CustomSpamParams) { if err != nil { panic(err) } - saveConfigsToFile(&BasicConfig{ + SaveConfigsToFile(&BasicConfig{ LastFaucetUnspentOutputID: w.LastFaucetUnspentOutput().ToHex(), }) } @@ -56,7 +44,7 @@ func CustomSpam(params *CustomSpamParams) { log.Infof("Start spamming with rate: %d, time unit: %s, and spamming type: %s.", params.Rates[i], params.TimeUnit.String(), sType) switch sType { - case SpammerTypeBlock: + case interactive.SpammerTypeBlock: wg.Add(1) go func(i int) { defer wg.Done() @@ -66,19 +54,19 @@ func CustomSpam(params *CustomSpamParams) { } s.Spam() }(i) - case SpammerTypeTx: + case interactive.SpammerTypeTx: wg.Add(1) go func(i int) { defer wg.Done() SpamTransaction(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.DeepSpam, params.EnableRateSetter) }(i) - case SpammerTypeDs: + case interactive.SpammerTypeDs: wg.Add(1) go func(i int) { defer wg.Done() SpamDoubleSpends(w, params.Rates[i], params.NSpend, params.TimeUnit, params.Durations[i], params.DelayBetweenConflicts, params.DeepSpam, params.EnableRateSetter) }(i) - case SpammerTypeCustom: + case interactive.SpammerTypeCustom: wg.Add(1) go func(i int) { defer wg.Done() @@ -88,12 +76,12 @@ func CustomSpam(params *CustomSpamParams) { } s.Spam() }(i) - case SpammerTypeCommitments: + case interactive.SpammerTypeCommitments: wg.Add(1) go func() { defer wg.Done() }() - case SpammerTypeAccounts: + case interactive.SpammerTypeAccounts: wg.Add(1) go func() { defer wg.Done() @@ -116,7 +104,7 @@ func CustomSpam(params *CustomSpamParams) { func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, deepSpam, enableRateSetter bool) { if w.NumOfClient() < 1 { - printer.NotEnoughClientsWarning(1) + log.Infof("Warning: At least one client is needed to spam.") } scenarioOptions := []wallet.ScenarioOption{ @@ -147,7 +135,7 @@ func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Dur func SpamDoubleSpends(w *wallet.EvilWallet, rate, nSpent int, timeUnit, duration, delayBetweenConflicts time.Duration, deepSpam, enableRateSetter bool) { log.Debugf("Setting up double spend spammer with rate: %d, time unit: %s, and duration: %s.", rate, timeUnit.String(), duration.String()) if w.NumOfClient() < 2 { - printer.NotEnoughClientsWarning(2) + log.Infof("Warning: At least two client are needed to spam, and %d was provided", w.NumOfClient()) } scenarioOptions := []wallet.ScenarioOption{ @@ -192,7 +180,7 @@ func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time } scenario := wallet.NewEvilScenario(scenarioOptions...) if scenario.NumOfClientsNeeded > w.NumOfClient() { - printer.NotEnoughClientsWarning(scenario.NumOfClientsNeeded) + log.Infof("Warning: At least %d client are needed to spam, and %d was provided", scenario.NumOfClientsNeeded, w.NumOfClient()) } options := []spammer.Options{ @@ -208,7 +196,7 @@ func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, numBlkToSend int, enableRateSetter bool) *spammer.Spammer { if w.NumOfClient() < 1 { - printer.NotEnoughClientsWarning(1) + log.Infof("Warning: At least one client is needed to spam.") } options := []spammer.Options{ @@ -225,7 +213,7 @@ func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration func SpamAccounts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, enableRateSetter bool) *spammer.Spammer { if w.NumOfClient() < 1 { - printer.NotEnoughClientsWarning(1) + log.Infof("Warning: At least one client is needed to spam.") } scenarioOptions := []wallet.ScenarioOption{ wallet.WithScenarioCustomConflicts(wallet.SingleTransactionBatch()), From f4f7ad50050fc3f242e25de0290446722975180e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 28 Sep 2023 13:36:08 +0200 Subject: [PATCH 07/84] Fix dependency cycle --- tools/evil-spammer/config.go | 4 ++-- tools/evil-spammer/interactive/interactive.go | 19 ++++++------------- tools/evil-spammer/programs/spammers.go | 15 +++++++-------- tools/evil-spammer/spammer/spammer.go | 9 +++++++++ 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index 3cd994b61..254084931 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -3,8 +3,8 @@ package main import ( "time" - "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" + "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" ) @@ -20,7 +20,7 @@ var ( customSpamParams = programs.CustomSpamParams{ ClientURLs: urls, - SpamTypes: []string{interactive.SpammerTypeBlock}, + SpamTypes: []string{spammer.TypeBlock}, Rates: []int{1}, Durations: []time.Duration{time.Second * 20}, BlkToBeSent: []int{0}, diff --git a/tools/evil-spammer/interactive/interactive.go b/tools/evil-spammer/interactive/interactive.go index bea2969c9..f1c4d426b 100644 --- a/tools/evil-spammer/interactive/interactive.go +++ b/tools/evil-spammer/interactive/interactive.go @@ -31,13 +31,6 @@ const ( const ( AnswerEnable = "enable" AnswerDisable = "disable" - - SpammerTypeBlock = "blk" - SpammerTypeTx = "tx" - SpammerTypeDs = "ds" - SpammerTypeCustom = "custom" - SpammerTypeCommitments = "commitments" - SpammerTypeAccounts = "accounts" ) var ( @@ -75,7 +68,7 @@ var configJSON = fmt.Sprintf(`{ "autoRequestingEnabled": false, "autoRequestingAmount": "100", "useRateSetter": true -}`, SpammerTypeTx) +}`, spammer.TypeTx) var defaultConfig = InteractiveConfig{ clientURLs: map[string]types.Empty{ @@ -87,7 +80,7 @@ var defaultConfig = InteractiveConfig{ timeUnit: time.Second, Deep: false, Reuse: true, - Scenario: SpammerTypeTx, + Scenario: spammer.TypeTx, AutoRequesting: false, AutoRequestingAmount: "100", UseRateSetter: true, @@ -145,7 +138,7 @@ const ( ) var ( - scenarios = []string{SpammerTypeBlock, SpammerTypeTx, SpammerTypeDs, "conflict-circle", "guava", "orange", "mango", "pear", "lemon", "banana", "kiwi", "peace"} + scenarios = []string{spammer.TypeBlock, spammer.TypeTx, spammer.TypeDs, "conflict-circle", "guava", "orange", "mango", "pear", "lemon", "banana", "kiwi", "peace"} confirms = []string{AnswerEnable, AnswerDisable} outputNumbers = []string{"100", "1000", "5000", "cancel"} timeUnits = []string{mpm, mps} @@ -443,7 +436,7 @@ func (m *Mode) areEnoughFundsAvailable() bool { outputsNeeded = int(float64(m.Config.Rate) * m.Config.duration.Minutes()) } - return m.evilWallet.UnspentOutputsLeft(wallet.Fresh) < outputsNeeded && m.Config.Scenario != SpammerTypeBlock + return m.evilWallet.UnspentOutputsLeft(wallet.Fresh) < outputsNeeded && m.Config.Scenario != spammer.TypeBlock } func (m *Mode) startSpam() { @@ -451,7 +444,7 @@ func (m *Mode) startSpam() { defer m.spamMutex.Unlock() var s *spammer.Spammer - if m.Config.Scenario == SpammerTypeBlock { + if m.Config.Scenario == spammer.TypeBlock { s = programs.SpamBlocks(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, 0, m.Config.UseRateSetter) } else { scenario, _ := wallet.GetScenario(m.Config.Scenario) @@ -700,7 +693,7 @@ func (m *Mode) summarizeSpam(id int) { func (m *Mode) updateSentStatistic(s *spammer.Spammer, id int) { blkSent := s.BlocksSent() scenariosCreated := s.BatchesPrepared() - if m.spammerLog.SpamDetails(id).Scenario == SpammerTypeBlock { + if m.spammerLog.SpamDetails(id).Scenario == spammer.TypeBlock { m.blkSent.Add(blkSent) } else { m.txSent.Add(blkSent) diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index ba8965b73..6acac571f 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -5,7 +5,6 @@ import ( "time" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" - "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" @@ -26,7 +25,7 @@ func CustomSpam(params *CustomSpamParams) { // funds are requested fro all spam types except SpammerTypeBlock fundsNeeded := false for _, st := range params.SpamTypes { - if st != interactive.SpammerTypeBlock { + if st != spammer.TypeBlock { fundsNeeded = true } } @@ -44,7 +43,7 @@ func CustomSpam(params *CustomSpamParams) { log.Infof("Start spamming with rate: %d, time unit: %s, and spamming type: %s.", params.Rates[i], params.TimeUnit.String(), sType) switch sType { - case interactive.SpammerTypeBlock: + case spammer.TypeBlock: wg.Add(1) go func(i int) { defer wg.Done() @@ -54,19 +53,19 @@ func CustomSpam(params *CustomSpamParams) { } s.Spam() }(i) - case interactive.SpammerTypeTx: + case spammer.TypeTx: wg.Add(1) go func(i int) { defer wg.Done() SpamTransaction(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.DeepSpam, params.EnableRateSetter) }(i) - case interactive.SpammerTypeDs: + case spammer.TypeDs: wg.Add(1) go func(i int) { defer wg.Done() SpamDoubleSpends(w, params.Rates[i], params.NSpend, params.TimeUnit, params.Durations[i], params.DelayBetweenConflicts, params.DeepSpam, params.EnableRateSetter) }(i) - case interactive.SpammerTypeCustom: + case spammer.TypeCustom: wg.Add(1) go func(i int) { defer wg.Done() @@ -76,12 +75,12 @@ func CustomSpam(params *CustomSpamParams) { } s.Spam() }(i) - case interactive.SpammerTypeCommitments: + case spammer.TypeCommitments: wg.Add(1) go func() { defer wg.Done() }() - case interactive.SpammerTypeAccounts: + case spammer.TypeAccounts: wg.Add(1) go func() { defer wg.Done() diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index 4b870351e..9f810bad2 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -17,6 +17,15 @@ import ( iotago "github.com/iotaledger/iota.go/v4" ) +const ( + TypeBlock = "blk" + TypeTx = "tx" + TypeDs = "ds" + TypeCustom = "custom" + TypeCommitments = "commitments" + TypeAccounts = "accounts" +) + // region Spammer ////////////////////////////////////////////////////////////////////////////////////////////////////// // //nolint:revive From cc34f8ac1d88c8a27dff30ab7a7bc9ffa2188eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 28 Sep 2023 19:23:16 +0200 Subject: [PATCH 08/84] Add structure for first account commands --- tools/evil-spammer/accountwallet/commands.go | 21 +++++++ tools/evil-spammer/accountwallet/config.go | 42 +++++++++++++ tools/evil-spammer/accountwallet/wallet.go | 26 ++++++++ tools/evil-spammer/config.go | 21 ++++++- tools/evil-spammer/main.go | 65 +++++++++++++++++++- tools/evil-spammer/wallet/evilwallet.go | 1 - 6 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 tools/evil-spammer/accountwallet/commands.go create mode 100644 tools/evil-spammer/accountwallet/config.go create mode 100644 tools/evil-spammer/accountwallet/wallet.go diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go new file mode 100644 index 000000000..c10492a7e --- /dev/null +++ b/tools/evil-spammer/accountwallet/commands.go @@ -0,0 +1,21 @@ +package accountwallet + +func (a *AccountWallet) CreateAccount(params *CreateAccountParams) error { + //input := a.getFunds(params.Amount) + //txBuilder := builder.NewTransactionBuilder(a.api) + //txBuilder.AddInput(input) + + return nil +} + +func (a *AccountWallet) DestroyAccount(params *DestroyAccountParams) error { + return nil +} + +func (a *AccountWallet) ListAccount() error { + return nil +} + +func (a *AccountWallet) AllotToAccount(params *AllotAccountParams) error { + return nil +} diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go new file mode 100644 index 000000000..62e88fa1c --- /dev/null +++ b/tools/evil-spammer/accountwallet/config.go @@ -0,0 +1,42 @@ +package accountwallet + +// commands + +const ( + CreateAccountCommand = "create" + DestroyAccountCommand = "destroy" + AllotAccountCommand = "allot" + ListAccountsCommand = "list" +) + +type configuration struct { + WebAPI string `json:"WebAPI,omitempty"` +} + +type CommandParams interface { + CreateAccountParams | DestroyAccountParams | AllotAccountParams +} + +type CreateAccountParams struct { + Alias string + Amount uint64 +} + +type DestroyAccountParams struct { + AccountAlias string +} + +type AllotAccountParams struct { + AccountAlias string + Amount uint64 +} + +const lockFile = "wallet.LOCK" + +func loadWallet() *AccountWallet { + return nil +} + +func writeWalletStateFile(w any, filename string) { + +} diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go new file mode 100644 index 000000000..1cb00ae48 --- /dev/null +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -0,0 +1,26 @@ +package accountwallet + +import iotago "github.com/iotaledger/iota.go/v4" + +type AccountWallet struct { + // TODO can we reuse faucet requests from evil wallet? + // faucetFunds map[string]*Output + seed [32]byte + + accountsAliases map[string]iotago.AccountID + + api iotago.API +} + +func Run() *AccountWallet { + + // load wallet + wallet := loadWallet() + defer writeWalletStateFile(wallet, "wallet.dat") + + return wallet +} + +func (a *AccountWallet) getFunds(amount uint64) iotago.Output { + return nil +} diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index 254084931..a9b5f20b6 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -3,6 +3,7 @@ package main import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" @@ -11,12 +12,13 @@ import ( // Nodes used during the test, use at least two nodes to be able to doublespend. var ( // urls = []string{"http://bootstrap-01.feature.shimmer.iota.cafe:8080", "http://vanilla-01.feature.shimmer.iota.cafe:8080", "http://drng-01.feature.shimmer.iota.cafe:8080"} - // urls = []string{"http://localhost:8080", "http://localhost:8090", "http://localhost:8070", "http://localhost:8040"} - urls = []string{} + urls = []string{"http://localhost:8080"} //, "http://localhost:8090", "http://localhost:8070", "http://localhost:8040"} + //urls = []string{} ) var ( - Script = "basic" + Script = "basic" + Subcommand = "" customSpamParams = programs.CustomSpamParams{ ClientURLs: urls, @@ -40,6 +42,19 @@ var ( EnableRateSetter: false, } + createAccountParams = accountwallet.CreateAccountParams{ + Alias: "A", + Amount: 100, + } + + destoryAccountParams = accountwallet.DestroyAccountParams{ + AccountAlias: "A", + } + + allotAccountParams = accountwallet.AllotAccountParams{ + AccountAlias: "A", + Amount: 100, + } //nolint:godot // commitmentsSpamParams = CommitmentsSpamParams{ // Rate: 1, diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index a3d0441fc..5f0f2a4c2 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" @@ -38,7 +39,8 @@ func main() { case "basic": programs.CustomSpam(&customSpamParams) case "accounts": - //AccountWalletRun() + accWallet := accountwallet.Run() + accountsSubcommands(accWallet) case "quick": programs.QuickTest(&quickTestParams) // case SpammerTypeCommitments: @@ -48,6 +50,39 @@ func main() { } } +func accountsSubcommands(wallet *accountwallet.AccountWallet) { + switch Subcommand { + case accountwallet.CreateAccountCommand: + err := wallet.CreateAccount(&createAccountParams) + if err != nil { + log.Errorf("Error creating account: %v", err) + + return + } + case accountwallet.DestroyAccountCommand: + err := wallet.DestroyAccount(&destoryAccountParams) + if err != nil { + log.Errorf("Error destroying account: %v", err) + + return + } + case accountwallet.ListAccountsCommand: + err := wallet.ListAccount() + if err != nil { + log.Errorf("Error listing accounts: %v", err) + + return + } + case accountwallet.AllotAccountCommand: + err := wallet.AllotToAccount(&allotAccountParams) + if err != nil { + log.Errorf("Error allotting account: %v", err) + + return + } + } +} + func parseFlags() (help bool) { if len(os.Args) <= 1 { return true @@ -60,6 +95,13 @@ func parseFlags() (help bool) { switch Script { case "basic": parseBasicSpamFlags() + case "accounts": + // pass subcommands + subcommands := make([]string, 0) + if len(os.Args) > 2 { + subcommands = os.Args[2:] + } + parseAccountHandlerFlags(subcommands) case "quick": parseQuickTestFlags() // case SpammerTypeCommitments: @@ -72,8 +114,12 @@ func parseFlags() (help bool) { return } -func parseOptionFlagSet(flagSet *flag.FlagSet) { - err := flagSet.Parse(os.Args[2:]) +func parseOptionFlagSet(flagSet *flag.FlagSet, args ...[]string) { + commands := os.Args[2:] + if len(args) > 0 { + commands = args[0] + } + err := flagSet.Parse(commands) if err != nil { log.Errorf("Cannot parse first `script` parameter") return @@ -160,6 +206,19 @@ func parseQuickTestFlags() { quickTestParams.VerifyLedger = *verifyLedger } +func parseAccountHandlerFlags(subcommands []string) { + Subcommand = subcommands[0] + + switch Subcommand { + case "create-account": + alias := optionFlagSet.String("alias", "", "Alias of the account to be created") + amount := optionFlagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") + parseOptionFlagSet(optionFlagSet, subcommands) + createAccountParams.Alias = *alias + createAccountParams.Amount = uint64(*amount) + } +} + // func parseCommitmentsSpamFlags() { // commitmentType := optionFlagSet.String("type", commitmentsSpamParams.CommitmentType, "Type of commitment spam. Possible values: 'latest' - valid commitment spam, 'random' - completely new, invalid cahin, 'fork' - forked chain, combine with 'forkAfter' parameter.") // rate := optionFlagSet.Int("rate", commitmentsSpamParams.Rate, "Commitment spam rate") diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index bb9511314..5acc0b75d 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -599,7 +599,6 @@ func (e *EvilWallet) matchOutputsWithAliases(buildOptions *Options, tempWallet * case iotago.OutputAccount: outputBuilder := builder.NewAccountOutputBuilder(addr, addr, output.BaseTokenAmount()) outputs = append(outputs, outputBuilder.MustBuild()) - fmt.Println("having accout output", outputBuilder.MustBuild()) } addrAliasMap[addr.String()] = alias From 643de7c11bf7f7ab186f159b8337589779507502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 28 Sep 2023 19:35:13 +0200 Subject: [PATCH 09/84] After merge fix of tx types --- tools/evil-spammer/wallet/evilwallet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index 9801f762e..02aac5b48 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -428,7 +428,7 @@ func (e *EvilWallet) CreateTransaction(options ...Option) (signedTx *iotago.Sign // addOutputsToOutputManager adds output to the OutputManager if. func (e *EvilWallet) addOutputsToOutputManager(signedTx *iotago.SignedTransaction, outWallet, tmpWallet *Wallet, tempAddresses map[string]types.Empty) { - for idx, o := range signedTx.Transaction.Essence.Outputs { + for idx, o := range signedTx.Transaction.Outputs { if o.UnlockConditionSet().Address() == nil { continue } @@ -736,7 +736,7 @@ func (e *EvilWallet) PrepareCustomConflictsSpam(scenario *EvilScenario) (signedT return } -func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario) (*iotago.Transaction, ScenarioAlias, error) { +func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario) (*iotago.SignedTransaction, ScenarioAlias, error) { accountSpamOptions, allAliases := e.prepareFlatOptionsForAccountScenario(scenario) tx, err := e.CreateTransaction(accountSpamOptions...) From d0b7e765a4bd05d06c4d68420330ee015052db36 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Fri, 29 Sep 2023 13:43:20 +0800 Subject: [PATCH 10/84] Implement read/write file in AccountWallet --- tools/evil-spammer/accountwallet/config.go | 55 ++++++++++++++++++++-- tools/evil-spammer/accountwallet/wallet.go | 42 +++++++++++++++-- tools/evil-spammer/main.go | 6 ++- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 62e88fa1c..1432600ae 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -1,5 +1,12 @@ package accountwallet +import ( + "os" + + "github.com/iotaledger/hive.go/ierrors" + iotago "github.com/iotaledger/iota.go/v4" +) + // commands const ( @@ -33,10 +40,52 @@ type AllotAccountParams struct { const lockFile = "wallet.LOCK" -func loadWallet() *AccountWallet { - return nil +type AccountData struct { + Accounts []Account `serix:"0,mapKey=accounts,lengthPrefixType=uint8"` + // TODO: other info that the account wallet needs to store } -func writeWalletStateFile(w any, filename string) { +type Account struct { + Alias string `serix:"0,mapKey=alias"` + AccountID iotago.AccountID `serix:"1,mapKey=accountID"` + // TODO: other info of an account +} + +func loadWallet() (*AccountWallet, error) { + wallet := NewAccountWallet() + + bytes, err := os.ReadFile(lockFile) + if err != nil { + if err == os.ErrNotExist { + return wallet, nil + } + return nil, ierrors.Wrap(err, "failed to read account file") + } + + var data AccountData + _, err = wallet.api.Decode(bytes, &data) + if err != nil { + return nil, ierrors.Wrap(err, "failed to decode from file") + } + // TODO: import the data to Wallet + wallet.FromAccountData(data) + + return wallet, nil +} + +func writeWalletStateFile(w *AccountWallet, filename string) error { + dataToDump := w.ToAccountData() + + bytesToWrite, err := w.api.Encode(dataToDump) + if err != nil { + return ierrors.Wrap(err, "failed to encode account data") + } + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(filename, bytesToWrite, 0o644); err != nil { + return ierrors.Wrap(err, "failed to write account file") + } + + return nil } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 1cb00ae48..45043b4cd 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -1,6 +1,10 @@ package accountwallet -import iotago "github.com/iotaledger/iota.go/v4" +import ( + "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/runtime/options" + iotago "github.com/iotaledger/iota.go/v4" +) type AccountWallet struct { // TODO can we reuse faucet requests from evil wallet? @@ -12,13 +16,43 @@ type AccountWallet struct { api iotago.API } -func Run() *AccountWallet { +func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { + return options.Apply(&AccountWallet{ + accountsAliases: make(map[string]iotago.Identifier), + }, opts, func(w *AccountWallet) { + }) +} + +func Run() (*AccountWallet, error) { // load wallet - wallet := loadWallet() + wallet, err := loadWallet() + if err != nil { + return nil, ierrors.Wrap(err, "failed to load wallet from file") + } defer writeWalletStateFile(wallet, "wallet.dat") - return wallet + return wallet, nil +} + +// ToAccountData converts accounts information to ToAccountData +func (a *AccountWallet) ToAccountData() *AccountData { + accounts := make([]Account, 0) + + for alias, acc := range a.accountsAliases { + accounts = append(accounts, Account{ + Alias: alias, + AccountID: acc, + }) + } + + return &AccountData{Accounts: accounts} +} + +func (a *AccountWallet) FromAccountData(data AccountData) { + for _, acc := range data.Accounts { + a.accountsAliases[acc.Alias] = acc.AccountID + } } func (a *AccountWallet) getFunds(amount uint64) iotago.Output { diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 5f0f2a4c2..4e6ff3006 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -39,7 +39,11 @@ func main() { case "basic": programs.CustomSpam(&customSpamParams) case "accounts": - accWallet := accountwallet.Run() + accWallet, err := accountwallet.Run() + if err != nil { + log.Warn(err) + return + } accountsSubcommands(accWallet) case "quick": programs.QuickTest(&quickTestParams) From 3d062b0ad41f63f5472caf01d5fe08ce890354ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 29 Sep 2023 12:22:57 +0200 Subject: [PATCH 11/84] Support multiple subcommands --- tools/evil-spammer/accountwallet/config.go | 50 ++++---- tools/evil-spammer/accountwallet/wallet.go | 2 +- tools/evil-spammer/config.go | 16 +-- tools/evil-spammer/main.go | 133 +++++++++++++++++---- 4 files changed, 142 insertions(+), 59 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 1432600ae..5dd8e24f1 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -3,6 +3,7 @@ package accountwallet import ( "os" + "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" iotago "github.com/iotaledger/iota.go/v4" ) @@ -16,12 +17,16 @@ const ( ListAccountsCommand = "list" ) -type configuration struct { - WebAPI string `json:"WebAPI,omitempty"` +var AvailableCommands = map[string]types.Empty{ + CreateAccountCommand: types.Void, + DestroyAccountCommand: types.Void, + AllotAccountCommand: types.Void, + ListAccountsCommand: types.Void, } -type CommandParams interface { - CreateAccountParams | DestroyAccountParams | AllotAccountParams +// TODO how do wee read api +type configuration struct { + WebAPI string `json:"WebAPI,omitempty"` } type CreateAccountParams struct { @@ -34,10 +39,12 @@ type DestroyAccountParams struct { } type AllotAccountParams struct { - AccountAlias string - Amount uint64 + Amount uint64 + To string + From string // if not set we use faucet } +// TODO do wee need to restrict that only one instance of the wallet runs? const lockFile = "wallet.LOCK" type AccountData struct { @@ -51,25 +58,22 @@ type Account struct { // TODO: other info of an account } -func loadWallet() (*AccountWallet, error) { +func loadWallet(filename string) (*AccountWallet, error) { wallet := NewAccountWallet() - bytes, err := os.ReadFile(lockFile) - if err != nil { - if err == os.ErrNotExist { - return wallet, nil - } - return nil, ierrors.Wrap(err, "failed to read account file") - } - - var data AccountData - _, err = wallet.api.Decode(bytes, &data) - if err != nil { - return nil, ierrors.Wrap(err, "failed to decode from file") - } - - // TODO: import the data to Wallet - wallet.FromAccountData(data) + //walletStateBytes, err := os.ReadFile(filename) + //if err != nil { + // return nil, ierrors.Wrap(err, "failed to read wallet file") + //} + // + //var data AccountData + //_, err = wallet.api.Decode(bytes, &data) + //if err != nil { + // return nil, ierrors.Wrap(err, "failed to decode from file") + //} + // + //TODO: import the data to Wallet + //wallet.FromAccountData(data) return wallet, nil } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 45043b4cd..165b52fe5 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -26,7 +26,7 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { func Run() (*AccountWallet, error) { // load wallet - wallet, err := loadWallet() + wallet, err := loadWallet("") if err != nil { return nil, ierrors.Wrap(err, "failed to load wallet from file") } diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index a9b5f20b6..13f2dc81d 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -3,7 +3,6 @@ package main import ( "time" - "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" @@ -33,6 +32,7 @@ var ( DeepSpam: false, EnableRateSetter: false, } + quickTestParams = programs.QuickTestParams{ ClientURLs: urls, Rate: 100, @@ -42,19 +42,7 @@ var ( EnableRateSetter: false, } - createAccountParams = accountwallet.CreateAccountParams{ - Alias: "A", - Amount: 100, - } - - destoryAccountParams = accountwallet.DestroyAccountParams{ - AccountAlias: "A", - } - - allotAccountParams = accountwallet.AllotAccountParams{ - AccountAlias: "A", - Amount: 100, - } + accountsSubcommandsFlags = make([]*subcommand, 0) //nolint:godot // commitmentsSpamParams = CommitmentsSpamParams{ // Rate: 1, diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 4e6ff3006..3c4ed3cfb 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -39,12 +39,12 @@ func main() { case "basic": programs.CustomSpam(&customSpamParams) case "accounts": - accWallet, err := accountwallet.Run() - if err != nil { - log.Warn(err) - return - } - accountsSubcommands(accWallet) + //accWallet, err := accountwallet.Run() + //if err != nil { + // log.Warn(err) + // return + //} + accountsSubcommands(nil, accountsSubcommandsFlags) case "quick": programs.QuickTest(&quickTestParams) // case SpammerTypeCommitments: @@ -54,17 +54,28 @@ func main() { } } -func accountsSubcommands(wallet *accountwallet.AccountWallet) { - switch Subcommand { +func accountsSubcommands(wallet *accountwallet.AccountWallet, subcommands []*subcommand) { + for _, sub := range subcommands { + accountsSubcommand(wallet, sub) + } +} + +func accountsSubcommand(wallet *accountwallet.AccountWallet, sub *subcommand) { + switch sub.command { case accountwallet.CreateAccountCommand: - err := wallet.CreateAccount(&createAccountParams) + params := parseCreateAccountFlags(sub.flags) + log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.CreateAccountCommand, params) + err := wallet.CreateAccount(params) if err != nil { log.Errorf("Error creating account: %v", err) return } case accountwallet.DestroyAccountCommand: - err := wallet.DestroyAccount(&destoryAccountParams) + params := parseDestroyAccountFlags(sub.flags) + log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.DestroyAccountCommand, params) + + err := wallet.DestroyAccount(params) if err != nil { log.Errorf("Error destroying account: %v", err) @@ -78,7 +89,10 @@ func accountsSubcommands(wallet *accountwallet.AccountWallet) { return } case accountwallet.AllotAccountCommand: - err := wallet.AllotToAccount(&allotAccountParams) + params := parseAllotAccountFlags(sub.flags) + log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.AllotAccountCommand, params) + + err := wallet.AllotToAccount(params) if err != nil { log.Errorf("Error allotting account: %v", err) @@ -105,7 +119,7 @@ func parseFlags() (help bool) { if len(os.Args) > 2 { subcommands = os.Args[2:] } - parseAccountHandlerFlags(subcommands) + accountsSubcommandsFlags = parseSubcommands(subcommands) case "quick": parseQuickTestFlags() // case SpammerTypeCommitments: @@ -210,17 +224,94 @@ func parseQuickTestFlags() { quickTestParams.VerifyLedger = *verifyLedger } -func parseAccountHandlerFlags(subcommands []string) { - Subcommand = subcommands[0] +type subcommand struct { + command string + flags []string +} + +func parseSubcommands(subcommands []string) []*subcommand { + prevSplitIndex := 0 + subcommandsSplit := make([]*subcommand, 0) + + for index := 0; index < len(subcommands); index++ { + _, validCommand := accountwallet.AvailableCommands[subcommands[index]] + if !strings.HasPrefix(subcommands[index], "--") && validCommand { + if index != 0 { + subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1 : index]}) + } + prevSplitIndex = index + } + } + subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1:]}) + + return subcommandsSplit +} + +func parseCreateAccountFlags(subcommands []string) *accountwallet.CreateAccountParams { + flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + + alias := flagSet.String("alias", "", "Alias of the account to be created") + amount := flagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") + + log.Infof("Parsing create account flags, subcommands: %v", subcommands) + + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil + } + + createAccountParams := &accountwallet.CreateAccountParams{ + Alias: *alias, + Amount: uint64(*amount), + } + return createAccountParams +} + +func parseDestroyAccountFlags(subcommands []string) *accountwallet.DestroyAccountParams { + flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + + alias := flagSet.String("alias", "", "Alias of the account to be destroyed") + + log.Infof("Parsing destroy account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil + } + createAccountParams := &accountwallet.DestroyAccountParams{ + AccountAlias: *alias, + } + return createAccountParams +} + +func parseAllotAccountFlags(subcommands []string) *accountwallet.AllotAccountParams { + flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + + to := flagSet.String("to", "", "Alias of the account to allot mana") + amount := flagSet.Int("amount", 100, "Amount of mana to allot") + from := flagSet.String("from", "", "Alias of the account we allot from, if not specified, we allot from the faucet account") + + log.Infof("Parsing allot account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") - switch Subcommand { - case "create-account": - alias := optionFlagSet.String("alias", "", "Alias of the account to be created") - amount := optionFlagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") - parseOptionFlagSet(optionFlagSet, subcommands) - createAccountParams.Alias = *alias - createAccountParams.Amount = uint64(*amount) + return nil } + + createAccountParams := &accountwallet.AllotAccountParams{ + To: *to, + Amount: uint64(*amount), + } + + if *from != "" { + createAccountParams.From = *from + } + + return createAccountParams } // func parseCommitmentsSpamFlags() { From ec6ae168f2db49a1491895e09d810fa82a93fcdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 29 Sep 2023 13:29:44 +0200 Subject: [PATCH 12/84] Update account wallet saving and loading from the file --- tools/evil-spammer/accountwallet/config.go | 45 +--- tools/evil-spammer/accountwallet/wallet.go | 61 ++++- tools/evil-spammer/main.go | 291 ++------------------- tools/evil-spammer/parse.go | 275 +++++++++++++++++++ 4 files changed, 358 insertions(+), 314 deletions(-) create mode 100644 tools/evil-spammer/parse.go diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 5dd8e24f1..ac314ec84 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -3,6 +3,8 @@ package accountwallet import ( "os" + "github.com/google/martian/log" + "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" iotago "github.com/iotaledger/iota.go/v4" @@ -47,7 +49,7 @@ type AllotAccountParams struct { // TODO do wee need to restrict that only one instance of the wallet runs? const lockFile = "wallet.LOCK" -type AccountData struct { +type StateData struct { Accounts []Account `serix:"0,mapKey=accounts,lengthPrefixType=uint8"` // TODO: other info that the account wallet needs to store } @@ -58,38 +60,17 @@ type Account struct { // TODO: other info of an account } -func loadWallet(filename string) (*AccountWallet, error) { - wallet := NewAccountWallet() - - //walletStateBytes, err := os.ReadFile(filename) - //if err != nil { - // return nil, ierrors.Wrap(err, "failed to read wallet file") - //} - // - //var data AccountData - //_, err = wallet.api.Decode(bytes, &data) - //if err != nil { - // return nil, ierrors.Wrap(err, "failed to decode from file") - //} - // - //TODO: import the data to Wallet - //wallet.FromAccountData(data) - - return wallet, nil -} - -func writeWalletStateFile(w *AccountWallet, filename string) error { - dataToDump := w.ToAccountData() - - bytesToWrite, err := w.api.Encode(dataToDump) +func loadWallet(filename string, api iotago.API) (wallet *AccountWallet, err error) { + walletStateBytes, err := os.ReadFile(filename) if err != nil { - return ierrors.Wrap(err, "failed to encode account data") + log.Infof("No working wallet file %s found, creating new wallet...", filename) + wallet = NewAccountWallet(api) + } else { + wallet, err = AccountWalletFromBytes(api, walletStateBytes) + if err != nil { + return nil, ierrors.Wrap(err, "failed to create wallet from bytes") + } } - //nolint:gosec // users should be able to read the file - if err = os.WriteFile(filename, bytesToWrite, 0o644); err != nil { - return ierrors.Wrap(err, "failed to write account file") - } - - return nil + return wallet, nil } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 165b52fe5..eea1741ea 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -1,11 +1,39 @@ package accountwallet import ( + "os" + "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" iotago "github.com/iotaledger/iota.go/v4" ) +func Run(walletSourceFile string) (*AccountWallet, error) { + protocolParams := snapshotcreator.NewOptions(presets.Docker...).ProtocolParameters + api := iotago.V3API(protocolParams) + + // load wallet + wallet, err := loadWallet(walletSourceFile, api) + if err != nil { + return nil, ierrors.Wrap(err, "failed to load wallet from file") + } + + return wallet, nil +} + +func SaveState(w *AccountWallet, filename string) error { + bytesToWrite, err := w.Bytes() + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(filename, bytesToWrite, 0o644); err != nil { + return ierrors.Wrap(err, "failed to write account file") + } + + return nil +} + type AccountWallet struct { // TODO can we reuse faucet requests from evil wallet? // faucetFunds map[string]*Output @@ -16,27 +44,40 @@ type AccountWallet struct { api iotago.API } -func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { +func NewAccountWallet(api iotago.API, opts ...options.Option[AccountWallet]) *AccountWallet { return options.Apply(&AccountWallet{ accountsAliases: make(map[string]iotago.Identifier), + api: api, }, opts, func(w *AccountWallet) { }) } -func Run() (*AccountWallet, error) { - // load wallet - wallet, err := loadWallet("") +func AccountWalletFromBytes(api iotago.API, bytes []byte) (*AccountWallet, error) { + wallet := NewAccountWallet(api) + var data StateData + _, err := wallet.api.Decode(bytes, &data) if err != nil { - return nil, ierrors.Wrap(err, "failed to load wallet from file") + return nil, ierrors.Wrap(err, "failed to decode from file") } - defer writeWalletStateFile(wallet, "wallet.dat") + //TODO: import the data to Wallet + wallet.fromStateData(data) return wallet, nil } -// ToAccountData converts accounts information to ToAccountData -func (a *AccountWallet) ToAccountData() *AccountData { +func (a *AccountWallet) Bytes() ([]byte, error) { + state := a.toStateData() + stateBytes, err := a.api.Encode(state) + if err != nil { + return nil, ierrors.Wrap(err, "failed to encode state") + } + + return stateBytes, nil +} + +// toStateData converts accounts information to ToAccountData +func (a *AccountWallet) toStateData() *StateData { accounts := make([]Account, 0) for alias, acc := range a.accountsAliases { @@ -46,10 +87,10 @@ func (a *AccountWallet) ToAccountData() *AccountData { }) } - return &AccountData{Accounts: accounts} + return &StateData{Accounts: accounts} } -func (a *AccountWallet) FromAccountData(data AccountData) { +func (a *AccountWallet) fromStateData(data StateData) { for _, acc := range data.Accounts { a.accountsAliases[acc.Alias] = acc.AccountID } diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 3c4ed3cfb..cb95b9bd4 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -3,16 +3,15 @@ package main import ( "flag" "fmt" - "os" - "strconv" - "strings" - "time" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/interactive" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" +) + +const ( + accountWalletFilename = "wallet.dat" ) var ( @@ -39,12 +38,21 @@ func main() { case "basic": programs.CustomSpam(&customSpamParams) case "accounts": - //accWallet, err := accountwallet.Run() - //if err != nil { - // log.Warn(err) - // return - //} - accountsSubcommands(nil, accountsSubcommandsFlags) + // TODO init wallet for the first time if no file was found + // load wallet + accWallet, err := accountwallet.Run(accountWalletFilename) + if err != nil { + log.Warn(err) + return + } + // save wallet + defer func(w *accountwallet.AccountWallet, filename string) { + err = accountwallet.SaveState(w, filename) + if err != nil { + log.Errorf("Error while saving wallet state: %v", err) + } + }(accWallet, "wallet.dat") + accountsSubcommands(accWallet, accountsSubcommandsFlags) case "quick": programs.QuickTest(&quickTestParams) // case SpammerTypeCommitments: @@ -100,264 +108,3 @@ func accountsSubcommand(wallet *accountwallet.AccountWallet, sub *subcommand) { } } } - -func parseFlags() (help bool) { - if len(os.Args) <= 1 { - return true - } - script := os.Args[1] - - Script = script - log.Infof("script %s", Script) - - switch Script { - case "basic": - parseBasicSpamFlags() - case "accounts": - // pass subcommands - subcommands := make([]string, 0) - if len(os.Args) > 2 { - subcommands = os.Args[2:] - } - accountsSubcommandsFlags = parseSubcommands(subcommands) - case "quick": - parseQuickTestFlags() - // case SpammerTypeCommitments: - // parseCommitmentsSpamFlags() - } - if Script == "help" || Script == "-h" || Script == "--help" { - return true - } - - return -} - -func parseOptionFlagSet(flagSet *flag.FlagSet, args ...[]string) { - commands := os.Args[2:] - if len(args) > 0 { - commands = args[0] - } - err := flagSet.Parse(commands) - if err != nil { - log.Errorf("Cannot parse first `script` parameter") - return - } -} - -func parseBasicSpamFlags() { - urls := optionFlagSet.String("urls", "", "API urls for clients used in test separated with commas") - spamTypes := optionFlagSet.String("spammer", "", "Spammers used during test. Format: strings separated with comma, available options: 'blk' - block,"+ - " 'tx' - transaction, 'ds' - double spends spammers, 'nds' - n-spends spammer, 'custom' - spams with provided scenario") - rate := optionFlagSet.String("rate", "", "Spamming rate for provided 'spammer'. Format: numbers separated with comma, e.g. 10,100,1 if three spammers were provided for 'spammer' parameter.") - duration := optionFlagSet.String("duration", "", "Spam duration. Cannot be combined with flag 'blkNum'. Format: separated by commas list of decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") - blkNum := optionFlagSet.String("blkNum", "", "Spam duration in seconds. Cannot be combined with flag 'duration'. Format: numbers separated with comma, e.g. 10,100,1 if three spammers were provided for 'spammer' parameter.") - timeunit := optionFlagSet.Duration("tu", customSpamParams.TimeUnit, "Time unit for the spamming rate. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") - delayBetweenConflicts := optionFlagSet.Duration("dbc", customSpamParams.DelayBetweenConflicts, "delayBetweenConflicts - Time delay between conflicts in double spend spamming") - scenario := optionFlagSet.String("scenario", "", "Name of the EvilBatch that should be used for the spam. By default uses Scenario1. Possible scenarios can be found in evilwallet/customscenarion.go.") - deepSpam := optionFlagSet.Bool("deep", customSpamParams.DeepSpam, "Enable the deep spam, by reusing outputs created during the spam.") - nSpend := optionFlagSet.Int("nSpend", customSpamParams.NSpend, "Number of outputs to be spent in n-spends spammer for the spammer type needs to be set to 'ds'. Default value is 2 for double-spend.") - - parseOptionFlagSet(optionFlagSet) - - if *urls != "" { - parsedUrls := parseCommaSepString(*urls) - quickTestParams.ClientURLs = parsedUrls - customSpamParams.ClientURLs = parsedUrls - } - if *spamTypes != "" { - parsedSpamTypes := parseCommaSepString(*spamTypes) - customSpamParams.SpamTypes = parsedSpamTypes - } - if *rate != "" { - parsedRates := parseCommaSepInt(*rate) - customSpamParams.Rates = parsedRates - } - if *duration != "" { - parsedDurations := parseDurations(*duration) - customSpamParams.Durations = parsedDurations - } - if *blkNum != "" { - parsedBlkNums := parseCommaSepInt(*blkNum) - customSpamParams.BlkToBeSent = parsedBlkNums - } - if *scenario != "" { - conflictBatch, ok := wallet.GetScenario(*scenario) - if ok { - customSpamParams.Scenario = conflictBatch - } - } - - customSpamParams.NSpend = *nSpend - customSpamParams.DeepSpam = *deepSpam - customSpamParams.TimeUnit = *timeunit - customSpamParams.DelayBetweenConflicts = *delayBetweenConflicts - - // fill in unused parameter: blkNum or duration with zeros - if *duration == "" && *blkNum != "" { - customSpamParams.Durations = make([]time.Duration, len(customSpamParams.BlkToBeSent)) - } - if *blkNum == "" && *duration != "" { - customSpamParams.BlkToBeSent = make([]int, len(customSpamParams.Durations)) - } - - customSpamParams.Config = programs.LoadBasicConfig() -} - -func parseQuickTestFlags() { - urls := optionFlagSet.String("urls", "", "API urls for clients used in test separated with commas") - rate := optionFlagSet.Int("rate", quickTestParams.Rate, "The spamming rate") - duration := optionFlagSet.Duration("duration", quickTestParams.Duration, "Duration of the spam. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") - timeunit := optionFlagSet.Duration("tu", quickTestParams.TimeUnit, "Time unit for the spamming rate. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") - delayBetweenConflicts := optionFlagSet.Duration("dbc", quickTestParams.DelayBetweenConflicts, "delayBetweenConflicts - Time delay between conflicts in double spend spamming") - verifyLedger := optionFlagSet.Bool("verify", quickTestParams.VerifyLedger, "Set to true if verify ledger script should be run at the end of the test") - - parseOptionFlagSet(optionFlagSet) - - if *urls != "" { - parsedUrls := parseCommaSepString(*urls) - quickTestParams.ClientURLs = parsedUrls - } - quickTestParams.Rate = *rate - quickTestParams.Duration = *duration - quickTestParams.TimeUnit = *timeunit - quickTestParams.DelayBetweenConflicts = *delayBetweenConflicts - quickTestParams.VerifyLedger = *verifyLedger -} - -type subcommand struct { - command string - flags []string -} - -func parseSubcommands(subcommands []string) []*subcommand { - prevSplitIndex := 0 - subcommandsSplit := make([]*subcommand, 0) - - for index := 0; index < len(subcommands); index++ { - _, validCommand := accountwallet.AvailableCommands[subcommands[index]] - if !strings.HasPrefix(subcommands[index], "--") && validCommand { - if index != 0 { - subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1 : index]}) - } - prevSplitIndex = index - } - } - subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1:]}) - - return subcommandsSplit -} - -func parseCreateAccountFlags(subcommands []string) *accountwallet.CreateAccountParams { - flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) - - alias := flagSet.String("alias", "", "Alias of the account to be created") - amount := flagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") - - log.Infof("Parsing create account flags, subcommands: %v", subcommands) - - err := flagSet.Parse(subcommands) - if err != nil { - log.Errorf("Cannot parse first `script` parameter") - - return nil - } - - createAccountParams := &accountwallet.CreateAccountParams{ - Alias: *alias, - Amount: uint64(*amount), - } - return createAccountParams -} - -func parseDestroyAccountFlags(subcommands []string) *accountwallet.DestroyAccountParams { - flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) - - alias := flagSet.String("alias", "", "Alias of the account to be destroyed") - - log.Infof("Parsing destroy account flags, subcommands: %v", subcommands) - err := flagSet.Parse(subcommands) - if err != nil { - log.Errorf("Cannot parse first `script` parameter") - - return nil - } - createAccountParams := &accountwallet.DestroyAccountParams{ - AccountAlias: *alias, - } - return createAccountParams -} - -func parseAllotAccountFlags(subcommands []string) *accountwallet.AllotAccountParams { - flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) - - to := flagSet.String("to", "", "Alias of the account to allot mana") - amount := flagSet.Int("amount", 100, "Amount of mana to allot") - from := flagSet.String("from", "", "Alias of the account we allot from, if not specified, we allot from the faucet account") - - log.Infof("Parsing allot account flags, subcommands: %v", subcommands) - err := flagSet.Parse(subcommands) - if err != nil { - log.Errorf("Cannot parse first `script` parameter") - - return nil - } - - createAccountParams := &accountwallet.AllotAccountParams{ - To: *to, - Amount: uint64(*amount), - } - - if *from != "" { - createAccountParams.From = *from - } - - return createAccountParams -} - -// func parseCommitmentsSpamFlags() { -// commitmentType := optionFlagSet.String("type", commitmentsSpamParams.CommitmentType, "Type of commitment spam. Possible values: 'latest' - valid commitment spam, 'random' - completely new, invalid cahin, 'fork' - forked chain, combine with 'forkAfter' parameter.") -// rate := optionFlagSet.Int("rate", commitmentsSpamParams.Rate, "Commitment spam rate") -// duration := optionFlagSet.Duration("duration", commitmentsSpamParams.Duration, "Duration of the spam. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") -// timeUnit := optionFlagSet.Duration("tu", commitmentsSpamParams.TimeUnit, "Time unit for the spamming rate. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") -// networkAlias := optionFlagSet.String("network", commitmentsSpamParams.NetworkAlias, "Network alias for the test. Check your keys-config.json file for possible values.") -// identityAlias := optionFlagSet.String("spammerAlias", commitmentsSpamParams.SpammerAlias, "Identity alias for the node identity and its private keys that will be used to spam. Check your keys-config.json file for possible values.") -// validAlias := optionFlagSet.String("validAlias", commitmentsSpamParams.ValidAlias, "Identity alias for the honest node and its private keys, will be used to request valid commitment and block data. Check your keys-config.json file for possible values.") -// forkAfter := optionFlagSet.Int("forkAfter", commitmentsSpamParams.Rate, "Indicates how many slots after spammer startup should fork be placed in the created commitment chain. Works only for 'fork' commitment spam type.") - -// parseOptionFlagSet(optionFlagSet) - -// commitmentsSpamParams.CommitmentType = *commitmentType -// commitmentsSpamParams.Rate = *rate -// commitmentsSpamParams.Duration = *duration -// commitmentsSpamParams.TimeUnit = *timeUnit -// commitmentsSpamParams.NetworkAlias = *networkAlias -// commitmentsSpamParams.SpammerAlias = *identityAlias -// commitmentsSpamParams.ValidAlias = *validAlias -// commitmentsSpamParams.ForkAfter = *forkAfter -// } - -func parseCommaSepString(urls string) []string { - split := strings.Split(urls, ",") - - return split -} - -func parseCommaSepInt(nums string) []int { - split := strings.Split(nums, ",") - parsed := make([]int, len(split)) - for i, num := range split { - parsed[i], _ = strconv.Atoi(num) - } - - return parsed -} - -func parseDurations(durations string) []time.Duration { - split := strings.Split(durations, ",") - parsed := make([]time.Duration, len(split)) - for i, dur := range split { - parsed[i], _ = time.ParseDuration(dur) - } - - return parsed -} diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go new file mode 100644 index 000000000..c4d3431b6 --- /dev/null +++ b/tools/evil-spammer/parse.go @@ -0,0 +1,275 @@ +package main + +import ( + "flag" + "os" + "strconv" + "strings" + "time" + + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" + "github.com/iotaledger/iota-core/tools/evil-spammer/programs" + "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" +) + +func parseFlags() (help bool) { + if len(os.Args) <= 1 { + return true + } + script := os.Args[1] + + Script = script + log.Infof("script %s", Script) + + switch Script { + case "basic": + parseBasicSpamFlags() + case "accounts": + // pass subcommands + subcommands := make([]string, 0) + if len(os.Args) > 2 { + subcommands = os.Args[2:] + } + accountsSubcommandsFlags = readSubcommandsAndFlagSets(subcommands) + case "quick": + parseQuickTestFlags() + // case SpammerTypeCommitments: + // parseCommitmentsSpamFlags() + } + if Script == "help" || Script == "-h" || Script == "--help" { + return true + } + + return +} + +func parseOptionFlagSet(flagSet *flag.FlagSet, args ...[]string) { + commands := os.Args[2:] + if len(args) > 0 { + commands = args[0] + } + err := flagSet.Parse(commands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + return + } +} + +func parseBasicSpamFlags() { + urls := optionFlagSet.String("urls", "", "API urls for clients used in test separated with commas") + spamTypes := optionFlagSet.String("spammer", "", "Spammers used during test. Format: strings separated with comma, available options: 'blk' - block,"+ + " 'tx' - transaction, 'ds' - double spends spammers, 'nds' - n-spends spammer, 'custom' - spams with provided scenario") + rate := optionFlagSet.String("rate", "", "Spamming rate for provided 'spammer'. Format: numbers separated with comma, e.g. 10,100,1 if three spammers were provided for 'spammer' parameter.") + duration := optionFlagSet.String("duration", "", "Spam duration. Cannot be combined with flag 'blkNum'. Format: separated by commas list of decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") + blkNum := optionFlagSet.String("blkNum", "", "Spam duration in seconds. Cannot be combined with flag 'duration'. Format: numbers separated with comma, e.g. 10,100,1 if three spammers were provided for 'spammer' parameter.") + timeunit := optionFlagSet.Duration("tu", customSpamParams.TimeUnit, "Time unit for the spamming rate. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") + delayBetweenConflicts := optionFlagSet.Duration("dbc", customSpamParams.DelayBetweenConflicts, "delayBetweenConflicts - Time delay between conflicts in double spend spamming") + scenario := optionFlagSet.String("scenario", "", "Name of the EvilBatch that should be used for the spam. By default uses Scenario1. Possible scenarios can be found in evilwallet/customscenarion.go.") + deepSpam := optionFlagSet.Bool("deep", customSpamParams.DeepSpam, "Enable the deep spam, by reusing outputs created during the spam.") + nSpend := optionFlagSet.Int("nSpend", customSpamParams.NSpend, "Number of outputs to be spent in n-spends spammer for the spammer type needs to be set to 'ds'. Default value is 2 for double-spend.") + + parseOptionFlagSet(optionFlagSet) + + if *urls != "" { + parsedUrls := parseCommaSepString(*urls) + quickTestParams.ClientURLs = parsedUrls + customSpamParams.ClientURLs = parsedUrls + } + if *spamTypes != "" { + parsedSpamTypes := parseCommaSepString(*spamTypes) + customSpamParams.SpamTypes = parsedSpamTypes + } + if *rate != "" { + parsedRates := parseCommaSepInt(*rate) + customSpamParams.Rates = parsedRates + } + if *duration != "" { + parsedDurations := parseDurations(*duration) + customSpamParams.Durations = parsedDurations + } + if *blkNum != "" { + parsedBlkNums := parseCommaSepInt(*blkNum) + customSpamParams.BlkToBeSent = parsedBlkNums + } + if *scenario != "" { + conflictBatch, ok := wallet.GetScenario(*scenario) + if ok { + customSpamParams.Scenario = conflictBatch + } + } + + customSpamParams.NSpend = *nSpend + customSpamParams.DeepSpam = *deepSpam + customSpamParams.TimeUnit = *timeunit + customSpamParams.DelayBetweenConflicts = *delayBetweenConflicts + + // fill in unused parameter: blkNum or duration with zeros + if *duration == "" && *blkNum != "" { + customSpamParams.Durations = make([]time.Duration, len(customSpamParams.BlkToBeSent)) + } + if *blkNum == "" && *duration != "" { + customSpamParams.BlkToBeSent = make([]int, len(customSpamParams.Durations)) + } + + customSpamParams.Config = programs.LoadBasicConfig() +} + +func parseQuickTestFlags() { + urls := optionFlagSet.String("urls", "", "API urls for clients used in test separated with commas") + rate := optionFlagSet.Int("rate", quickTestParams.Rate, "The spamming rate") + duration := optionFlagSet.Duration("duration", quickTestParams.Duration, "Duration of the spam. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") + timeunit := optionFlagSet.Duration("tu", quickTestParams.TimeUnit, "Time unit for the spamming rate. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") + delayBetweenConflicts := optionFlagSet.Duration("dbc", quickTestParams.DelayBetweenConflicts, "delayBetweenConflicts - Time delay between conflicts in double spend spamming") + verifyLedger := optionFlagSet.Bool("verify", quickTestParams.VerifyLedger, "Set to true if verify ledger script should be run at the end of the test") + + parseOptionFlagSet(optionFlagSet) + + if *urls != "" { + parsedUrls := parseCommaSepString(*urls) + quickTestParams.ClientURLs = parsedUrls + } + quickTestParams.Rate = *rate + quickTestParams.Duration = *duration + quickTestParams.TimeUnit = *timeunit + quickTestParams.DelayBetweenConflicts = *delayBetweenConflicts + quickTestParams.VerifyLedger = *verifyLedger +} + +type subcommand struct { + command string + flags []string +} + +// readSubcommandsAndFlagSets splits the subcommands on multiple flag sets. +func readSubcommandsAndFlagSets(subcommands []string) []*subcommand { + prevSplitIndex := 0 + subcommandsSplit := make([]*subcommand, 0) + + for index := 0; index < len(subcommands); index++ { + _, validCommand := accountwallet.AvailableCommands[subcommands[index]] + if !strings.HasPrefix(subcommands[index], "--") && validCommand { + if index != 0 { + subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1 : index]}) + } + prevSplitIndex = index + } + } + subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1:]}) + + return subcommandsSplit +} + +func parseCreateAccountFlags(subcommands []string) *accountwallet.CreateAccountParams { + flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + + alias := flagSet.String("alias", "", "Alias of the account to be created") + amount := flagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") + + log.Infof("Parsing create account flags, subcommands: %v", subcommands) + + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil + } + + createAccountParams := &accountwallet.CreateAccountParams{ + Alias: *alias, + Amount: uint64(*amount), + } + return createAccountParams +} + +func parseDestroyAccountFlags(subcommands []string) *accountwallet.DestroyAccountParams { + flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + + alias := flagSet.String("alias", "", "Alias of the account to be destroyed") + + log.Infof("Parsing destroy account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil + } + createAccountParams := &accountwallet.DestroyAccountParams{ + AccountAlias: *alias, + } + return createAccountParams +} + +func parseAllotAccountFlags(subcommands []string) *accountwallet.AllotAccountParams { + flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + + to := flagSet.String("to", "", "Alias of the account to allot mana") + amount := flagSet.Int("amount", 100, "Amount of mana to allot") + from := flagSet.String("from", "", "Alias of the account we allot from, if not specified, we allot from the faucet account") + + log.Infof("Parsing allot account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil + } + + createAccountParams := &accountwallet.AllotAccountParams{ + To: *to, + Amount: uint64(*amount), + } + + if *from != "" { + createAccountParams.From = *from + } + + return createAccountParams +} + +// func parseCommitmentsSpamFlags() { +// commitmentType := optionFlagSet.String("type", commitmentsSpamParams.CommitmentType, "Type of commitment spam. Possible values: 'latest' - valid commitment spam, 'random' - completely new, invalid cahin, 'fork' - forked chain, combine with 'forkAfter' parameter.") +// rate := optionFlagSet.Int("rate", commitmentsSpamParams.Rate, "Commitment spam rate") +// duration := optionFlagSet.Duration("duration", commitmentsSpamParams.Duration, "Duration of the spam. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") +// timeUnit := optionFlagSet.Duration("tu", commitmentsSpamParams.TimeUnit, "Time unit for the spamming rate. Format: decimal numbers, each with optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'.\n Valid time units are 'ns', 'us', 'ms', 's', 'm', 'h'.") +// networkAlias := optionFlagSet.String("network", commitmentsSpamParams.NetworkAlias, "Network alias for the test. Check your keys-config.json file for possible values.") +// identityAlias := optionFlagSet.String("spammerAlias", commitmentsSpamParams.SpammerAlias, "Identity alias for the node identity and its private keys that will be used to spam. Check your keys-config.json file for possible values.") +// validAlias := optionFlagSet.String("validAlias", commitmentsSpamParams.ValidAlias, "Identity alias for the honest node and its private keys, will be used to request valid commitment and block data. Check your keys-config.json file for possible values.") +// forkAfter := optionFlagSet.Int("forkAfter", commitmentsSpamParams.Rate, "Indicates how many slots after spammer startup should fork be placed in the created commitment chain. Works only for 'fork' commitment spam type.") + +// parseOptionFlagSet(optionFlagSet) + +// commitmentsSpamParams.CommitmentType = *commitmentType +// commitmentsSpamParams.Rate = *rate +// commitmentsSpamParams.Duration = *duration +// commitmentsSpamParams.TimeUnit = *timeUnit +// commitmentsSpamParams.NetworkAlias = *networkAlias +// commitmentsSpamParams.SpammerAlias = *identityAlias +// commitmentsSpamParams.ValidAlias = *validAlias +// commitmentsSpamParams.ForkAfter = *forkAfter +// } + +func parseCommaSepString(urls string) []string { + split := strings.Split(urls, ",") + + return split +} + +func parseCommaSepInt(nums string) []int { + split := strings.Split(nums, ",") + parsed := make([]int, len(split)) + for i, num := range split { + parsed[i], _ = strconv.Atoi(num) + } + + return parsed +} + +func parseDurations(durations string) []time.Duration { + split := strings.Split(durations, ",") + parsed := make([]time.Duration, len(split)) + for i, dur := range split { + parsed[i], _ = time.ParseDuration(dur) + } + + return parsed +} From 60d906fa47b32c354432842a4ef2be2831219568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 29 Sep 2023 15:18:44 +0200 Subject: [PATCH 13/84] Update flags and help generation --- tools/evil-spammer/logger/logger.go | 2 +- tools/evil-spammer/main.go | 7 +++-- tools/evil-spammer/parse.go | 40 ++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/tools/evil-spammer/logger/logger.go b/tools/evil-spammer/logger/logger.go index 276850a01..20ce465a3 100644 --- a/tools/evil-spammer/logger/logger.go +++ b/tools/evil-spammer/logger/logger.go @@ -12,7 +12,7 @@ var New = logger.NewLogger func init() { config := configuration.New() - err := config.Set(logger.ConfigurationKeyOutputPaths, []string{"evil-spammer.log"}) + err := config.Set(logger.ConfigurationKeyOutputPaths, []string{"evil-spammer.log", "stdout"}) if err != nil { fmt.Println(err) return diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index cb95b9bd4..13c81859c 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -26,8 +26,8 @@ func main() { fmt.Println("Usage of the Evil Spammer tool, provide the first argument for the selected mode:\n" + "'interactive' - enters the interactive mode.\n" + "'basic' - can be parametrized with additional flags to run one time spammer. Run 'evil-wallet basic -h' for the list of possible flags.\n" + - "'quick' - runs simple stress test: tx spam -> blk spam -> ds spam. Run 'evil-wallet quick -h' for the list of possible flags.\n" + - "'commitments' - runs spammer for commitments. Run 'evil-wallet commitments -h' for the list of possible flags.") + "'accounts' - tool for account creation and transition. Run 'evil-wallet accounts -h' for the list of possible flags.\n" + + "'quick' - runs simple stress test: tx spam -> blk spam -> ds spam. Run 'evil-wallet quick -h' for the list of possible flags.") return } @@ -38,7 +38,6 @@ func main() { case "basic": programs.CustomSpam(&customSpamParams) case "accounts": - // TODO init wallet for the first time if no file was found // load wallet accWallet, err := accountwallet.Run(accountWalletFilename) if err != nil { @@ -58,7 +57,7 @@ func main() { // case SpammerTypeCommitments: // CommitmentsSpam(&commitmentsSpamParams) default: - log.Warnf("Unknown parameter for script, possible values: basic, quick, commitments") + log.Warnf("Unknown parameter for script, possible values: interactive, basic, accounts, quick") } } diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index c4d3431b6..d2a0b2a9b 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -2,6 +2,7 @@ package main import ( "flag" + "fmt" "os" "strconv" "strings" @@ -144,9 +145,14 @@ type subcommand struct { func readSubcommandsAndFlagSets(subcommands []string) []*subcommand { prevSplitIndex := 0 subcommandsSplit := make([]*subcommand, 0) - + if len(subcommands) == 0 { + accountUsage() + } for index := 0; index < len(subcommands); index++ { _, validCommand := accountwallet.AvailableCommands[subcommands[index]] + if subcommands[index] == "-h" || subcommands[index] == "--help" { + accountUsage() + } if !strings.HasPrefix(subcommands[index], "--") && validCommand { if index != 0 { subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1 : index]}) @@ -159,12 +165,32 @@ func readSubcommandsAndFlagSets(subcommands []string) []*subcommand { return subcommandsSplit } +func accountUsage() { + fmt.Println("Usage for accounts [COMMAND] [FLAGS], multiple commands can be chained together.") + fmt.Printf("COMMAND: %s\n", accountwallet.CreateAccountCommand) + parseCreateAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.DestroyAccountCommand) + parseDestroyAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.AllotAccountCommand) + parseAllotAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n No flags available.", accountwallet.AllotAccountCommand) +} + func parseCreateAccountFlags(subcommands []string) *accountwallet.CreateAccountParams { flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) alias := flagSet.String("alias", "", "Alias of the account to be created") amount := flagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") + if subcommands == nil { + flagSet.Usage() + + return nil + } + log.Infof("Parsing create account flags, subcommands: %v", subcommands) err := flagSet.Parse(subcommands) @@ -186,6 +212,12 @@ func parseDestroyAccountFlags(subcommands []string) *accountwallet.DestroyAccoun alias := flagSet.String("alias", "", "Alias of the account to be destroyed") + if subcommands == nil { + flagSet.Usage() + + return nil + } + log.Infof("Parsing destroy account flags, subcommands: %v", subcommands) err := flagSet.Parse(subcommands) if err != nil { @@ -206,6 +238,12 @@ func parseAllotAccountFlags(subcommands []string) *accountwallet.AllotAccountPar amount := flagSet.Int("amount", 100, "Amount of mana to allot") from := flagSet.String("from", "", "Alias of the account we allot from, if not specified, we allot from the faucet account") + if subcommands == nil { + flagSet.Usage() + + return nil + } + log.Infof("Parsing allot account flags, subcommands: %v", subcommands) err := flagSet.Parse(subcommands) if err != nil { From 4f86c8ba89ae5eaf83949d983e3e09787d482435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Sun, 1 Oct 2023 15:36:58 +0200 Subject: [PATCH 14/84] Move connector to models --- tools/evil-spammer/{wallet => models}/connector.go | 2 +- tools/evil-spammer/spammer/options.go | 3 ++- tools/evil-spammer/spammer/spammer.go | 7 ++++--- tools/evil-spammer/wallet/evilwallet.go | 11 ++++++----- tools/evil-spammer/wallet/output_manager.go | 9 +++++---- tools/evil-spammer/wallet/wallet.go | 2 +- 6 files changed, 19 insertions(+), 15 deletions(-) rename tools/evil-spammer/{wallet => models}/connector.go (99%) diff --git a/tools/evil-spammer/wallet/connector.go b/tools/evil-spammer/models/connector.go similarity index 99% rename from tools/evil-spammer/wallet/connector.go rename to tools/evil-spammer/models/connector.go index e02c81b00..271bc13ac 100644 --- a/tools/evil-spammer/wallet/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -1,4 +1,4 @@ -package wallet +package models import ( "context" diff --git a/tools/evil-spammer/spammer/options.go b/tools/evil-spammer/spammer/options.go index ec45ce8ca..590763d70 100644 --- a/tools/evil-spammer/spammer/options.go +++ b/tools/evil-spammer/spammer/options.go @@ -3,6 +3,7 @@ package spammer import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" ) @@ -118,7 +119,7 @@ func WithNumberOfSpends(n int) Options { func WithClientURL(clientURL string) Options { return func(s *Spammer) { - s.Clients = wallet.NewWebClients([]string{clientURL}) + s.Clients = models.NewWebClients([]string{clientURL}) } } diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index d95ac4610..3cee97a08 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -12,6 +12,7 @@ import ( "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" iotago "github.com/iotaledger/iota.go/v4" @@ -58,7 +59,7 @@ type Spammer struct { State *State UseRateSetter bool SpamType SpamType - Clients wallet.Connector + Clients models.Connector EvilWallet *wallet.EvilWallet EvilScenario *wallet.EvilScenario IdentityManager *IdentityManager @@ -233,7 +234,7 @@ func (s *Spammer) StopSpamming() { // PostTransaction use provided client to issue a transaction. It chooses API method based on Spammer options. Counts errors, // counts transactions and provides debug logs. -func (s *Spammer) PostTransaction(signedTx *iotago.SignedTransaction, clt wallet.Client) { +func (s *Spammer) PostTransaction(signedTx *iotago.SignedTransaction, clt models.Client) { if signedTx == nil { s.log.Debug(ErrTransactionIsNil) s.ErrCounter.CountError(ErrTransactionIsNil) @@ -269,7 +270,7 @@ func (s *Spammer) PostTransaction(signedTx *iotago.SignedTransaction, clt wallet s.log.Debugf("%s: Last transaction sent, ID: %s, txCount: %d", blockID.ToHex(), txID.ToHex(), count) } -func (s *Spammer) handleSolidityForReuseOutputs(_ wallet.Client, _ *iotago.SignedTransaction) (ok bool) { +func (s *Spammer) handleSolidityForReuseOutputs(_ models.Client, _ *iotago.SignedTransaction) (ok bool) { // ok = s.EvilWallet.AwaitInputsSolidity(tx.SignedTransaction().Inputs(), clt) // if s.EvilScenario.OutputWallet.Type() == wallet.Reuse { // s.EvilWallet.AddReuseOutputsToThePool(tx.SignedTransaction().Outputs()) diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index 02aac5b48..332085bc2 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -12,6 +12,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" "github.com/iotaledger/iota.go/v4/tpkg" @@ -53,7 +54,7 @@ type EvilWallet struct { // faucet is the wallet of faucet faucet *Wallet wallets *Wallets - connector Connector + connector models.Connector outputManager *OutputManager aliasManager *AliasManager @@ -71,7 +72,7 @@ func NewEvilWallet(opts ...options.Option[EvilWallet]) *EvilWallet { optFaucetUnspentOutputID: iotago.OutputIDFromTransactionIDAndIndex(genesisTransactionID, 0), optsClientURLs: defaultClientsURLs, }, opts, func(w *EvilWallet) { - connector := NewWebClients(w.optsClientURLs) + connector := models.NewWebClients(w.optsClientURLs) w.connector = connector clt := w.connector.GetClient() @@ -124,12 +125,12 @@ func (e *EvilWallet) NewWallet(wType ...WalletType) *Wallet { } // GetClients returns the given number of clients. -func (e *EvilWallet) GetClients(num int) []Client { +func (e *EvilWallet) GetClients(num int) []models.Client { return e.connector.GetClients(num) } // Connector give access to the EvilWallet connector. -func (e *EvilWallet) Connector() Connector { +func (e *EvilWallet) Connector() models.Connector { return e.connector } @@ -255,7 +256,7 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *Output, err e faucetAddr := e.faucet.AddressOnIndex(0) unspentFaucet := e.faucet.UnspentOutput(faucetAddr.String()) if unspentFaucet.OutputStruct == nil { - clt := e.connector.GetClient() + clt = e.connector.GetClient() faucetOutput := clt.GetOutput(e.optFaucetUnspentOutputID) if faucetOutput == nil { panic("no valid faucet unspent output") diff --git a/tools/evil-spammer/wallet/output_manager.go b/tools/evil-spammer/wallet/output_manager.go index 559c8521f..e46d992b0 100644 --- a/tools/evil-spammer/wallet/output_manager.go +++ b/tools/evil-spammer/wallet/output_manager.go @@ -8,6 +8,7 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/syncutils" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" ) @@ -36,7 +37,7 @@ type Outputs []*Output // OutputManager keeps track of the output statuses. type OutputManager struct { - connector Connector + connector models.Connector wallets *Wallets outputIDWalletMap map[string]*Wallet @@ -48,7 +49,7 @@ type OutputManager struct { } // NewOutputManager creates an OutputManager instance. -func NewOutputManager(connector Connector, wallets *Wallets) *OutputManager { +func NewOutputManager(connector models.Connector, wallets *Wallets) *OutputManager { return &OutputManager{ connector: connector, wallets: wallets, @@ -326,7 +327,7 @@ func (o *OutputManager) AwaitTransactionToBeAccepted(txID iotago.TransactionID, } // AwaitOutputToBeSolid awaits for solidification of a single output by provided clt. -func (o *OutputManager) AwaitOutputToBeSolid(outID iotago.OutputID, clt Client, waitFor time.Duration) error { +func (o *OutputManager) AwaitOutputToBeSolid(outID iotago.OutputID, clt models.Client, waitFor time.Duration) error { s := time.Now() var solid bool @@ -350,7 +351,7 @@ func (o *OutputManager) AwaitOutputToBeSolid(outID iotago.OutputID, clt Client, } // AwaitOutputsToBeSolid awaits for all provided outputs are solid for a provided client. -func (o *OutputManager) AwaitOutputsToBeSolid(outputs iotago.OutputIDs, clt Client, maxGoroutines int) (allSolid bool) { +func (o *OutputManager) AwaitOutputsToBeSolid(outputs iotago.OutputIDs, clt models.Client, maxGoroutines int) (allSolid bool) { wg := sync.WaitGroup{} semaphore := make(chan bool, maxGoroutines) allSolid = true diff --git a/tools/evil-spammer/wallet/wallet.go b/tools/evil-spammer/wallet/wallet.go index c1c024a81..5a278c9aa 100644 --- a/tools/evil-spammer/wallet/wallet.go +++ b/tools/evil-spammer/wallet/wallet.go @@ -80,7 +80,7 @@ func (w *Wallet) Address() *iotago.Ed25519Address { return addr } -// Address returns a new and unused address of a given wallet. +// AddressOnIndex returns a new and unused address of a given wallet. func (w *Wallet) AddressOnIndex(index uint64) *iotago.Ed25519Address { w.Lock() defer w.Unlock() From defd8ad410e51f2886d1be1f28659494410b464e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Sun, 1 Oct 2023 15:43:20 +0200 Subject: [PATCH 15/84] Move output to models --- tools/evil-spammer/models/output.go | 22 +++++++++++++ .../spammer/spamming_functions.go | 4 +-- tools/evil-spammer/wallet/aliasmanager.go | 25 +++++++------- tools/evil-spammer/wallet/evilwallet.go | 18 +++++----- tools/evil-spammer/wallet/options.go | 9 ++--- tools/evil-spammer/wallet/output_manager.go | 33 ++++--------------- tools/evil-spammer/wallet/wallet.go | 15 +++++---- 7 files changed, 66 insertions(+), 60 deletions(-) create mode 100644 tools/evil-spammer/models/output.go diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go new file mode 100644 index 000000000..e30fd7777 --- /dev/null +++ b/tools/evil-spammer/models/output.go @@ -0,0 +1,22 @@ +package models + +import "github.com/iotaledger/iota.go/v4" + +// Input contains details of an input. +type Input struct { + OutputID iotago.OutputID + Address iotago.Address +} + +// Output contains details of an output ID. +type Output struct { + OutputID iotago.OutputID + Address iotago.Address + Index uint64 + Balance iotago.BaseToken + + OutputStruct iotago.Output +} + +// Outputs is a list of Output. +type Outputs []*Output diff --git a/tools/evil-spammer/spammer/spamming_functions.go b/tools/evil-spammer/spammer/spamming_functions.go index 54a7b0ffb..cf189f381 100644 --- a/tools/evil-spammer/spammer/spamming_functions.go +++ b/tools/evil-spammer/spammer/spamming_functions.go @@ -6,7 +6,7 @@ import ( "time" "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" ) @@ -50,7 +50,7 @@ func CustomConflictSpammingFunc(s *Spammer) { wg := sync.WaitGroup{} for i, tx := range txs { wg.Add(1) - go func(clt wallet.Client, tx *iotago.SignedTransaction) { + go func(clt models.Client, tx *iotago.SignedTransaction) { defer wg.Done() // sleep randomly to avoid issuing blocks in different goroutines at once diff --git a/tools/evil-spammer/wallet/aliasmanager.go b/tools/evil-spammer/wallet/aliasmanager.go index c653c10b0..e08b50d7c 100644 --- a/tools/evil-spammer/wallet/aliasmanager.go +++ b/tools/evil-spammer/wallet/aliasmanager.go @@ -5,14 +5,15 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/syncutils" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" ) // region AliasManager ///////////////////////////////////////////////////////////////////////////////////////////////// // AliasManager is the manager for output aliases. type AliasManager struct { - outputMap map[string]*Output - inputMap map[string]*Output + outputMap map[string]*models.Output + inputMap map[string]*models.Output outputAliasCount *atomic.Uint64 mu syncutils.RWMutex @@ -21,14 +22,14 @@ type AliasManager struct { // NewAliasManager creates and returns a new AliasManager. func NewAliasManager() *AliasManager { return &AliasManager{ - outputMap: make(map[string]*Output), - inputMap: make(map[string]*Output), + outputMap: make(map[string]*models.Output), + inputMap: make(map[string]*models.Output), outputAliasCount: atomic.NewUint64(0), } } // AddOutputAlias maps the given outputAliasName to output, if there's duplicate outputAliasName, it will be overwritten. -func (a *AliasManager) AddOutputAlias(output *Output, aliasName string) { +func (a *AliasManager) AddOutputAlias(output *models.Output, aliasName string) { a.mu.Lock() defer a.mu.Unlock() @@ -36,7 +37,7 @@ func (a *AliasManager) AddOutputAlias(output *Output, aliasName string) { } // AddInputAlias adds an input alias. -func (a *AliasManager) AddInputAlias(input *Output, aliasName string) { +func (a *AliasManager) AddInputAlias(input *models.Output, aliasName string) { a.mu.Lock() defer a.mu.Unlock() @@ -44,7 +45,7 @@ func (a *AliasManager) AddInputAlias(input *Output, aliasName string) { } // GetInput returns the input for the alias specified. -func (a *AliasManager) GetInput(aliasName string) (*Output, bool) { +func (a *AliasManager) GetInput(aliasName string) (*models.Output, bool) { a.mu.RLock() defer a.mu.RUnlock() in, ok := a.inputMap[aliasName] @@ -53,7 +54,7 @@ func (a *AliasManager) GetInput(aliasName string) (*Output, bool) { } // GetOutput returns the output for the alias specified. -func (a *AliasManager) GetOutput(aliasName string) *Output { +func (a *AliasManager) GetOutput(aliasName string) *models.Output { a.mu.RLock() defer a.mu.RUnlock() @@ -65,8 +66,8 @@ func (a *AliasManager) ClearAllAliases() { a.mu.Lock() defer a.mu.Unlock() - a.inputMap = make(map[string]*Output) - a.outputMap = make(map[string]*Output) + a.inputMap = make(map[string]*models.Output) + a.outputMap = make(map[string]*models.Output) } // ClearAliases clears provided aliases. @@ -83,7 +84,7 @@ func (a *AliasManager) ClearAliases(aliases ScenarioAlias) { } // AddOutputAliases batch adds the outputs their respective aliases. -func (a *AliasManager) AddOutputAliases(outputs []*Output, aliases []string) error { +func (a *AliasManager) AddOutputAliases(outputs []*models.Output, aliases []string) error { if len(outputs) != len(aliases) { return ierrors.New("mismatch outputs and aliases length") } @@ -95,7 +96,7 @@ func (a *AliasManager) AddOutputAliases(outputs []*Output, aliases []string) err } // AddInputAliases batch adds the inputs their respective aliases. -func (a *AliasManager) AddInputAliases(inputs []*Output, aliases []string) error { +func (a *AliasManager) AddInputAliases(inputs []*models.Output, aliases []string) error { if len(inputs) != len(aliases) { return ierrors.New("mismatch outputs and aliases length") } diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index 332085bc2..43f099f4a 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -97,7 +97,7 @@ func NewEvilWallet(opts ...options.Option[EvilWallet]) *EvilWallet { } } - w.faucet.AddUnspentOutput(&Output{ + w.faucet.AddUnspentOutput(&models.Output{ Address: w.faucet.AddressOnIndex(0), Index: 0, OutputID: w.optFaucetUnspentOutputID, @@ -249,7 +249,7 @@ func (e *EvilWallet) requestAndSplitFaucetFunds(initWallet, receiveWallet *Walle return e.splitOutputs(splitOutput, initWallet, receiveWallet) } -func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *Output, err error) { +func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *models.Output, err error) { receiveAddr := wallet.AddressOnIndex(0) clt := e.connector.GetClient() @@ -307,7 +307,7 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *Output, err e output := e.outputManager.CreateOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 0), signedTx.Transaction.Outputs[0]) // set remainder output to be reused by the faucet wallet - e.faucet.AddUnspentOutput(&Output{ + e.faucet.AddUnspentOutput(&models.Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 1), Address: faucetAddr, Index: 0, @@ -319,7 +319,7 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *Output, err e } // splitOutputs splits faucet input to 100 outputs. -func (e *EvilWallet) splitOutputs(splitOutput *Output, inputWallet, outputWallet *Wallet) (iotago.TransactionID, error) { +func (e *EvilWallet) splitOutputs(splitOutput *models.Output, inputWallet, outputWallet *Wallet) (iotago.TransactionID, error) { if inputWallet.IsEmpty() { return iotago.TransactionID{}, ierrors.New("inputWallet is empty") } @@ -340,7 +340,7 @@ func (e *EvilWallet) splitOutputs(splitOutput *Output, inputWallet, outputWallet return lo.PanicOnErr(signedTx.ID()), nil } -func (e *EvilWallet) handleInputOutputDuringSplitOutputs(splitOutput *Output, splitNumber int, receiveWallet *Wallet) (input *Output, outputs []*OutputOption) { +func (e *EvilWallet) handleInputOutputDuringSplitOutputs(splitOutput *models.Output, splitNumber int, receiveWallet *Wallet) (input *models.Output, outputs []*OutputOption) { input = splitOutput balances := SplitBalanceEqually(splitNumber, input.Balance) @@ -436,7 +436,7 @@ func (e *EvilWallet) addOutputsToOutputManager(signedTx *iotago.SignedTransactio // register UnlockConditionAddress only (skip account outputs) addr := o.UnlockConditionSet().Address().Address - out := &Output{ + out := &models.Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), uint16(idx)), Address: addr, Balance: o.BaseTokenAmount(), @@ -494,7 +494,7 @@ func (e *EvilWallet) registerOutputAliases(signedTx *iotago.SignedTransaction, a } } -func (e *EvilWallet) prepareInputs(buildOptions *Options) (inputs []*Output, err error) { +func (e *EvilWallet) prepareInputs(buildOptions *Options) (inputs []*models.Output, err error) { if buildOptions.areInputsProvidedWithoutAliases() { inputs = append(inputs, buildOptions.inputs...) @@ -526,7 +526,7 @@ func (e *EvilWallet) prepareOutputs(buildOptions *Options, tempWallet *Wallet) ( // matchInputsWithAliases gets input from the alias manager. if input was not assigned to an alias before, // it assigns a new Fresh faucet output. -func (e *EvilWallet) matchInputsWithAliases(buildOptions *Options) (inputs []*Output, err error) { +func (e *EvilWallet) matchInputsWithAliases(buildOptions *Options) (inputs []*models.Output, err error) { // get inputs by alias for inputAlias := range buildOptions.aliasInputs { in, ok := e.aliasManager.GetInput(inputAlias) @@ -696,7 +696,7 @@ func (e *EvilWallet) updateOutputBalances(buildOptions *Options) (err error) { return } -func (e *EvilWallet) makeTransaction(inputs []*Output, outputs iotago.Outputs[iotago.Output], w *Wallet) (tx *iotago.SignedTransaction, err error) { +func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Outputs[iotago.Output], w *Wallet) (tx *iotago.SignedTransaction, err error) { clt := e.Connector().GetClient() txBuilder := builder.NewTransactionBuilder(clt.CurrentAPI()) diff --git a/tools/evil-spammer/wallet/options.go b/tools/evil-spammer/wallet/options.go index 74a0cd012..8c8d42a99 100644 --- a/tools/evil-spammer/wallet/options.go +++ b/tools/evil-spammer/wallet/options.go @@ -5,6 +5,7 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" ) @@ -14,7 +15,7 @@ import ( // Options is a struct that represents a collection of options that can be set when creating a block. type Options struct { aliasInputs map[string]types.Empty - inputs []*Output + inputs []*models.Output aliasOutputs map[string]iotago.Output outputs []iotago.Output inputWallet *Wallet @@ -37,7 +38,7 @@ type OutputOption struct { func NewOptions(options ...Option) (option *Options, err error) { option = &Options{ aliasInputs: make(map[string]types.Empty), - inputs: make([]*Output, 0), + inputs: make([]*models.Output, 0), aliasOutputs: make(map[string]iotago.Output), outputs: make([]iotago.Output, 0), specialOutputTypes: make(map[string]iotago.OutputType), @@ -131,9 +132,9 @@ func WithInputs(inputs interface{}) Option { for _, input := range in { options.aliasInputs[input] = types.Void } - case *Output: + case *models.Output: options.inputs = append(options.inputs, in) - case []*Output: + case []*models.Output: options.inputs = append(options.inputs, in...) } } diff --git a/tools/evil-spammer/wallet/output_manager.go b/tools/evil-spammer/wallet/output_manager.go index e46d992b0..361f0c29d 100644 --- a/tools/evil-spammer/wallet/output_manager.go +++ b/tools/evil-spammer/wallet/output_manager.go @@ -16,25 +16,6 @@ var ( awaitOutputToBeConfirmed = 150 * time.Second ) -// Input contains details of an input. -type Input struct { - OutputID iotago.OutputID - Address iotago.Address -} - -// Output contains details of an output ID. -type Output struct { - OutputID iotago.OutputID - Address iotago.Address - Index uint64 - Balance iotago.BaseToken - - OutputStruct iotago.Output -} - -// Outputs is a list of Output. -type Outputs []*Output - // OutputManager keeps track of the output statuses. type OutputManager struct { connector models.Connector @@ -143,9 +124,9 @@ func (o *OutputManager) Track(outputIDs ...iotago.OutputID) (allConfirmed bool) // CreateOutputFromAddress creates output, retrieves outputID, and adds it to the wallet. // Provided address should be generated from provided wallet. Considers only first output found on address. -func (o *OutputManager) CreateOutputFromAddress(w *Wallet, addr *iotago.Ed25519Address, balance iotago.BaseToken, outputID iotago.OutputID, outputStruct iotago.Output) *Output { +func (o *OutputManager) CreateOutputFromAddress(w *Wallet, addr *iotago.Ed25519Address, balance iotago.BaseToken, outputID iotago.OutputID, outputStruct iotago.Output) *models.Output { index := w.AddrIndexMap(addr.String()) - out := &Output{ + out := &models.Output{ Address: addr, Index: index, OutputID: outputID, @@ -160,9 +141,9 @@ func (o *OutputManager) CreateOutputFromAddress(w *Wallet, addr *iotago.Ed25519A } // AddOutput adds existing output from wallet w to the OutputManager. -func (o *OutputManager) AddOutput(w *Wallet, output *Output) *Output { +func (o *OutputManager) AddOutput(w *Wallet, output *models.Output) *models.Output { idx := w.AddrIndexMap(output.Address.String()) - out := &Output{ + out := &models.Output{ Address: output.Address, Index: idx, OutputID: output.OutputID, @@ -178,7 +159,7 @@ func (o *OutputManager) AddOutput(w *Wallet, output *Output) *Output { // GetOutput returns the Output of the given outputID. // Firstly checks if output can be retrieved by outputManager from wallet, if not does an API call. -func (o *OutputManager) GetOutput(outputID iotago.OutputID) (output *Output) { +func (o *OutputManager) GetOutput(outputID iotago.OutputID) (output *models.Output) { output = o.getOutputFromWallet(outputID) // get output info via web api @@ -194,7 +175,7 @@ func (o *OutputManager) GetOutput(outputID iotago.OutputID) (output *Output) { return nil } - output = &Output{ + output = &models.Output{ OutputID: outputID, Address: basicOutput.UnlockConditionSet().Address().Address, Balance: basicOutput.BaseTokenAmount(), @@ -205,7 +186,7 @@ func (o *OutputManager) GetOutput(outputID iotago.OutputID) (output *Output) { return output } -func (o *OutputManager) getOutputFromWallet(outputID iotago.OutputID) (output *Output) { +func (o *OutputManager) getOutputFromWallet(outputID iotago.OutputID) (output *models.Output) { o.RLock() defer o.RUnlock() w, ok := o.outputIDWalletMap[outputID.ToHex()] diff --git a/tools/evil-spammer/wallet/wallet.go b/tools/evil-spammer/wallet/wallet.go index 5a278c9aa..3d653686f 100644 --- a/tools/evil-spammer/wallet/wallet.go +++ b/tools/evil-spammer/wallet/wallet.go @@ -8,6 +8,7 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/runtime/syncutils" "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/tpkg" ) @@ -18,7 +19,7 @@ import ( type Wallet struct { ID walletID walletType WalletType - unspentOutputs map[string]*Output // maps addr to its unspentOutput + unspentOutputs map[string]*models.Output // maps addr to its unspentOutput indexAddrMap map[uint64]string addrIndexMap map[string]uint64 inputTransactions map[string]types.Empty @@ -44,7 +45,7 @@ func NewWallet(wType ...WalletType) *Wallet { walletType: walletType, ID: -1, seed: tpkg.RandEd25519Seed(), - unspentOutputs: make(map[string]*Output), + unspentOutputs: make(map[string]*models.Output), indexAddrMap: make(map[uint64]string), addrIndexMap: make(map[string]uint64), inputTransactions: make(map[string]types.Empty), @@ -93,7 +94,7 @@ func (w *Wallet) AddressOnIndex(index uint64) *iotago.Ed25519Address { } // UnspentOutput returns the unspent output on the address. -func (w *Wallet) UnspentOutput(addr string) *Output { +func (w *Wallet) UnspentOutput(addr string) *models.Output { w.RLock() defer w.RUnlock() @@ -101,10 +102,10 @@ func (w *Wallet) UnspentOutput(addr string) *Output { } // UnspentOutputs returns all unspent outputs on the wallet. -func (w *Wallet) UnspentOutputs() (outputs map[string]*Output) { +func (w *Wallet) UnspentOutputs() (outputs map[string]*models.Output) { w.RLock() defer w.RUnlock() - outputs = make(map[string]*Output) + outputs = make(map[string]*models.Output) for addr, outs := range w.unspentOutputs { outputs[addr] = outs } @@ -129,7 +130,7 @@ func (w *Wallet) AddrIndexMap(address string) uint64 { } // AddUnspentOutput adds an unspentOutput of a given wallet. -func (w *Wallet) AddUnspentOutput(output *Output) { +func (w *Wallet) AddUnspentOutput(output *models.Output) { w.Lock() defer w.Unlock() w.unspentOutputs[output.Address.String()] = output @@ -200,7 +201,7 @@ func (w *Wallet) GetReuseAddress() string { } // GetUnspentOutput returns an unspent output on the oldest address ordered by index. -func (w *Wallet) GetUnspentOutput() *Output { +func (w *Wallet) GetUnspentOutput() *models.Output { switch w.walletType { case Reuse: addr := w.GetReuseAddress() From 08c2b946eefe7c94f56fb4f0e35c116150406c2e Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 11:56:14 +0800 Subject: [PATCH 16/84] Fix Output type in wallets --- tools/evil-spammer/wallet/wallets.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/evil-spammer/wallet/wallets.go b/tools/evil-spammer/wallet/wallets.go index bf9fe191c..71445f847 100644 --- a/tools/evil-spammer/wallet/wallets.go +++ b/tools/evil-spammer/wallet/wallets.go @@ -5,6 +5,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/syncutils" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" ) type walletID int @@ -146,7 +147,7 @@ func (w *Wallets) addReuseWallet(wallet *Wallet) { } // GetUnspentOutput gets first found unspent output for a given walletType. -func (w *Wallets) GetUnspentOutput(wallet *Wallet) *Output { +func (w *Wallets) GetUnspentOutput(wallet *Wallet) *models.Output { if wallet == nil { return nil } From 5b085f501f654201bef8c821360130f122664609 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 14:11:25 +0800 Subject: [PATCH 17/84] Load api from webClient --- tools/evil-spammer/accountwallet/config.go | 57 +++++++++++++++++---- tools/evil-spammer/accountwallet/wallet.go | 59 +++++++++++++--------- 2 files changed, 83 insertions(+), 33 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index ac314ec84..bf57f8ade 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -1,12 +1,14 @@ package accountwallet import ( + "encoding/json" "os" "github.com/google/martian/log" "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/runtime/options" iotago "github.com/iotaledger/iota.go/v4" ) @@ -26,9 +28,42 @@ var AvailableCommands = map[string]types.Empty{ ListAccountsCommand: types.Void, } -// TODO how do wee read api -type configuration struct { - WebAPI string `json:"WebAPI,omitempty"` +type Configuration struct { + BindAddress string `json:"bindAddress,omitempty"` +} + +var accountConfigFile = "account_config.json" + +var accountConfigJSON = `{ + "bindAddress": "http://localhost:8080" +}` + +// loadAccountConfig loads the config file. +func loadAccountConfig() *Configuration { + // open config file + config := new(Configuration) + file, err := os.Open(accountConfigFile) + if err != nil { + if !os.IsNotExist(err) { + panic(err) + } + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(accountConfigFile, []byte(accountConfigJSON), 0o644); err != nil { + panic(err) + } + if file, err = os.Open(accountConfigFile); err != nil { + panic(err) + } + } + defer file.Close() + + // decode config file + if err = json.NewDecoder(file).Decode(config); err != nil { + panic(err) + } + + return config } type CreateAccountParams struct { @@ -60,16 +95,18 @@ type Account struct { // TODO: other info of an account } -func loadWallet(filename string, api iotago.API) (wallet *AccountWallet, err error) { +func loadWallet(filename string, opts ...options.Option[AccountWallet]) (wallet *AccountWallet, err error) { + wallet = NewAccountWallet(opts...) + walletStateBytes, err := os.ReadFile(filename) if err != nil { log.Infof("No working wallet file %s found, creating new wallet...", filename) - wallet = NewAccountWallet(api) - } else { - wallet, err = AccountWalletFromBytes(api, walletStateBytes) - if err != nil { - return nil, ierrors.Wrap(err, "failed to create wallet from bytes") - } + return wallet, nil + } + + err = wallet.fromStateDataBytes(walletStateBytes) + if err != nil { + return nil, ierrors.Wrap(err, "failed to create wallet from bytes") } return wallet, nil diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index eea1741ea..4a602fd47 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -5,17 +5,16 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" - "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" ) func Run(walletSourceFile string) (*AccountWallet, error) { - protocolParams := snapshotcreator.NewOptions(presets.Docker...).ProtocolParameters - api := iotago.V3API(protocolParams) + // read config here + config := loadAccountConfig() // load wallet - wallet, err := loadWallet(walletSourceFile, api) + wallet, err := loadWallet(walletSourceFile, WithClientURL(config.BindAddress)) if err != nil { return nil, ierrors.Wrap(err, "failed to load wallet from file") } @@ -25,6 +24,9 @@ func Run(walletSourceFile string) (*AccountWallet, error) { func SaveState(w *AccountWallet, filename string) error { bytesToWrite, err := w.Bytes() + if err != nil { + return ierrors.Wrap(err, "failed to encode wallet state") + } //nolint:gosec // users should be able to read the file if err = os.WriteFile(filename, bytesToWrite, 0o644); err != nil { @@ -41,31 +43,22 @@ type AccountWallet struct { accountsAliases map[string]iotago.AccountID - api iotago.API + client *models.WebClient + api iotago.API + + optsClientBindAddress string } -func NewAccountWallet(api iotago.API, opts ...options.Option[AccountWallet]) *AccountWallet { +func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { return options.Apply(&AccountWallet{ - accountsAliases: make(map[string]iotago.Identifier), - api: api, + accountsAliases: make(map[string]iotago.Identifier), + optsClientBindAddress: "http://localhost:8080", }, opts, func(w *AccountWallet) { - + w.client = models.NewWebClient(w.optsClientBindAddress) + w.api = w.client.CurrentAPI() }) } -func AccountWalletFromBytes(api iotago.API, bytes []byte) (*AccountWallet, error) { - wallet := NewAccountWallet(api) - var data StateData - _, err := wallet.api.Decode(bytes, &data) - if err != nil { - return nil, ierrors.Wrap(err, "failed to decode from file") - } - - //TODO: import the data to Wallet - wallet.fromStateData(data) - return wallet, nil -} - func (a *AccountWallet) Bytes() ([]byte, error) { state := a.toStateData() stateBytes, err := a.api.Encode(state) @@ -96,6 +89,26 @@ func (a *AccountWallet) fromStateData(data StateData) { } } +func (a *AccountWallet) fromStateDataBytes(bytes []byte) error { + var data StateData + _, err := a.api.Decode(bytes, &data) + if err != nil { + return ierrors.Wrap(err, "failed to decode from file") + } + + //TODO: import the data to Wallet + a.fromStateData(data) + + return nil +} + func (a *AccountWallet) getFunds(amount uint64) iotago.Output { return nil } + +// WithClientURL sets the client bind address. +func WithClientURL(url string) options.Option[AccountWallet] { + return func(w *AccountWallet) { + w.optsClientBindAddress = url + } +} From ce3b120ccd3a9734ee6477050d4e07747b1dc9e2 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 14:30:39 +0800 Subject: [PATCH 18/84] Refactor wallet load/write --- tools/evil-spammer/accountwallet/config.go | 29 ++------------ tools/evil-spammer/accountwallet/wallet.go | 45 ++++++++++++++++------ tools/evil-spammer/main.go | 12 ++---- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index bf57f8ade..096bee1ed 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -4,11 +4,7 @@ import ( "encoding/json" "os" - "github.com/google/martian/log" - "github.com/iotaledger/hive.go/ds/types" - "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/hive.go/runtime/options" iotago "github.com/iotaledger/iota.go/v4" ) @@ -29,13 +25,15 @@ var AvailableCommands = map[string]types.Empty{ } type Configuration struct { - BindAddress string `json:"bindAddress,omitempty"` + BindAddress string `json:"bindAddress,omitempty"` + AccountStatesFile string `json:"accountStatesFile,omitempty"` } var accountConfigFile = "account_config.json" var accountConfigJSON = `{ - "bindAddress": "http://localhost:8080" + "bindAddress": "http://localhost:8080", + "accountStatesFile": "wallet.LOCK" }` // loadAccountConfig loads the config file. @@ -82,8 +80,6 @@ type AllotAccountParams struct { } // TODO do wee need to restrict that only one instance of the wallet runs? -const lockFile = "wallet.LOCK" - type StateData struct { Accounts []Account `serix:"0,mapKey=accounts,lengthPrefixType=uint8"` // TODO: other info that the account wallet needs to store @@ -94,20 +90,3 @@ type Account struct { AccountID iotago.AccountID `serix:"1,mapKey=accountID"` // TODO: other info of an account } - -func loadWallet(filename string, opts ...options.Option[AccountWallet]) (wallet *AccountWallet, err error) { - wallet = NewAccountWallet(opts...) - - walletStateBytes, err := os.ReadFile(filename) - if err != nil { - log.Infof("No working wallet file %s found, creating new wallet...", filename) - return wallet, nil - } - - err = wallet.fromStateDataBytes(walletStateBytes) - if err != nil { - return nil, ierrors.Wrap(err, "failed to create wallet from bytes") - } - - return wallet, nil -} diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 4a602fd47..f44864d99 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -9,12 +9,22 @@ import ( iotago "github.com/iotaledger/iota.go/v4" ) -func Run(walletSourceFile string) (*AccountWallet, error) { +func Run() (*AccountWallet, error) { // read config here config := loadAccountConfig() + var opts []options.Option[AccountWallet] + if config.BindAddress != "" { + opts = append(opts, WithClientURL(config.BindAddress)) + } + if config.AccountStatesFile != "" { + opts = append(opts, WithAccountStatesFile(config.AccountStatesFile)) + } + + wallet := NewAccountWallet(opts...) + // load wallet - wallet, err := loadWallet(walletSourceFile, WithClientURL(config.BindAddress)) + err := wallet.fromAccountStateFile() if err != nil { return nil, ierrors.Wrap(err, "failed to load wallet from file") } @@ -22,14 +32,14 @@ func Run(walletSourceFile string) (*AccountWallet, error) { return wallet, nil } -func SaveState(w *AccountWallet, filename string) error { +func SaveState(w *AccountWallet) error { bytesToWrite, err := w.Bytes() if err != nil { return ierrors.Wrap(err, "failed to encode wallet state") } //nolint:gosec // users should be able to read the file - if err = os.WriteFile(filename, bytesToWrite, 0o644); err != nil { + if err = os.WriteFile(w.optsAccountStatesFile, bytesToWrite, 0o644); err != nil { return ierrors.Wrap(err, "failed to write account file") } @@ -47,12 +57,14 @@ type AccountWallet struct { api iotago.API optsClientBindAddress string + optsAccountStatesFile string } func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { return options.Apply(&AccountWallet{ accountsAliases: make(map[string]iotago.Identifier), optsClientBindAddress: "http://localhost:8080", + optsAccountStatesFile: "wallet.dat", }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() @@ -83,21 +95,24 @@ func (a *AccountWallet) toStateData() *StateData { return &StateData{Accounts: accounts} } -func (a *AccountWallet) fromStateData(data StateData) { - for _, acc := range data.Accounts { - a.accountsAliases[acc.Alias] = acc.AccountID +func (a *AccountWallet) fromAccountStateFile() error { + walletStateBytes, err := os.ReadFile(a.optsAccountStatesFile) + if err != nil { + if !os.IsNotExist(err) { + return ierrors.Wrap(err, "failed to read file") + } + return nil } -} -func (a *AccountWallet) fromStateDataBytes(bytes []byte) error { var data StateData - _, err := a.api.Decode(bytes, &data) + _, err = a.api.Decode(walletStateBytes, &data) if err != nil { return ierrors.Wrap(err, "failed to decode from file") } - //TODO: import the data to Wallet - a.fromStateData(data) + for _, acc := range data.Accounts { + a.accountsAliases[acc.Alias] = acc.AccountID + } return nil } @@ -112,3 +127,9 @@ func WithClientURL(url string) options.Option[AccountWallet] { w.optsClientBindAddress = url } } + +func WithAccountStatesFile(fileName string) options.Option[AccountWallet] { + return func(w *AccountWallet) { + w.optsAccountStatesFile = fileName + } +} diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 13c81859c..3527c2b7c 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -10,10 +10,6 @@ import ( "github.com/iotaledger/iota-core/tools/evil-spammer/programs" ) -const ( - accountWalletFilename = "wallet.dat" -) - var ( log = logger.New("main") optionFlagSet = flag.NewFlagSet("script flag set", flag.ExitOnError) @@ -39,18 +35,18 @@ func main() { programs.CustomSpam(&customSpamParams) case "accounts": // load wallet - accWallet, err := accountwallet.Run(accountWalletFilename) + accWallet, err := accountwallet.Run() if err != nil { log.Warn(err) return } // save wallet - defer func(w *accountwallet.AccountWallet, filename string) { - err = accountwallet.SaveState(w, filename) + defer func(w *accountwallet.AccountWallet) { + err = accountwallet.SaveState(w) if err != nil { log.Errorf("Error while saving wallet state: %v", err) } - }(accWallet, "wallet.dat") + }(accWallet) accountsSubcommands(accWallet, accountsSubcommandsFlags) case "quick": programs.QuickTest(&quickTestParams) From be3d697ae4350ede8207c1108b2b789702f3fa02 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 14:41:53 +0800 Subject: [PATCH 19/84] Refactor write account states to file --- tools/evil-spammer/accountwallet/wallet.go | 38 ++++++++-------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index f44864d99..7970ebc99 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -33,17 +33,7 @@ func Run() (*AccountWallet, error) { } func SaveState(w *AccountWallet) error { - bytesToWrite, err := w.Bytes() - if err != nil { - return ierrors.Wrap(err, "failed to encode wallet state") - } - - //nolint:gosec // users should be able to read the file - if err = os.WriteFile(w.optsAccountStatesFile, bytesToWrite, 0o644); err != nil { - return ierrors.Wrap(err, "failed to write account file") - } - - return nil + return w.toAccountStateFile() } type AccountWallet struct { @@ -71,18 +61,8 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { }) } -func (a *AccountWallet) Bytes() ([]byte, error) { - state := a.toStateData() - stateBytes, err := a.api.Encode(state) - if err != nil { - return nil, ierrors.Wrap(err, "failed to encode state") - } - - return stateBytes, nil -} - -// toStateData converts accounts information to ToAccountData -func (a *AccountWallet) toStateData() *StateData { +// toAccountStateFile write account states to file. +func (a *AccountWallet) toAccountStateFile() error { accounts := make([]Account, 0) for alias, acc := range a.accountsAliases { @@ -92,7 +72,17 @@ func (a *AccountWallet) toStateData() *StateData { }) } - return &StateData{Accounts: accounts} + stateBytes, err := a.api.Encode(&StateData{Accounts: accounts}) + if err != nil { + return ierrors.Wrap(err, "failed to encode state") + } + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(a.optsAccountStatesFile, stateBytes, 0o644); err != nil { + return ierrors.Wrap(err, "failed to write account states to file") + } + + return nil } func (a *AccountWallet) fromAccountStateFile() error { From 85418323b175ab595a52f78bd0ebe877a1922118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 2 Oct 2023 10:25:07 +0200 Subject: [PATCH 20/84] Fix help flags --- tools/evil-spammer/parse.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index d2a0b2a9b..e84c1b121 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -147,11 +147,15 @@ func readSubcommandsAndFlagSets(subcommands []string) []*subcommand { subcommandsSplit := make([]*subcommand, 0) if len(subcommands) == 0 { accountUsage() + + return nil } for index := 0; index < len(subcommands); index++ { _, validCommand := accountwallet.AvailableCommands[subcommands[index]] if subcommands[index] == "-h" || subcommands[index] == "--help" { accountUsage() + + return nil } if !strings.HasPrefix(subcommands[index], "--") && validCommand { if index != 0 { From 0333dbb2f001c229e5e0452c5aeacc51315ca0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 2 Oct 2023 12:28:08 +0200 Subject: [PATCH 21/84] Request faucet funds for basic output --- tools/evil-spammer/accountwallet/commands.go | 11 +- tools/evil-spammer/accountwallet/config.go | 14 +++ tools/evil-spammer/accountwallet/faucet.go | 125 +++++++++++++++++++ tools/evil-spammer/accountwallet/wallet.go | 45 +++++-- tools/evil-spammer/config.go | 5 +- tools/evil-spammer/main.go | 7 +- tools/evil-spammer/parse.go | 7 ++ 7 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 tools/evil-spammer/accountwallet/faucet.go diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go index c10492a7e..f816d71af 100644 --- a/tools/evil-spammer/accountwallet/commands.go +++ b/tools/evil-spammer/accountwallet/commands.go @@ -1,9 +1,14 @@ package accountwallet +import ( + "fmt" + + iotago "github.com/iotaledger/iota.go/v4" +) + func (a *AccountWallet) CreateAccount(params *CreateAccountParams) error { - //input := a.getFunds(params.Amount) - //txBuilder := builder.NewTransactionBuilder(a.api) - //txBuilder.AddInput(input) + out := a.getFunds(params.Amount, iotago.AddressImplicitAccountCreation) + fmt.Printf("Created account %s with %d tokens\n", out.Address, params.Amount) return nil } diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 096bee1ed..ab2eff2d5 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -2,8 +2,11 @@ package accountwallet import ( "encoding/json" + "fmt" "os" + "github.com/mr-tron/base58/base58" + "github.com/iotaledger/hive.go/ds/types" iotago "github.com/iotaledger/iota.go/v4" ) @@ -90,3 +93,14 @@ type Account struct { AccountID iotago.AccountID `serix:"1,mapKey=accountID"` // TODO: other info of an account } + +var dockerFaucetSeed = func() []byte { + genesisSeed, err := base58.Decode("7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih") + if err != nil { + fmt.Printf("failed to decode base58 seed, using the default one: %v", err) + } + + return genesisSeed +} + +var genesisTransactionID = iotago.SlotIdentifierRepresentingData(0, []byte("genesis")) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go new file mode 100644 index 000000000..3491c05e3 --- /dev/null +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -0,0 +1,125 @@ +package accountwallet + +import ( + "sync" + "time" + + "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" + iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/builder" +) + +type Faucet struct { + facuetAddress *iotago.Ed25519Address + seed []byte + faucerAddr *iotago.Ed25519Address + clt models.Client + + unspentOutput *models.Output + + sync.Mutex +} + +func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet { + //get faucet output and amount + var faucetAmount iotago.BaseToken + + faucetOutput := clt.GetOutput(faucetUnspentOutputID) + if faucetOutput != nil { + faucetAmount = faucetOutput.BaseTokenAmount() + } else { + // use the genesis output ID instead, if we relaunch the docker network + faucetUnspentOutputID = iotago.OutputIDFromTransactionIDAndIndex(genesisTransactionID, 0) + faucetOutput = clt.GetOutput(faucetUnspentOutputID) + if faucetOutput != nil { + faucetAmount = faucetOutput.BaseTokenAmount() + } + } + + f := &Faucet{ + seed: dockerFaucetSeed(), + clt: clt, + } + + hdWallet := mock.NewHDWallet("", f.seed[:], 0) + f.facuetAddress = hdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address) + f.unspentOutput = &models.Output{ + Address: f.faucerAddr, + Index: 0, + OutputID: faucetUnspentOutputID, + Balance: faucetAmount, + OutputStruct: faucetOutput, + } + + return f +} + +func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { + remainderAmount := f.unspentOutput.Balance - amount + + txBuilder := builder.NewTransactionBuilder(f.clt.CurrentAPI()) + + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: f.facuetAddress, + InputID: f.unspentOutput.OutputID, + Input: f.unspentOutput.OutputStruct, + }) + + // receiver output + txBuilder.AddOutput(&iotago.BasicOutput{ + Amount: amount, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: receiveAddr}, + }, + }) + + // remainder output + txBuilder.AddOutput(&iotago.BasicOutput{ + Amount: remainderAmount, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: f.facuetAddress}, + }, + }) + + txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) + txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) + + hdWallet := mock.NewHDWallet("", f.seed[:], 0) + + signedTx, err := txBuilder.Build(hdWallet.AddressSigner()) + if err != nil { + return nil, err + } + + // send transaction + _, err = f.clt.PostTransaction(signedTx) + if err != nil { + return nil, err + } + + // set remainder output to be reused by the faucet wallet + f.unspentOutput = &models.Output{ + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 1), + Address: f.facuetAddress, + Index: 0, + Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), + OutputStruct: signedTx.Transaction.Outputs[1], + } + + // TODO handle implicit acc creation + //switch receiveAddr.(type) { + //case *iotago.Ed25519Address: + //case *iotago.ImplicitAccountCreationAddress: + // + //} + + return &models.Output{ + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 0), + Address: receiveAddr, + Index: 0, + Balance: signedTx.Transaction.Outputs[0].BaseTokenAmount(), + OutputStruct: signedTx.Transaction.Outputs[0], + }, nil +} diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 7970ebc99..c69c448b8 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -5,11 +5,13 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/tpkg" ) -func Run() (*AccountWallet, error) { +func Run(lastFaucetUnspentOutputID iotago.OutputID) (*AccountWallet, error) { // read config here config := loadAccountConfig() @@ -21,6 +23,8 @@ func Run() (*AccountWallet, error) { opts = append(opts, WithAccountStatesFile(config.AccountStatesFile)) } + opts = append(opts, WithFaucetUnspendOutputID(lastFaucetUnspentOutputID)) + wallet := NewAccountWallet(opts...) // load wallet @@ -37,27 +41,29 @@ func SaveState(w *AccountWallet) error { } type AccountWallet struct { - // TODO can we reuse faucet requests from evil wallet? - // faucetFunds map[string]*Output - seed [32]byte + faucet *Faucet + seed [32]byte accountsAliases map[string]iotago.AccountID + latestUsedIndex uint64 + aliasIndexMap map[string]uint64 client *models.WebClient api iotago.API - optsClientBindAddress string - optsAccountStatesFile string + optsClientBindAddress string + optsAccountStatesFile string + optsFaucetUnspendOutputID iotago.OutputID } func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { return options.Apply(&AccountWallet{ - accountsAliases: make(map[string]iotago.Identifier), - optsClientBindAddress: "http://localhost:8080", - optsAccountStatesFile: "wallet.dat", + accountsAliases: make(map[string]iotago.Identifier), + seed: tpkg.RandEd25519Seed(), }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() + w.faucet = NewFaucet(w.client, w.optsFaucetUnspendOutputID) }) } @@ -107,8 +113,19 @@ func (a *AccountWallet) fromAccountStateFile() error { return nil } -func (a *AccountWallet) getFunds(amount uint64) iotago.Output { - return nil +func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) *models.Output { + hdWallet := mock.NewHDWallet("", a.seed[:], a.latestUsedIndex+1) + + receiverAddr := hdWallet.Address(addressType) + createdOutput, err := a.faucet.RequestFunds(receiverAddr, iotago.BaseToken(amount)) + if err != nil { + panic(err) + } + + a.latestUsedIndex++ + createdOutput.Index = a.latestUsedIndex + + return createdOutput } // WithClientURL sets the client bind address. @@ -123,3 +140,9 @@ func WithAccountStatesFile(fileName string) options.Option[AccountWallet] { w.optsAccountStatesFile = fileName } } + +func WithFaucetUnspendOutputID(id iotago.OutputID) options.Option[AccountWallet] { + return func(w *AccountWallet) { + w.optsFaucetUnspendOutputID = id + } +} diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index 13f2dc81d..d1ddef3eb 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -6,6 +6,7 @@ import ( "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" + iotago "github.com/iotaledger/iota.go/v4" ) // Nodes used during the test, use at least two nodes to be able to doublespend. @@ -42,7 +43,9 @@ var ( EnableRateSetter: false, } - accountsSubcommandsFlags = make([]*subcommand, 0) + accountsSubcommandsFlags = make([]*subcommand, 0) + lastFaucetUnspendOutputID iotago.OutputID + //nolint:godot // commitmentsSpamParams = CommitmentsSpamParams{ // Rate: 1, diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 3527c2b7c..89139a89e 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -35,18 +35,19 @@ func main() { programs.CustomSpam(&customSpamParams) case "accounts": // load wallet - accWallet, err := accountwallet.Run() + accWallet, err := accountwallet.Run(lastFaucetUnspendOutputID) if err != nil { log.Warn(err) return } // save wallet - defer func(w *accountwallet.AccountWallet) { + defer func(w *accountwallet.AccountWallet, filename string) { err = accountwallet.SaveState(w) if err != nil { log.Errorf("Error while saving wallet state: %v", err) } - }(accWallet) + }(accWallet, "wallet.dat") + accountsSubcommands(accWallet, accountsSubcommandsFlags) case "quick": programs.QuickTest(&quickTestParams) diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index e84c1b121..8eb02e0ad 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -11,6 +11,7 @@ import ( "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" + iotago "github.com/iotaledger/iota.go/v4" ) func parseFlags() (help bool) { @@ -32,6 +33,12 @@ func parseFlags() (help bool) { subcommands = os.Args[2:] } accountsSubcommandsFlags = readSubcommandsAndFlagSets(subcommands) + basicConfig := programs.LoadBasicConfig() + outputID, err := iotago.OutputIDFromHex(basicConfig.LastFaucetUnspentOutputID) + if err != nil { + log.Warnf("Cannot parse faucet output id from config: %v", err) + } + lastFaucetUnspendOutputID = outputID case "quick": parseQuickTestFlags() // case SpammerTypeCommitments: From 5902b3089930d1d306d0609036467d63c2f684a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 2 Oct 2023 13:04:13 +0200 Subject: [PATCH 22/84] Use account builder and implicit account --- tools/evil-spammer/accountwallet/faucet.go | 37 ++++++++++++++-------- tools/evil-spammer/accountwallet/wallet.go | 3 ++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 3491c05e3..ccd2ae3d4 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -67,13 +67,25 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke Input: f.unspentOutput.OutputStruct, }) - // receiver output - txBuilder.AddOutput(&iotago.BasicOutput{ - Amount: amount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: receiveAddr}, - }, - }) + switch receiveAddr.(type) { + case *iotago.Ed25519Address: + txBuilder.AddOutput(&iotago.BasicOutput{ + Amount: amount, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: receiveAddr}, + }, + }) + case *iotago.ImplicitAccountCreationAddress: + log.Infof("creating account %s", receiveAddr) + accOutputBuilder := builder.NewAccountOutputBuilder(receiveAddr, receiveAddr, amount) + output, err := accOutputBuilder.Build() + if err != nil { + log.Errorf("failed to build account output: %s", err) + + return nil, err + } + txBuilder.AddOutput(output) + } // remainder output txBuilder.AddOutput(&iotago.BasicOutput{ @@ -90,12 +102,16 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke signedTx, err := txBuilder.Build(hdWallet.AddressSigner()) if err != nil { + log.Errorf("failed to build transaction: %s", err) + return nil, err } // send transaction _, err = f.clt.PostTransaction(signedTx) if err != nil { + log.Errorf("failed to post transaction: %s", err) + return nil, err } @@ -108,13 +124,6 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke OutputStruct: signedTx.Transaction.Outputs[1], } - // TODO handle implicit acc creation - //switch receiveAddr.(type) { - //case *iotago.Ed25519Address: - //case *iotago.ImplicitAccountCreationAddress: - // - //} - return &models.Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 0), Address: receiveAddr, diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index c69c448b8..533cb405d 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -6,11 +6,14 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/tpkg" ) +var log = logger.New("AccountWallet") + func Run(lastFaucetUnspentOutputID iotago.OutputID) (*AccountWallet, error) { // read config here config := loadAccountConfig() From 6450362870128c5dbc6e4bb303f069379e598794 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 20:09:40 +0800 Subject: [PATCH 23/84] Finish createAccount --- tools/evil-spammer/accountwallet/commands.go | 16 ++++++++++++---- tools/evil-spammer/accountwallet/faucet.go | 1 - tools/evil-spammer/accountwallet/wallet.go | 6 +++--- tools/evil-spammer/main.go | 3 ++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go index f816d71af..c9b265865 100644 --- a/tools/evil-spammer/accountwallet/commands.go +++ b/tools/evil-spammer/accountwallet/commands.go @@ -3,14 +3,22 @@ package accountwallet import ( "fmt" + "github.com/iotaledger/hive.go/ierrors" iotago "github.com/iotaledger/iota.go/v4" ) -func (a *AccountWallet) CreateAccount(params *CreateAccountParams) error { - out := a.getFunds(params.Amount, iotago.AddressImplicitAccountCreation) - fmt.Printf("Created account %s with %d tokens\n", out.Address, params.Amount) +func (a *AccountWallet) CreateAccount(params *CreateAccountParams) (iotago.AccountID, error) { + accountOutput, err := a.getFunds(params.Amount, iotago.AddressImplicitAccountCreation) + if err != nil { + return iotago.EmptyAccountID(), ierrors.Wrap(err, "Failed to create account") + } - return nil + accountID := iotago.AccountAddressFromOutputID(accountOutput.OutputID).AccountID() + a.accountsAliases[params.Alias] = accountID + a.aliasIndexMap[params.Alias] = a.latestUsedIndex + fmt.Printf("Created account %s with %d tokens\n", accountID.ToHex(), params.Amount) + + return accountID, nil } func (a *AccountWallet) DestroyAccount(params *DestroyAccountParams) error { diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index ccd2ae3d4..c7b79ac2f 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -99,7 +99,6 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) hdWallet := mock.NewHDWallet("", f.seed[:], 0) - signedTx, err := txBuilder.Build(hdWallet.AddressSigner()) if err != nil { log.Errorf("failed to build transaction: %s", err) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 533cb405d..3b77752f3 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -116,19 +116,19 @@ func (a *AccountWallet) fromAccountStateFile() error { return nil } -func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) *models.Output { +func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) (*models.Output, error) { hdWallet := mock.NewHDWallet("", a.seed[:], a.latestUsedIndex+1) receiverAddr := hdWallet.Address(addressType) createdOutput, err := a.faucet.RequestFunds(receiverAddr, iotago.BaseToken(amount)) if err != nil { - panic(err) + return nil, ierrors.Wrap(err, "failed to request funds from faucet") } a.latestUsedIndex++ createdOutput.Index = a.latestUsedIndex - return createdOutput + return createdOutput, nil } // WithClientURL sets the client bind address. diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 89139a89e..1eea2e44b 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -69,12 +69,13 @@ func accountsSubcommand(wallet *accountwallet.AccountWallet, sub *subcommand) { case accountwallet.CreateAccountCommand: params := parseCreateAccountFlags(sub.flags) log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.CreateAccountCommand, params) - err := wallet.CreateAccount(params) + accountID, err := wallet.CreateAccount(params) if err != nil { log.Errorf("Error creating account: %v", err) return } + log.Infof("Created account %s with %d tokens", accountID, params.Amount) case accountwallet.DestroyAccountCommand: params := parseDestroyAccountFlags(sub.flags) log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.DestroyAccountCommand, params) From 62d27a3133f754a3e0f4f62e99902576ed3e0fb3 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 20:31:23 +0800 Subject: [PATCH 24/84] Save faucet unspentOutputID --- tools/evil-spammer/accountwallet/wallet.go | 4 ++++ tools/evil-spammer/main.go | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 3b77752f3..93d5600f3 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -70,6 +70,10 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { }) } +func (a *AccountWallet) LastFaucetUnspentOutputID() iotago.OutputID { + return a.faucet.unspentOutput.OutputID +} + // toAccountStateFile write account states to file. func (a *AccountWallet) toAccountStateFile() error { accounts := make([]Account, 0) diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 1eea2e44b..a8fd54532 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -62,6 +62,11 @@ func accountsSubcommands(wallet *accountwallet.AccountWallet, subcommands []*sub for _, sub := range subcommands { accountsSubcommand(wallet, sub) } + + // save faucet unspent output id + programs.SaveConfigsToFile(&programs.BasicConfig{ + LastFaucetUnspentOutputID: wallet.LastFaucetUnspentOutputID().ToHex(), + }) } func accountsSubcommand(wallet *accountwallet.AccountWallet, sub *subcommand) { From 82309620e5d39a5a69c1c7ead7833df4be6d6492 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 20:43:08 +0800 Subject: [PATCH 25/84] Sketch the flow of destroying an account --- tools/evil-spammer/accountwallet/commands.go | 2 +- tools/evil-spammer/accountwallet/wallet.go | 44 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go index c9b265865..97b3af5de 100644 --- a/tools/evil-spammer/accountwallet/commands.go +++ b/tools/evil-spammer/accountwallet/commands.go @@ -22,7 +22,7 @@ func (a *AccountWallet) CreateAccount(params *CreateAccountParams) (iotago.Accou } func (a *AccountWallet) DestroyAccount(params *DestroyAccountParams) error { - return nil + return a.destroyAccount(params.AccountAlias) } func (a *AccountWallet) ListAccount() error { diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 93d5600f3..b6f94be9a 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -9,6 +9,7 @@ import ( "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/builder" "github.com/iotaledger/iota.go/v4/tpkg" ) @@ -135,6 +136,49 @@ func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) return createdOutput, nil } +func (a *AccountWallet) destroyAccount(alias string) error { + if _, ok := a.accountsAliases[alias]; !ok { + return ierrors.Errorf("account with alias %s does not exist", alias) + } + hdWallet := mock.NewHDWallet("", a.seed[:], a.aliasIndexMap[alias]) + + // get output from node + // From TIP42: Indexers and node plugins shall map the account address of the output derived with Account ID to the regular address -> output mapping table, so that given an Account Address, its most recent unspent account output can be retrieved. + // TODO: use correct outputID + accountOutput := a.client.GetOutput(iotago.EmptyOutputID) + + txBuilder := builder.NewTransactionBuilder(a.api) + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: a.accountsAliases[alias].ToAddress(), + // InputID: accountOutput.ID(), + Input: accountOutput, + }) + + // send all tokens to faucet + txBuilder.AddOutput(&iotago.BasicOutput{ + Amount: accountOutput.BaseTokenAmount(), + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: a.faucet.facuetAddress}, + }, + }) + + tx, err := txBuilder.Build(hdWallet.AddressSigner()) + if err != nil { + return ierrors.Wrap(err, "failed to build transaction") + } + + _, err = a.client.PostTransaction(tx) + if err != nil { + return ierrors.Wrap(err, "failed to post transaction") + } + + // remove account from wallet + delete(a.accountsAliases, alias) + delete(a.aliasIndexMap, alias) + + return nil +} + // WithClientURL sets the client bind address. func WithClientURL(url string) options.Option[AccountWallet] { return func(w *AccountWallet) { From d8840b0d2e51438580a343d35bb68bf0487bf7a5 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 20:49:30 +0800 Subject: [PATCH 26/84] Add index and seed to AccountStateData --- tools/evil-spammer/accountwallet/config.go | 4 +++- tools/evil-spammer/accountwallet/wallet.go | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index ab2eff2d5..52100098b 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -84,13 +84,15 @@ type AllotAccountParams struct { // TODO do wee need to restrict that only one instance of the wallet runs? type StateData struct { - Accounts []Account `serix:"0,mapKey=accounts,lengthPrefixType=uint8"` + Seed string `serix:"0,mapKey=seed"` + Accounts []Account `serix:"1,mapKey=accounts,lengthPrefixType=uint8"` // TODO: other info that the account wallet needs to store } type Account struct { Alias string `serix:"0,mapKey=alias"` AccountID iotago.AccountID `serix:"1,mapKey=accountID"` + Index uint64 `serix:"2,mapKey=index"` // TODO: other info of an account } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index b6f94be9a..0edf3b25d 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -11,6 +11,7 @@ import ( iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" "github.com/iotaledger/iota.go/v4/tpkg" + "github.com/mr-tron/base58" ) var log = logger.New("AccountWallet") @@ -83,10 +84,14 @@ func (a *AccountWallet) toAccountStateFile() error { accounts = append(accounts, Account{ Alias: alias, AccountID: acc, + Index: a.aliasIndexMap[alias], }) } - stateBytes, err := a.api.Encode(&StateData{Accounts: accounts}) + stateBytes, err := a.api.Encode(&StateData{ + Seed: base58.Encode(a.seed[:]), + Accounts: accounts, + }) if err != nil { return ierrors.Wrap(err, "failed to encode state") } @@ -114,8 +119,17 @@ func (a *AccountWallet) fromAccountStateFile() error { return ierrors.Wrap(err, "failed to decode from file") } + // copy seeds + decodedSeeds, err := base58.Decode(data.Seed) + if err != nil { + return ierrors.Wrap(err, "failed to decode seed") + } + copy(a.seed[:], decodedSeeds) + + // account data for _, acc := range data.Accounts { a.accountsAliases[acc.Alias] = acc.AccountID + a.aliasIndexMap[acc.Alias] = acc.Index } return nil From 4b9dfdfc6ffbf948a8d780bdfa46f5b03fcde0d8 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 20:51:56 +0800 Subject: [PATCH 27/84] Move accountWallet options to options.go --- tools/evil-spammer/accountwallet/options.go | 25 +++++++++++++++++++++ tools/evil-spammer/accountwallet/wallet.go | 19 ---------------- 2 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 tools/evil-spammer/accountwallet/options.go diff --git a/tools/evil-spammer/accountwallet/options.go b/tools/evil-spammer/accountwallet/options.go new file mode 100644 index 000000000..02f63c174 --- /dev/null +++ b/tools/evil-spammer/accountwallet/options.go @@ -0,0 +1,25 @@ +package accountwallet + +import ( + "github.com/iotaledger/hive.go/runtime/options" + iotago "github.com/iotaledger/iota.go/v4" +) + +// WithClientURL sets the client bind address. +func WithClientURL(url string) options.Option[AccountWallet] { + return func(w *AccountWallet) { + w.optsClientBindAddress = url + } +} + +func WithAccountStatesFile(fileName string) options.Option[AccountWallet] { + return func(w *AccountWallet) { + w.optsAccountStatesFile = fileName + } +} + +func WithFaucetUnspendOutputID(id iotago.OutputID) options.Option[AccountWallet] { + return func(w *AccountWallet) { + w.optsFaucetUnspendOutputID = id + } +} diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 0edf3b25d..c04e1ed32 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -192,22 +192,3 @@ func (a *AccountWallet) destroyAccount(alias string) error { return nil } - -// WithClientURL sets the client bind address. -func WithClientURL(url string) options.Option[AccountWallet] { - return func(w *AccountWallet) { - w.optsClientBindAddress = url - } -} - -func WithAccountStatesFile(fileName string) options.Option[AccountWallet] { - return func(w *AccountWallet) { - w.optsAccountStatesFile = fileName - } -} - -func WithFaucetUnspendOutputID(id iotago.OutputID) options.Option[AccountWallet] { - return func(w *AccountWallet) { - w.optsFaucetUnspendOutputID = id - } -} From 1724b2f930d4b78758234b7efcbedbac178da6bb Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Mon, 2 Oct 2023 20:54:54 +0800 Subject: [PATCH 28/84] Write/Read lastUsedIndex to AccountStateData --- tools/evil-spammer/accountwallet/config.go | 5 +++-- tools/evil-spammer/accountwallet/wallet.go | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 52100098b..360bc660d 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -84,8 +84,9 @@ type AllotAccountParams struct { // TODO do wee need to restrict that only one instance of the wallet runs? type StateData struct { - Seed string `serix:"0,mapKey=seed"` - Accounts []Account `serix:"1,mapKey=accounts,lengthPrefixType=uint8"` + Seed string `serix:"0,mapKey=seed"` + LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` + Accounts []Account `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` // TODO: other info that the account wallet needs to store } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index c04e1ed32..ff4057336 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -89,8 +89,9 @@ func (a *AccountWallet) toAccountStateFile() error { } stateBytes, err := a.api.Encode(&StateData{ - Seed: base58.Encode(a.seed[:]), - Accounts: accounts, + Seed: base58.Encode(a.seed[:]), + LastUsedIndex: a.latestUsedIndex, + Accounts: accounts, }) if err != nil { return ierrors.Wrap(err, "failed to encode state") @@ -126,6 +127,9 @@ func (a *AccountWallet) fromAccountStateFile() error { } copy(a.seed[:], decodedSeeds) + // set latest used index + a.latestUsedIndex = data.LastUsedIndex + // account data for _, acc := range data.Accounts { a.accountsAliases[acc.Alias] = acc.AccountID From 014005f39f8c82da42fa228bf43fb2dbebb98d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 2 Oct 2023 16:12:24 +0200 Subject: [PATCH 29/84] Add wait for account commitment method and refactor accountData --- tools/evil-spammer/accountwallet/commands.go | 5 +- tools/evil-spammer/accountwallet/config.go | 16 +-- tools/evil-spammer/accountwallet/wallet.go | 109 +++++++++++++++---- tools/evil-spammer/models/output.go | 12 +- 4 files changed, 106 insertions(+), 36 deletions(-) diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go index 97b3af5de..ceae55ba4 100644 --- a/tools/evil-spammer/accountwallet/commands.go +++ b/tools/evil-spammer/accountwallet/commands.go @@ -13,9 +13,8 @@ func (a *AccountWallet) CreateAccount(params *CreateAccountParams) (iotago.Accou return iotago.EmptyAccountID(), ierrors.Wrap(err, "Failed to create account") } - accountID := iotago.AccountAddressFromOutputID(accountOutput.OutputID).AccountID() - a.accountsAliases[params.Alias] = accountID - a.aliasIndexMap[params.Alias] = a.latestUsedIndex + accountID := a.registerAccount(params.Alias, accountOutput.OutputID, a.latestUsedIndex) + fmt.Printf("Created account %s with %d tokens\n", accountID.ToHex(), params.Amount) return accountID, nil diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 360bc660d..1913316ca 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -8,6 +8,7 @@ import ( "github.com/mr-tron/base58/base58" "github.com/iotaledger/hive.go/ds/types" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" ) @@ -82,19 +83,10 @@ type AllotAccountParams struct { From string // if not set we use faucet } -// TODO do wee need to restrict that only one instance of the wallet runs? type StateData struct { - Seed string `serix:"0,mapKey=seed"` - LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` - Accounts []Account `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` - // TODO: other info that the account wallet needs to store -} - -type Account struct { - Alias string `serix:"0,mapKey=alias"` - AccountID iotago.AccountID `serix:"1,mapKey=accountID"` - Index uint64 `serix:"2,mapKey=index"` - // TODO: other info of an account + Seed string `serix:"0,mapKey=seed"` + LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` + AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` } var dockerFaucetSeed = func() []byte { diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index ff4057336..3513f18c2 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -2,16 +2,19 @@ package accountwallet import ( "os" + "time" + + "github.com/mr-tron/base58" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/hive.go/runtime/timeutil" "github.com/iotaledger/iota-core/pkg/testsuite/mock" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" "github.com/iotaledger/iota.go/v4/tpkg" - "github.com/mr-tron/base58" ) var log = logger.New("AccountWallet") @@ -49,9 +52,10 @@ type AccountWallet struct { faucet *Faucet seed [32]byte - accountsAliases map[string]iotago.AccountID + accountsAliases map[string]*models.AccountData + + //accountsStatus map[string]models.AccountMetadata latestUsedIndex uint64 - aliasIndexMap map[string]uint64 client *models.WebClient api iotago.API @@ -59,12 +63,16 @@ type AccountWallet struct { optsClientBindAddress string optsAccountStatesFile string optsFaucetUnspendOutputID iotago.OutputID + optsRequestTimeout time.Duration + optsRequestTicker time.Duration } func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { return options.Apply(&AccountWallet{ - accountsAliases: make(map[string]iotago.Identifier), - seed: tpkg.RandEd25519Seed(), + accountsAliases: make(map[string]*models.AccountData), + seed: tpkg.RandEd25519Seed(), + optsRequestTimeout: time.Second * 30, + optsRequestTicker: time.Second * 5, }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() @@ -78,20 +86,16 @@ func (a *AccountWallet) LastFaucetUnspentOutputID() iotago.OutputID { // toAccountStateFile write account states to file. func (a *AccountWallet) toAccountStateFile() error { - accounts := make([]Account, 0) + accounts := make([]*models.AccountData, 0) - for alias, acc := range a.accountsAliases { - accounts = append(accounts, Account{ - Alias: alias, - AccountID: acc, - Index: a.aliasIndexMap[alias], - }) + for _, acc := range a.accountsAliases { + accounts = append(accounts, acc) } stateBytes, err := a.api.Encode(&StateData{ Seed: base58.Encode(a.seed[:]), LastUsedIndex: a.latestUsedIndex, - Accounts: accounts, + AccountsData: accounts, }) if err != nil { return ierrors.Wrap(err, "failed to encode state") @@ -131,14 +135,79 @@ func (a *AccountWallet) fromAccountStateFile() error { a.latestUsedIndex = data.LastUsedIndex // account data - for _, acc := range data.Accounts { - a.accountsAliases[acc.Alias] = acc.AccountID - a.aliasIndexMap[acc.Alias] = acc.Index + for _, acc := range data.AccountsData { + a.accountsAliases[acc.Alias] = acc } return nil } +func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, index uint64) iotago.AccountID { + accountID := iotago.AccountIDFromOutputID(outputID) + a.accountsAliases[alias] = &models.AccountData{ + Alias: alias, + AccountID: accountID, + Status: "created", + OutputID: outputID, + Index: index, + } + + return accountID +} + +func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { + accData, exists := a.accountsAliases[alias] + if !exists { + return nil, ierrors.Errorf("account with alias %s does not exist", alias) + } + creationSlot := accData.OutputID.CreationSlot() + + // wait for the account to be committed + err := a.retry(func() (bool, error) { + resp, err := a.client.GetBlockIssuance() + if err != nil { + return false, err + } + + if resp.Commitment.Slot >= creationSlot { + return true, nil + } + + return false, nil + }) + + if err != nil { + log.Errorf("failed to get commitment details while waiting %s: %s", alias, err) + return nil, err + } + + return accData, nil + +} + +func (a *AccountWallet) retry(requestFunc func() (bool, error)) error { + timeout := time.NewTimer(a.optsRequestTimeout) + interval := time.NewTicker(a.optsRequestTicker) + defer timeutil.CleanupTimer(timeout) + defer timeutil.CleanupTicker(interval) + + for { + done, err := requestFunc() + if err != nil { + return err + } + if done { + return nil + } + select { + case <-interval.C: + continue + case <-timeout.C: + return ierrors.New("timeout while trying to request") + } + } +} + func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) (*models.Output, error) { hdWallet := mock.NewHDWallet("", a.seed[:], a.latestUsedIndex+1) @@ -155,10 +224,11 @@ func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) } func (a *AccountWallet) destroyAccount(alias string) error { - if _, ok := a.accountsAliases[alias]; !ok { + accData, exists := a.accountsAliases[alias] + if !exists { return ierrors.Errorf("account with alias %s does not exist", alias) } - hdWallet := mock.NewHDWallet("", a.seed[:], a.aliasIndexMap[alias]) + hdWallet := mock.NewHDWallet("", a.seed[:], accData.Index) // get output from node // From TIP42: Indexers and node plugins shall map the account address of the output derived with Account ID to the regular address -> output mapping table, so that given an Account Address, its most recent unspent account output can be retrieved. @@ -167,7 +237,7 @@ func (a *AccountWallet) destroyAccount(alias string) error { txBuilder := builder.NewTransactionBuilder(a.api) txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: a.accountsAliases[alias].ToAddress(), + UnlockTarget: a.accountsAliases[alias].AccountID.ToAddress(), // InputID: accountOutput.ID(), Input: accountOutput, }) @@ -192,7 +262,6 @@ func (a *AccountWallet) destroyAccount(alias string) error { // remove account from wallet delete(a.accountsAliases, alias) - delete(a.aliasIndexMap, alias) return nil } diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index e30fd7777..52712a336 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -1,6 +1,8 @@ package models -import "github.com/iotaledger/iota.go/v4" +import ( + "github.com/iotaledger/iota.go/v4" +) // Input contains details of an input. type Input struct { @@ -20,3 +22,11 @@ type Output struct { // Outputs is a list of Output. type Outputs []*Output + +type AccountData struct { + Alias string `serix:"0"` + Status string `serix:"1"` + AccountID iotago.AccountID `serix:"2"` + OutputID iotago.OutputID `serix:"3"` + Index uint64 `serix:"4"` +} From bea12c416edf0300aba86c92e77f9e0ac3b89ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 2 Oct 2023 16:37:39 +0200 Subject: [PATCH 30/84] Extend logs and waiting period --- tools/evil-spammer/accountwallet/wallet.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 3513f18c2..649c83728 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -71,7 +71,7 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { return options.Apply(&AccountWallet{ accountsAliases: make(map[string]*models.AccountData), seed: tpkg.RandEd25519Seed(), - optsRequestTimeout: time.Second * 30, + optsRequestTimeout: time.Second * 120, optsRequestTicker: time.Second * 5, }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) @@ -163,6 +163,7 @@ func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { creationSlot := accData.OutputID.CreationSlot() // wait for the account to be committed + log.Infof("Waiting for account %s to be committed within slot %d...", alias, creationSlot) err := a.retry(func() (bool, error) { resp, err := a.client.GetBlockIssuance() if err != nil { @@ -170,6 +171,7 @@ func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { } if resp.Commitment.Slot >= creationSlot { + log.Infof("Slot %d commited, account %s is ready to use", creationSlot, alias) return true, nil } @@ -224,9 +226,10 @@ func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) } func (a *AccountWallet) destroyAccount(alias string) error { - accData, exists := a.accountsAliases[alias] - if !exists { - return ierrors.Errorf("account with alias %s does not exist", alias) + accData, err := a.getAccount(alias) + if err != nil { + + return err } hdWallet := mock.NewHDWallet("", a.seed[:], accData.Index) @@ -263,5 +266,6 @@ func (a *AccountWallet) destroyAccount(alias string) error { // remove account from wallet delete(a.accountsAliases, alias) + log.Infof("Account %s has been destroyed", alias) return nil } From 24654884c99eb1821eb51b8878e2b3d99fe374de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 2 Oct 2023 16:42:28 +0200 Subject: [PATCH 31/84] Fix AccountData serialization --- tools/evil-spammer/accountwallet/config.go | 4 ++-- tools/evil-spammer/models/output.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 1913316ca..827dc1bf4 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -84,9 +84,9 @@ type AllotAccountParams struct { } type StateData struct { - Seed string `serix:"0,mapKey=seed"` + Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` - AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` + AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint32"` } var dockerFaucetSeed = func() []byte { diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index 52712a336..ee0355e76 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -24,8 +24,8 @@ type Output struct { type Outputs []*Output type AccountData struct { - Alias string `serix:"0"` - Status string `serix:"1"` + Alias string `serix:"0,lengthPrefixType=uint8"` + Status string `serix:"1,lengthPrefixType=uint8"` AccountID iotago.AccountID `serix:"2"` OutputID iotago.OutputID `serix:"3"` Index uint64 `serix:"4"` From 3f1ec3dac203d25edbf71ae876298a33a0c87069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 09:51:13 +0200 Subject: [PATCH 32/84] Fix wallet name --- tools/evil-spammer/accountwallet/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 827dc1bf4..1125950a4 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -37,7 +37,7 @@ var accountConfigFile = "account_config.json" var accountConfigJSON = `{ "bindAddress": "http://localhost:8080", - "accountStatesFile": "wallet.LOCK" + "accountStatesFile": "wallet.dat" }` // loadAccountConfig loads the config file. From 511a280d5f2df713461e70446d78792fdf4850bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 09:56:21 +0200 Subject: [PATCH 33/84] Add accountAlias param to evil spammer --- tools/evil-spammer/accountwallet/wallet.go | 32 ++++++++++++++++++++++ tools/evil-spammer/config.go | 1 + tools/evil-spammer/parse.go | 2 ++ tools/evil-spammer/programs/params.go | 1 + tools/evil-spammer/programs/spammers.go | 20 +++++++------- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 649c83728..42ffd9aee 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -44,6 +44,30 @@ func Run(lastFaucetUnspentOutputID iotago.OutputID) (*AccountWallet, error) { return wallet, nil } +func ReadAccountWallet() (map[string]*models.AccountData, error) { + // read config here + config := loadAccountConfig() + + var opts []options.Option[AccountWallet] + if config.BindAddress != "" { + opts = append(opts, WithClientURL(config.BindAddress)) + } + if config.AccountStatesFile != "" { + opts = append(opts, WithAccountStatesFile(config.AccountStatesFile)) + } + + opts = append(opts, WithFaucetUnspendOutputID(iotago.EmptyOutputID)) + + wallet := NewAccountWallet(opts...) + accountsData, err := wallet.readAccountsStateFile() + if err != nil { + return nil, ierrors.Wrap(err, "failed to read accounts state file") + } + + return accountsData, nil + +} + func SaveState(w *AccountWallet) error { return w.toAccountStateFile() } @@ -142,6 +166,14 @@ func (a *AccountWallet) fromAccountStateFile() error { return nil } +func (a *AccountWallet) readAccountsStateFile() (map[string]*models.AccountData, error) { + err := a.fromAccountStateFile() + if err != nil { + return nil, ierrors.Wrap(err, "failed to load wallet from file") + } + return a.accountsAliases, nil +} + func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, index uint64) iotago.AccountID { accountID := iotago.AccountIDFromOutputID(outputID) a.accountsAliases[alias] = &models.AccountData{ diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index d1ddef3eb..e8704a4f4 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -32,6 +32,7 @@ var ( Scenario: wallet.Scenario1(), DeepSpam: false, EnableRateSetter: false, + AccountAlias: "faucet", } quickTestParams = programs.QuickTestParams{ diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index 8eb02e0ad..e4d921bf4 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -75,6 +75,7 @@ func parseBasicSpamFlags() { scenario := optionFlagSet.String("scenario", "", "Name of the EvilBatch that should be used for the spam. By default uses Scenario1. Possible scenarios can be found in evilwallet/customscenarion.go.") deepSpam := optionFlagSet.Bool("deep", customSpamParams.DeepSpam, "Enable the deep spam, by reusing outputs created during the spam.") nSpend := optionFlagSet.Int("nSpend", customSpamParams.NSpend, "Number of outputs to be spent in n-spends spammer for the spammer type needs to be set to 'ds'. Default value is 2 for double-spend.") + account := optionFlagSet.String("account", "", "Account alias to be used for the spam. Account should be created first with accounts tool.") parseOptionFlagSet(optionFlagSet) @@ -110,6 +111,7 @@ func parseBasicSpamFlags() { customSpamParams.DeepSpam = *deepSpam customSpamParams.TimeUnit = *timeunit customSpamParams.DelayBetweenConflicts = *delayBetweenConflicts + customSpamParams.AccountAlias = *account // fill in unused parameter: blkNum or duration with zeros if *duration == "" && *blkNum != "" { diff --git a/tools/evil-spammer/programs/params.go b/tools/evil-spammer/programs/params.go index 2d87ebe9b..0d2cdec07 100644 --- a/tools/evil-spammer/programs/params.go +++ b/tools/evil-spammer/programs/params.go @@ -20,6 +20,7 @@ type CustomSpamParams struct { Scenario wallet.EvilBatch DeepSpam bool EnableRateSetter bool + AccountAlias string Config *BasicConfig } diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index 6acac571f..6ef0bb650 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -47,7 +47,7 @@ func CustomSpam(params *CustomSpamParams) { wg.Add(1) go func(i int) { defer wg.Done() - s := SpamBlocks(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.BlkToBeSent[i], params.EnableRateSetter) + s := SpamBlocks(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.BlkToBeSent[i], params.EnableRateSetter, params.AccountAlias) if s == nil { return } @@ -57,19 +57,19 @@ func CustomSpam(params *CustomSpamParams) { wg.Add(1) go func(i int) { defer wg.Done() - SpamTransaction(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.DeepSpam, params.EnableRateSetter) + SpamTransaction(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.DeepSpam, params.EnableRateSetter, params.AccountAlias) }(i) case spammer.TypeDs: wg.Add(1) go func(i int) { defer wg.Done() - SpamDoubleSpends(w, params.Rates[i], params.NSpend, params.TimeUnit, params.Durations[i], params.DelayBetweenConflicts, params.DeepSpam, params.EnableRateSetter) + SpamDoubleSpends(w, params.Rates[i], params.NSpend, params.TimeUnit, params.Durations[i], params.DelayBetweenConflicts, params.DeepSpam, params.EnableRateSetter, params.AccountAlias) }(i) case spammer.TypeCustom: wg.Add(1) go func(i int) { defer wg.Done() - s := SpamNestedConflicts(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.Scenario, params.DeepSpam, false, params.EnableRateSetter) + s := SpamNestedConflicts(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.Scenario, params.DeepSpam, false, params.EnableRateSetter, params.AccountAlias) if s == nil { return } @@ -85,7 +85,7 @@ func CustomSpam(params *CustomSpamParams) { go func() { defer wg.Done() - s := SpamAccounts(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.EnableRateSetter) + s := SpamAccounts(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.EnableRateSetter, params.AccountAlias) if s == nil { return } @@ -101,7 +101,7 @@ func CustomSpam(params *CustomSpamParams) { log.Info("Basic spamming finished!") } -func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, deepSpam, enableRateSetter bool) { +func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, deepSpam, enableRateSetter bool, accountAlias string) { if w.NumOfClient() < 1 { log.Infof("Warning: At least one client is needed to spam.") } @@ -131,7 +131,7 @@ func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Dur s.Spam() } -func SpamDoubleSpends(w *wallet.EvilWallet, rate, nSpent int, timeUnit, duration, delayBetweenConflicts time.Duration, deepSpam, enableRateSetter bool) { +func SpamDoubleSpends(w *wallet.EvilWallet, rate, nSpent int, timeUnit, duration, delayBetweenConflicts time.Duration, deepSpam, enableRateSetter bool, accountAlias string) { log.Debugf("Setting up double spend spammer with rate: %d, time unit: %s, and duration: %s.", rate, timeUnit.String(), duration.String()) if w.NumOfClient() < 2 { log.Infof("Warning: At least two client are needed to spam, and %d was provided", w.NumOfClient()) @@ -162,7 +162,7 @@ func SpamDoubleSpends(w *wallet.EvilWallet, rate, nSpent int, timeUnit, duration s.Spam() } -func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, conflictBatch wallet.EvilBatch, deepSpam, reuseOutputs, enableRateSetter bool) *spammer.Spammer { +func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, conflictBatch wallet.EvilBatch, deepSpam, reuseOutputs, enableRateSetter bool, accountAlias string) *spammer.Spammer { scenarioOptions := []wallet.ScenarioOption{ wallet.WithScenarioCustomConflicts(conflictBatch), } @@ -193,7 +193,7 @@ func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time return spammer.NewSpammer(options...) } -func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, numBlkToSend int, enableRateSetter bool) *spammer.Spammer { +func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, numBlkToSend int, enableRateSetter bool, accountAlias string) *spammer.Spammer { if w.NumOfClient() < 1 { log.Infof("Warning: At least one client is needed to spam.") } @@ -210,7 +210,7 @@ func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration return spammer.NewSpammer(options...) } -func SpamAccounts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, enableRateSetter bool) *spammer.Spammer { +func SpamAccounts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, enableRateSetter bool, accountAlias string) *spammer.Spammer { if w.NumOfClient() < 1 { log.Infof("Warning: At least one client is needed to spam.") } From 9fc8fa4b05d77316f4788b680484167e8df07b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 09:57:02 +0200 Subject: [PATCH 34/84] Load accData with CustomSpammer --- tools/evil-spammer/main.go | 9 ++++++++- tools/evil-spammer/programs/spammers.go | 5 +++-- tools/evil-spammer/wallet/evilwallet.go | 7 +++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index a8fd54532..917c9054d 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -32,7 +32,14 @@ func main() { case "interactive": interactive.Run() case "basic": - programs.CustomSpam(&customSpamParams) + // load wallet + accData, err := accountwallet.ReadAccountWallet() + if err != nil { + log.Warn(err) + return + } + + programs.CustomSpam(&customSpamParams, accData) case "accounts": // load wallet accWallet, err := accountwallet.Run(lastFaucetUnspendOutputID) diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index 6ef0bb650..09f28f44d 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -6,6 +6,7 @@ import ( "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" "github.com/iotaledger/iota.go/v4" @@ -13,13 +14,13 @@ import ( var log = logger.New("customSpam") -func CustomSpam(params *CustomSpamParams) { +func CustomSpam(params *CustomSpamParams, accData map[string]*models.AccountData) { outputID := iotago.OutputIDFromTransactionIDAndIndex(snapshotcreator.GenesisTransactionID, 0) if params.Config.LastFaucetUnspentOutputID != "" { outputID, _ = iotago.OutputIDFromHex(params.Config.LastFaucetUnspentOutputID) } - w := wallet.NewEvilWallet(wallet.WithClients(params.ClientURLs...), wallet.WithFaucetOutputID(outputID)) + w := wallet.NewEvilWallet(wallet.WithClients(params.ClientURLs...), wallet.WithFaucetOutputID(outputID), wallet.WithAccountsData(accData)) wg := sync.WaitGroup{} // funds are requested fro all spam types except SpammerTypeBlock diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/wallet/evilwallet.go index 43f099f4a..5a0f810c5 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/wallet/evilwallet.go @@ -61,6 +61,7 @@ type EvilWallet struct { optFaucetSeed []byte optFaucetUnspentOutputID iotago.OutputID optsClientURLs []string + optsAccountsData map[string]*models.AccountData } // NewEvilWallet creates an EvilWallet instance. @@ -849,3 +850,9 @@ func WithClients(urls ...string) options.Option[EvilWallet] { opts.optsClientURLs = urls } } + +func WithAccountsData(accData map[string]*models.AccountData) options.Option[EvilWallet] { + return func(opts *EvilWallet) { + opts.optsAccountsData = accData + } +} From 4fced083ae79bfb5ce1bed49a9da00261b726f05 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Tue, 3 Oct 2023 14:33:57 +0800 Subject: [PATCH 35/84] Introduce AccountStatus --- tools/evil-spammer/accountwallet/wallet.go | 2 +- tools/evil-spammer/models/output.go | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 649c83728..c97157168 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -147,7 +147,7 @@ func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, a.accountsAliases[alias] = &models.AccountData{ Alias: alias, AccountID: accountID, - Status: "created", + Status: models.AccountPending, OutputID: outputID, Index: index, } diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index ee0355e76..b65c1750b 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -1,7 +1,7 @@ package models import ( - "github.com/iotaledger/iota.go/v4" + iotago "github.com/iotaledger/iota.go/v4" ) // Input contains details of an input. @@ -23,9 +23,16 @@ type Output struct { // Outputs is a list of Output. type Outputs []*Output +type AccountStatus uint8 + +const ( + AccountPending AccountStatus = iota + AccountReady +) + type AccountData struct { Alias string `serix:"0,lengthPrefixType=uint8"` - Status string `serix:"1,lengthPrefixType=uint8"` + Status AccountStatus `serix:"1"` AccountID iotago.AccountID `serix:"2"` OutputID iotago.OutputID `serix:"3"` Index uint64 `serix:"4"` From 6e57e405177ecf363e51d5094f15b0282e1d194b Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Tue, 3 Oct 2023 15:46:32 +0800 Subject: [PATCH 36/84] Refactor getAccount --- tools/evil-spammer/accountwallet/wallet.go | 91 +++++++++++++++------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index c97157168..8d340469d 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -155,15 +155,48 @@ func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, return accountID } +func (a *AccountWallet) updateAccountStatus(alias string, status models.AccountStatus) (*models.AccountData, bool) { + accData, exists := a.accountsAliases[alias] + if !exists { + return nil, false + } + + if accData.Status == status { + return accData, false + } + + accData.Status = status + a.accountsAliases[alias] = accData + + return accData, true +} + func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { accData, exists := a.accountsAliases[alias] if !exists { return nil, ierrors.Errorf("account with alias %s does not exist", alias) } + + // check if account is ready (to be included in a commitment) + ready := a.isAccountReady(accData) + if !ready { + return nil, ierrors.Errorf("account with alias %s is not ready", alias) + } + + accData, _ = a.updateAccountStatus(alias, models.AccountReady) + + return accData, nil +} + +func (a *AccountWallet) isAccountReady(accData *models.AccountData) bool { + if accData.Status == models.AccountReady { + return true + } + creationSlot := accData.OutputID.CreationSlot() // wait for the account to be committed - log.Infof("Waiting for account %s to be committed within slot %d...", alias, creationSlot) + log.Infof("Waiting for account %s to be committed within slot %d...", accData.Alias, creationSlot) err := a.retry(func() (bool, error) { resp, err := a.client.GetBlockIssuance() if err != nil { @@ -171,7 +204,7 @@ func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { } if resp.Commitment.Slot >= creationSlot { - log.Infof("Slot %d commited, account %s is ready to use", creationSlot, alias) + log.Infof("Slot %d commited, account %s is ready to use", creationSlot, accData.Alias) return true, nil } @@ -179,35 +212,11 @@ func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { }) if err != nil { - log.Errorf("failed to get commitment details while waiting %s: %s", alias, err) - return nil, err + log.Errorf("failed to get commitment details while waiting %s: %s", accData.Alias, err) + return false } - return accData, nil - -} - -func (a *AccountWallet) retry(requestFunc func() (bool, error)) error { - timeout := time.NewTimer(a.optsRequestTimeout) - interval := time.NewTicker(a.optsRequestTicker) - defer timeutil.CleanupTimer(timeout) - defer timeutil.CleanupTicker(interval) - - for { - done, err := requestFunc() - if err != nil { - return err - } - if done { - return nil - } - select { - case <-interval.C: - continue - case <-timeout.C: - return ierrors.New("timeout while trying to request") - } - } + return true } func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) (*models.Output, error) { @@ -228,7 +237,6 @@ func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) func (a *AccountWallet) destroyAccount(alias string) error { accData, err := a.getAccount(alias) if err != nil { - return err } hdWallet := mock.NewHDWallet("", a.seed[:], accData.Index) @@ -269,3 +277,26 @@ func (a *AccountWallet) destroyAccount(alias string) error { log.Infof("Account %s has been destroyed", alias) return nil } + +func (a *AccountWallet) retry(requestFunc func() (bool, error)) error { + timeout := time.NewTimer(a.optsRequestTimeout) + interval := time.NewTicker(a.optsRequestTicker) + defer timeutil.CleanupTimer(timeout) + defer timeutil.CleanupTicker(interval) + + for { + done, err := requestFunc() + if err != nil { + return err + } + if done { + return nil + } + select { + case <-interval.C: + continue + case <-timeout.C: + return ierrors.New("timeout while trying to request") + } + } +} From 52fa5b01e98b6ab47b7f044e5178d7af0069b5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 12:30:22 +0200 Subject: [PATCH 37/84] Rename wallet to evilwallet --- tools/evil-spammer/config.go | 4 +- .../{wallet => evilwallet}/aliasmanager.go | 2 +- .../{wallet => evilwallet}/customscenarios.go | 2 +- .../{wallet => evilwallet}/evilscenario.go | 2 +- .../{wallet => evilwallet}/evilwallet.go | 2 +- .../{wallet => evilwallet}/options.go | 2 +- .../{wallet => evilwallet}/output_manager.go | 2 +- .../{wallet => evilwallet}/utils.go | 2 +- .../{wallet => evilwallet}/wallet.go | 2 +- .../{wallet => evilwallet}/wallets.go | 2 +- tools/evil-spammer/interactive/interactive.go | 16 ++--- tools/evil-spammer/interactive/menu.go | 6 +- tools/evil-spammer/parse.go | 4 +- tools/evil-spammer/programs/params.go | 4 +- tools/evil-spammer/programs/quick-test.go | 8 +-- tools/evil-spammer/programs/spammers.go | 68 +++++++++---------- tools/evil-spammer/spammer/options.go | 6 +- tools/evil-spammer/spammer/spammer.go | 12 ++-- tools/evil-spammer/spammer/utils.go | 4 +- 19 files changed, 75 insertions(+), 75 deletions(-) rename tools/evil-spammer/{wallet => evilwallet}/aliasmanager.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/customscenarios.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/evilscenario.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/evilwallet.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/options.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/output_manager.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/utils.go (98%) rename tools/evil-spammer/{wallet => evilwallet}/wallet.go (99%) rename tools/evil-spammer/{wallet => evilwallet}/wallets.go (99%) diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index e8704a4f4..a1320d8f0 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -3,9 +3,9 @@ package main import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" iotago "github.com/iotaledger/iota.go/v4" ) @@ -29,7 +29,7 @@ var ( TimeUnit: time.Second, DelayBetweenConflicts: 0, NSpend: 2, - Scenario: wallet.Scenario1(), + Scenario: evilwallet.Scenario1(), DeepSpam: false, EnableRateSetter: false, AccountAlias: "faucet", diff --git a/tools/evil-spammer/wallet/aliasmanager.go b/tools/evil-spammer/evilwallet/aliasmanager.go similarity index 99% rename from tools/evil-spammer/wallet/aliasmanager.go rename to tools/evil-spammer/evilwallet/aliasmanager.go index e08b50d7c..284e89f6d 100644 --- a/tools/evil-spammer/wallet/aliasmanager.go +++ b/tools/evil-spammer/evilwallet/aliasmanager.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "go.uber.org/atomic" diff --git a/tools/evil-spammer/wallet/customscenarios.go b/tools/evil-spammer/evilwallet/customscenarios.go similarity index 99% rename from tools/evil-spammer/wallet/customscenarios.go rename to tools/evil-spammer/evilwallet/customscenarios.go index 0f5599544..e26142746 100644 --- a/tools/evil-spammer/wallet/customscenarios.go +++ b/tools/evil-spammer/evilwallet/customscenarios.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "strconv" diff --git a/tools/evil-spammer/wallet/evilscenario.go b/tools/evil-spammer/evilwallet/evilscenario.go similarity index 99% rename from tools/evil-spammer/wallet/evilscenario.go rename to tools/evil-spammer/evilwallet/evilscenario.go index 32dd1109c..32a171bd0 100644 --- a/tools/evil-spammer/wallet/evilscenario.go +++ b/tools/evil-spammer/evilwallet/evilscenario.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "fmt" diff --git a/tools/evil-spammer/wallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go similarity index 99% rename from tools/evil-spammer/wallet/evilwallet.go rename to tools/evil-spammer/evilwallet/evilwallet.go index 5a0f810c5..1206eb9a7 100644 --- a/tools/evil-spammer/wallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "fmt" diff --git a/tools/evil-spammer/wallet/options.go b/tools/evil-spammer/evilwallet/options.go similarity index 99% rename from tools/evil-spammer/wallet/options.go rename to tools/evil-spammer/evilwallet/options.go index 8c8d42a99..35dec30da 100644 --- a/tools/evil-spammer/wallet/options.go +++ b/tools/evil-spammer/evilwallet/options.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "time" diff --git a/tools/evil-spammer/wallet/output_manager.go b/tools/evil-spammer/evilwallet/output_manager.go similarity index 99% rename from tools/evil-spammer/wallet/output_manager.go rename to tools/evil-spammer/evilwallet/output_manager.go index 361f0c29d..57811c2bd 100644 --- a/tools/evil-spammer/wallet/output_manager.go +++ b/tools/evil-spammer/evilwallet/output_manager.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "sync" diff --git a/tools/evil-spammer/wallet/utils.go b/tools/evil-spammer/evilwallet/utils.go similarity index 98% rename from tools/evil-spammer/wallet/utils.go rename to tools/evil-spammer/evilwallet/utils.go index eb080d749..733d86987 100644 --- a/tools/evil-spammer/wallet/utils.go +++ b/tools/evil-spammer/evilwallet/utils.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import iotago "github.com/iotaledger/iota.go/v4" diff --git a/tools/evil-spammer/wallet/wallet.go b/tools/evil-spammer/evilwallet/wallet.go similarity index 99% rename from tools/evil-spammer/wallet/wallet.go rename to tools/evil-spammer/evilwallet/wallet.go index 3d653686f..5b97d86f8 100644 --- a/tools/evil-spammer/wallet/wallet.go +++ b/tools/evil-spammer/evilwallet/wallet.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "crypto/ed25519" diff --git a/tools/evil-spammer/wallet/wallets.go b/tools/evil-spammer/evilwallet/wallets.go similarity index 99% rename from tools/evil-spammer/wallet/wallets.go rename to tools/evil-spammer/evilwallet/wallets.go index 71445f847..31e5c0366 100644 --- a/tools/evil-spammer/wallet/wallets.go +++ b/tools/evil-spammer/evilwallet/wallets.go @@ -1,4 +1,4 @@ -package wallet +package evilwallet import ( "go.uber.org/atomic" diff --git a/tools/evil-spammer/interactive/interactive.go b/tools/evil-spammer/interactive/interactive.go index f1c4d426b..a3a92ff55 100644 --- a/tools/evil-spammer/interactive/interactive.go +++ b/tools/evil-spammer/interactive/interactive.go @@ -15,9 +15,9 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/runtime/syncutils" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" "github.com/iotaledger/iota.go/v4/nodeclient" ) @@ -191,7 +191,7 @@ func configure(mode *Mode) { // region Mode ///////////////////////////////////////////////////////////////////////////////////////////////////////// type Mode struct { - evilWallet *wallet.EvilWallet + evilWallet *evilwallet.EvilWallet shutdown chan types.Empty mainMenu chan types.Empty spamFinished chan int @@ -215,7 +215,7 @@ type Mode struct { func NewInteractiveMode() *Mode { return &Mode{ - evilWallet: wallet.NewEvilWallet(), + evilWallet: evilwallet.NewEvilWallet(), action: make(chan action), shutdown: make(chan types.Empty), mainMenu: make(chan types.Empty), @@ -298,7 +298,7 @@ func (m *Mode) onMenuAction() { } func (m *Mode) prepareFundsIfNeeded() { - if m.evilWallet.UnspentOutputsLeft(wallet.Fresh) < minSpamOutputs { + if m.evilWallet.UnspentOutputsLeft(evilwallet.Fresh) < minSpamOutputs { if !m.preparingFunds && m.Config.AutoRequesting { m.preparingFunds = true go func() { @@ -436,7 +436,7 @@ func (m *Mode) areEnoughFundsAvailable() bool { outputsNeeded = int(float64(m.Config.Rate) * m.Config.duration.Minutes()) } - return m.evilWallet.UnspentOutputsLeft(wallet.Fresh) < outputsNeeded && m.Config.Scenario != spammer.TypeBlock + return m.evilWallet.UnspentOutputsLeft(evilwallet.Fresh) < outputsNeeded && m.Config.Scenario != spammer.TypeBlock } func (m *Mode) startSpam() { @@ -445,10 +445,10 @@ func (m *Mode) startSpam() { var s *spammer.Spammer if m.Config.Scenario == spammer.TypeBlock { - s = programs.SpamBlocks(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, 0, m.Config.UseRateSetter) + s = programs.SpamBlocks(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, 0, m.Config.UseRateSetter, "") } else { - scenario, _ := wallet.GetScenario(m.Config.Scenario) - s = programs.SpamNestedConflicts(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, scenario, m.Config.Deep, m.Config.Reuse, m.Config.UseRateSetter) + scenario, _ := evilwallet.GetScenario(m.Config.Scenario) + s = programs.SpamNestedConflicts(m.evilWallet, m.Config.Rate, time.Second, m.Config.duration, scenario, m.Config.Deep, m.Config.Reuse, m.Config.UseRateSetter, "") if s == nil { return } diff --git a/tools/evil-spammer/interactive/menu.go b/tools/evil-spammer/interactive/menu.go index 38bda5f01..3f91c8c00 100644 --- a/tools/evil-spammer/interactive/menu.go +++ b/tools/evil-spammer/interactive/menu.go @@ -5,7 +5,7 @@ import ( "os" "time" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" ) // region Printer ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -63,8 +63,8 @@ func (p *Printer) printBanner() { func (p *Printer) EvilWalletStatus() { p.PrintTopLine() p.Println(p.colorString("Evil Wallet status:", "cyan"), level2) - p.PrintlnPoint(fmt.Sprintf("Available faucet outputs: %d", p.mode.evilWallet.UnspentOutputsLeft(wallet.Fresh)), level2) - p.PrintlnPoint(fmt.Sprintf("Available reuse outputs: %d", p.mode.evilWallet.UnspentOutputsLeft(wallet.Reuse)), level2) + p.PrintlnPoint(fmt.Sprintf("Available faucet outputs: %d", p.mode.evilWallet.UnspentOutputsLeft(evilwallet.Fresh)), level2) + p.PrintlnPoint(fmt.Sprintf("Available reuse outputs: %d", p.mode.evilWallet.UnspentOutputsLeft(evilwallet.Reuse)), level2) p.PrintlnPoint(fmt.Sprintf("Spammed blocks: %d", p.mode.blkSent.Load()), level2) p.PrintlnPoint(fmt.Sprintf("Spammed transactions: %d", p.mode.txSent.Load()), level2) p.PrintlnPoint(fmt.Sprintf("Spammed scenario batches: %d", p.mode.scenariosSent.Load()), level2) diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index e4d921bf4..3df1430c3 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -9,8 +9,8 @@ import ( "time" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" iotago "github.com/iotaledger/iota.go/v4" ) @@ -101,7 +101,7 @@ func parseBasicSpamFlags() { customSpamParams.BlkToBeSent = parsedBlkNums } if *scenario != "" { - conflictBatch, ok := wallet.GetScenario(*scenario) + conflictBatch, ok := evilwallet.GetScenario(*scenario) if ok { customSpamParams.Scenario = conflictBatch } diff --git a/tools/evil-spammer/programs/params.go b/tools/evil-spammer/programs/params.go index 0d2cdec07..009d18f9f 100644 --- a/tools/evil-spammer/programs/params.go +++ b/tools/evil-spammer/programs/params.go @@ -5,7 +5,7 @@ import ( "os" "time" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" ) type CustomSpamParams struct { @@ -17,7 +17,7 @@ type CustomSpamParams struct { TimeUnit time.Duration DelayBetweenConflicts time.Duration NSpend int - Scenario wallet.EvilBatch + Scenario evilwallet.EvilBatch DeepSpam bool EnableRateSetter bool AccountAlias string diff --git a/tools/evil-spammer/programs/quick-test.go b/tools/evil-spammer/programs/quick-test.go index 942f74de7..e17725594 100644 --- a/tools/evil-spammer/programs/quick-test.go +++ b/tools/evil-spammer/programs/quick-test.go @@ -3,8 +3,8 @@ package programs import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" ) type QuickTestParams struct { @@ -19,7 +19,7 @@ type QuickTestParams struct { // QuickTest runs short spamming periods with stable mps. func QuickTest(params *QuickTestParams) { - evilWallet := wallet.NewEvilWallet(wallet.WithClients(params.ClientURLs...)) + evilWallet := evilwallet.NewEvilWallet(evilwallet.WithClients(params.ClientURLs...)) counter := spammer.NewErrorCount() log.Info("Starting quick test") @@ -41,8 +41,8 @@ func QuickTest(params *QuickTestParams) { spammer.WithSpammingFunc(spammer.DataSpammingFunction), ) - dsScenario := wallet.NewEvilScenario( - wallet.WithScenarioCustomConflicts(wallet.NSpendBatch(2)), + dsScenario := evilwallet.NewEvilScenario( + evilwallet.WithScenarioCustomConflicts(evilwallet.NSpendBatch(2)), ) //nolint:gocritic // we want a copy here diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index 09f28f44d..78a54b09b 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -5,10 +5,10 @@ import ( "time" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" "github.com/iotaledger/iota.go/v4" ) @@ -20,7 +20,7 @@ func CustomSpam(params *CustomSpamParams, accData map[string]*models.AccountData outputID, _ = iotago.OutputIDFromHex(params.Config.LastFaucetUnspentOutputID) } - w := wallet.NewEvilWallet(wallet.WithClients(params.ClientURLs...), wallet.WithFaucetOutputID(outputID), wallet.WithAccountsData(accData)) + w := evilwallet.NewEvilWallet(evilwallet.WithClients(params.ClientURLs...), evilwallet.WithFaucetOutputID(outputID), evilwallet.WithAccountsData(accData)) wg := sync.WaitGroup{} // funds are requested fro all spam types except SpammerTypeBlock @@ -102,23 +102,23 @@ func CustomSpam(params *CustomSpamParams, accData map[string]*models.AccountData log.Info("Basic spamming finished!") } -func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, deepSpam, enableRateSetter bool, accountAlias string) { +func SpamTransaction(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Duration, deepSpam, enableRateSetter bool, accountAlias string) { if w.NumOfClient() < 1 { log.Infof("Warning: At least one client is needed to spam.") } - scenarioOptions := []wallet.ScenarioOption{ - wallet.WithScenarioCustomConflicts(wallet.SingleTransactionBatch()), + scenarioOptions := []evilwallet.ScenarioOption{ + evilwallet.WithScenarioCustomConflicts(evilwallet.SingleTransactionBatch()), } if deepSpam { - outWallet := wallet.NewWallet(wallet.Reuse) + outWallet := evilwallet.NewWallet(evilwallet.Reuse) scenarioOptions = append(scenarioOptions, - wallet.WithScenarioDeepSpamEnabled(), - wallet.WithScenarioReuseOutputWallet(outWallet), - wallet.WithScenarioInputWalletForDeepSpam(outWallet), + evilwallet.WithScenarioDeepSpamEnabled(), + evilwallet.WithScenarioReuseOutputWallet(outWallet), + evilwallet.WithScenarioInputWalletForDeepSpam(outWallet), ) } - scenarioTx := wallet.NewEvilScenario(scenarioOptions...) + scenarioTx := evilwallet.NewEvilScenario(scenarioOptions...) options := []spammer.Options{ spammer.WithSpamRate(rate, timeUnit), @@ -132,24 +132,24 @@ func SpamTransaction(w *wallet.EvilWallet, rate int, timeUnit, duration time.Dur s.Spam() } -func SpamDoubleSpends(w *wallet.EvilWallet, rate, nSpent int, timeUnit, duration, delayBetweenConflicts time.Duration, deepSpam, enableRateSetter bool, accountAlias string) { +func SpamDoubleSpends(w *evilwallet.EvilWallet, rate, nSpent int, timeUnit, duration, delayBetweenConflicts time.Duration, deepSpam, enableRateSetter bool, accountAlias string) { log.Debugf("Setting up double spend spammer with rate: %d, time unit: %s, and duration: %s.", rate, timeUnit.String(), duration.String()) if w.NumOfClient() < 2 { log.Infof("Warning: At least two client are needed to spam, and %d was provided", w.NumOfClient()) } - scenarioOptions := []wallet.ScenarioOption{ - wallet.WithScenarioCustomConflicts(wallet.NSpendBatch(nSpent)), + scenarioOptions := []evilwallet.ScenarioOption{ + evilwallet.WithScenarioCustomConflicts(evilwallet.NSpendBatch(nSpent)), } if deepSpam { - outWallet := wallet.NewWallet(wallet.Reuse) + outWallet := evilwallet.NewWallet(evilwallet.Reuse) scenarioOptions = append(scenarioOptions, - wallet.WithScenarioDeepSpamEnabled(), - wallet.WithScenarioReuseOutputWallet(outWallet), - wallet.WithScenarioInputWalletForDeepSpam(outWallet), + evilwallet.WithScenarioDeepSpamEnabled(), + evilwallet.WithScenarioReuseOutputWallet(outWallet), + evilwallet.WithScenarioInputWalletForDeepSpam(outWallet), ) } - scenarioDs := wallet.NewEvilScenario(scenarioOptions...) + scenarioDs := evilwallet.NewEvilScenario(scenarioOptions...) options := []spammer.Options{ spammer.WithSpamRate(rate, timeUnit), spammer.WithSpamDuration(duration), @@ -163,22 +163,22 @@ func SpamDoubleSpends(w *wallet.EvilWallet, rate, nSpent int, timeUnit, duration s.Spam() } -func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, conflictBatch wallet.EvilBatch, deepSpam, reuseOutputs, enableRateSetter bool, accountAlias string) *spammer.Spammer { - scenarioOptions := []wallet.ScenarioOption{ - wallet.WithScenarioCustomConflicts(conflictBatch), +func SpamNestedConflicts(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Duration, conflictBatch evilwallet.EvilBatch, deepSpam, reuseOutputs, enableRateSetter bool, accountAlias string) *spammer.Spammer { + scenarioOptions := []evilwallet.ScenarioOption{ + evilwallet.WithScenarioCustomConflicts(conflictBatch), } if deepSpam { - outWallet := wallet.NewWallet(wallet.Reuse) + outWallet := evilwallet.NewWallet(evilwallet.Reuse) scenarioOptions = append(scenarioOptions, - wallet.WithScenarioDeepSpamEnabled(), - wallet.WithScenarioReuseOutputWallet(outWallet), - wallet.WithScenarioInputWalletForDeepSpam(outWallet), + evilwallet.WithScenarioDeepSpamEnabled(), + evilwallet.WithScenarioReuseOutputWallet(outWallet), + evilwallet.WithScenarioInputWalletForDeepSpam(outWallet), ) } else if reuseOutputs { - outWallet := wallet.NewWallet(wallet.Reuse) - scenarioOptions = append(scenarioOptions, wallet.WithScenarioReuseOutputWallet(outWallet)) + outWallet := evilwallet.NewWallet(evilwallet.Reuse) + scenarioOptions = append(scenarioOptions, evilwallet.WithScenarioReuseOutputWallet(outWallet)) } - scenario := wallet.NewEvilScenario(scenarioOptions...) + scenario := evilwallet.NewEvilScenario(scenarioOptions...) if scenario.NumOfClientsNeeded > w.NumOfClient() { log.Infof("Warning: At least %d client are needed to spam, and %d was provided", scenario.NumOfClientsNeeded, w.NumOfClient()) } @@ -194,7 +194,7 @@ func SpamNestedConflicts(w *wallet.EvilWallet, rate int, timeUnit, duration time return spammer.NewSpammer(options...) } -func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, numBlkToSend int, enableRateSetter bool, accountAlias string) *spammer.Spammer { +func SpamBlocks(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Duration, numBlkToSend int, enableRateSetter bool, accountAlias string) *spammer.Spammer { if w.NumOfClient() < 1 { log.Infof("Warning: At least one client is needed to spam.") } @@ -211,16 +211,16 @@ func SpamBlocks(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration return spammer.NewSpammer(options...) } -func SpamAccounts(w *wallet.EvilWallet, rate int, timeUnit, duration time.Duration, enableRateSetter bool, accountAlias string) *spammer.Spammer { +func SpamAccounts(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Duration, enableRateSetter bool, accountAlias string) *spammer.Spammer { if w.NumOfClient() < 1 { log.Infof("Warning: At least one client is needed to spam.") } - scenarioOptions := []wallet.ScenarioOption{ - wallet.WithScenarioCustomConflicts(wallet.SingleTransactionBatch()), - wallet.WithCreateAccounts(), + scenarioOptions := []evilwallet.ScenarioOption{ + evilwallet.WithScenarioCustomConflicts(evilwallet.SingleTransactionBatch()), + evilwallet.WithCreateAccounts(), } - scenarioAccount := wallet.NewEvilScenario(scenarioOptions...) + scenarioAccount := evilwallet.NewEvilScenario(scenarioOptions...) options := []spammer.Options{ spammer.WithSpamRate(rate, timeUnit), diff --git a/tools/evil-spammer/spammer/options.go b/tools/evil-spammer/spammer/options.go index 590763d70..51ef08ea0 100644 --- a/tools/evil-spammer/spammer/options.go +++ b/tools/evil-spammer/spammer/options.go @@ -3,8 +3,8 @@ package spammer import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/models" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" ) type Options func(*Spammer) @@ -86,14 +86,14 @@ func WithBatchesSent(maxBatchesSent int) Options { } // WithEvilWallet provides evil wallet instance, that will handle all spam logic according to provided EvilScenario. -func WithEvilWallet(initWallets *wallet.EvilWallet) Options { +func WithEvilWallet(initWallets *evilwallet.EvilWallet) Options { return func(s *Spammer) { s.EvilWallet = initWallets } } // WithEvilScenario provides initWallet of spammer, if omitted spammer will prepare funds based on maxBlkSent parameter. -func WithEvilScenario(scenario *wallet.EvilScenario) Options { +func WithEvilScenario(scenario *evilwallet.EvilScenario) Options { return func(s *Spammer) { s.EvilScenario = scenario } diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index 3cee97a08..7eaeb1bea 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -12,8 +12,8 @@ import ( "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/models" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" iotago "github.com/iotaledger/iota.go/v4" ) @@ -60,8 +60,8 @@ type Spammer struct { UseRateSetter bool SpamType SpamType Clients models.Connector - EvilWallet *wallet.EvilWallet - EvilScenario *wallet.EvilScenario + EvilWallet *evilwallet.EvilWallet + EvilScenario *evilwallet.EvilScenario IdentityManager *IdentityManager // CommitmentManager *CommitmentManager ErrCounter *ErrorCounter @@ -93,7 +93,7 @@ func NewSpammer(options ...Options) *Spammer { spamFunc: CustomConflictSpammingFunc, State: state, SpamType: SpamEvilWallet, - EvilScenario: wallet.NewEvilScenario(), + EvilScenario: evilwallet.NewEvilScenario(), IdentityManager: NewIdentityManager(), // CommitmentManager: NewCommitmentManager(), UseRateSetter: true, @@ -129,7 +129,7 @@ func (s *Spammer) setup() { switch s.SpamType { case SpamEvilWallet: if s.EvilWallet == nil { - s.EvilWallet = wallet.NewEvilWallet() + s.EvilWallet = evilwallet.NewEvilWallet() } s.Clients = s.EvilWallet.Connector() // case SpamCommitments: @@ -258,7 +258,7 @@ func (s *Spammer) PostTransaction(signedTx *iotago.SignedTransaction, clt models return } - if s.EvilScenario.OutputWallet.Type() == wallet.Reuse { + if s.EvilScenario.OutputWallet.Type() == evilwallet.Reuse { var outputIDs iotago.OutputIDs for index := range signedTx.Transaction.Outputs { outputIDs = append(outputIDs, iotago.OutputIDFromTransactionIDAndIndex(txID, uint16(index))) diff --git a/tools/evil-spammer/spammer/utils.go b/tools/evil-spammer/spammer/utils.go index c395d023b..997945723 100644 --- a/tools/evil-spammer/spammer/utils.go +++ b/tools/evil-spammer/spammer/utils.go @@ -3,12 +3,12 @@ package spammer import ( "time" - "github.com/iotaledger/iota-core/tools/evil-spammer/wallet" + "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" ) // BigWalletsNeeded calculates how many big wallets needs to be prepared for a spam based on provided spam details. func BigWalletsNeeded(rate int, timeUnit, duration time.Duration) int { - bigWalletSize := wallet.FaucetRequestSplitNumber * wallet.FaucetRequestSplitNumber + bigWalletSize := evilwallet.FaucetRequestSplitNumber * evilwallet.FaucetRequestSplitNumber outputsNeeded := rate * int(duration/timeUnit) walletsNeeded := outputsNeeded/bigWalletSize + 1 From a0888c9656d64e52b1afb2eeb8eaee02eeba8194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 12:31:54 +0200 Subject: [PATCH 38/84] Remove redundant constant --- tools/evil-spammer/evilwallet/evilwallet.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 1206eb9a7..6582de0db 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -28,8 +28,6 @@ const ( awaitConfirmationSleep = 3 * time.Second awaitSolidificationSleep = time.Millisecond * 500 - - WaitForTxSolid = 150 * time.Second ) var ( From a0b3e4ce3b1f68061e65470add4c39fc3a6b6c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 12:48:11 +0200 Subject: [PATCH 39/84] Fix signedTxIDs errors --- tools/evil-spammer/evilwallet/evilwallet.go | 10 +++++----- tools/evil-spammer/spammer/spammer.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 6582de0db..3b31c7992 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -303,11 +303,11 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *models.Output } // requested output to split and use in spammer - output := e.outputManager.CreateOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 0), signedTx.Transaction.Outputs[0]) + output := e.outputManager.CreateOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 0), signedTx.Transaction.Outputs[0]) // set remainder output to be reused by the faucet wallet e.faucet.AddUnspentOutput(&models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 1), + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), Address: faucetAddr, Index: 0, Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), @@ -336,7 +336,7 @@ func (e *EvilWallet) splitOutputs(splitOutput *models.Output, inputWallet, outpu return iotago.TransactionID{}, err } - return lo.PanicOnErr(signedTx.ID()), nil + return lo.PanicOnErr(signedTx.Transaction.ID()), nil } func (e *EvilWallet) handleInputOutputDuringSplitOutputs(splitOutput *models.Output, splitNumber int, receiveWallet *Wallet) (input *models.Output, outputs []*OutputOption) { @@ -436,7 +436,7 @@ func (e *EvilWallet) addOutputsToOutputManager(signedTx *iotago.SignedTransactio // register UnlockConditionAddress only (skip account outputs) addr := o.UnlockConditionSet().Address().Address out := &models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), uint16(idx)), + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), uint16(idx)), Address: addr, Balance: o.BaseTokenAmount(), OutputStruct: o, @@ -479,7 +479,7 @@ func (e *EvilWallet) registerOutputAliases(signedTx *iotago.SignedTransaction, a } for idx := range signedTx.Transaction.Outputs { - id := iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), uint16(idx)) + id := iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), uint16(idx)) out := e.outputManager.GetOutput(id) if out == nil { continue diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index 7eaeb1bea..a0794bcba 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -242,7 +242,7 @@ func (s *Spammer) PostTransaction(signedTx *iotago.SignedTransaction, clt models return } - txID := lo.PanicOnErr(signedTx.ID()) + txID := lo.PanicOnErr(signedTx.Transaction.ID()) allSolid := s.handleSolidityForReuseOutputs(clt, signedTx) if !allSolid { s.log.Debug(ErrInputsNotSolid) From 9c83dd3bda966cf0835952a812ea7157ee11cbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 12:51:08 +0200 Subject: [PATCH 40/84] Fix genesis transaction ID creation --- tools/evil-spammer/evilwallet/evilwallet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 3b31c7992..b6d3c4d3b 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -33,7 +33,7 @@ const ( var ( defaultClientsURLs = []string{"http://localhost:8080", "http://localhost:8090"} - genesisTransactionID = iotago.SlotIdentifierRepresentingData(0, []byte("genesis")) + genesisTransactionID = iotago.TransactionIDRepresentingData(0, []byte("genesis")) dockerFaucetSeed = func() []byte { genesisSeed, err := base58.Decode("7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih") From d47e84561d54d80b8c8a72f1ce5525339a487739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 13:29:55 +0200 Subject: [PATCH 41/84] Fix txID errors in accWallet --- pkg/protocol/snapshotcreator/snapshotcreator.go | 2 +- tools/evil-spammer/accountwallet/config.go | 2 +- tools/evil-spammer/accountwallet/faucet.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/protocol/snapshotcreator/snapshotcreator.go b/pkg/protocol/snapshotcreator/snapshotcreator.go index db8e77948..e470bed35 100644 --- a/pkg/protocol/snapshotcreator/snapshotcreator.go +++ b/pkg/protocol/snapshotcreator/snapshotcreator.go @@ -47,7 +47,7 @@ const ( GenesisTransactionCreationSlot = 0 ) -var GenesisTransactionID = iotago.TransactionIDFromData(GenesisTransactionCreationSlot, []byte("genesis")) +var GenesisTransactionID = iotago.TransactionIDRepresentingData(GenesisTransactionCreationSlot, []byte("genesis")) func CreateSnapshot(opts ...options.Option[Options]) error { opt := NewOptions(opts...) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 1125950a4..d13234d33 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -98,4 +98,4 @@ var dockerFaucetSeed = func() []byte { return genesisSeed } -var genesisTransactionID = iotago.SlotIdentifierRepresentingData(0, []byte("genesis")) +var genesisTransactionID = iotago.TransactionIDRepresentingData(0, []byte("genesis")) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index c7b79ac2f..4bca91925 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -116,7 +116,7 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke // set remainder output to be reused by the faucet wallet f.unspentOutput = &models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 1), + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), Address: f.facuetAddress, Index: 0, Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), @@ -124,7 +124,7 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke } return &models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.ID()), 0), + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 0), Address: receiveAddr, Index: 0, Balance: signedTx.Transaction.Outputs[0].BaseTokenAmount(), From 8a04767d90502b4c0401042c775510ba4b91bf4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 13:52:46 +0200 Subject: [PATCH 42/84] Use account wallet directly by spammer --- tools/evil-spammer/accountwallet/wallet.go | 24 ------------------- tools/evil-spammer/evilwallet/evilwallet.go | 7 +++--- tools/evil-spammer/main.go | 26 +++++++++------------ tools/evil-spammer/programs/spammers.go | 6 ++--- 4 files changed, 18 insertions(+), 45 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 42ffd9aee..9edab1fd1 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -44,30 +44,6 @@ func Run(lastFaucetUnspentOutputID iotago.OutputID) (*AccountWallet, error) { return wallet, nil } -func ReadAccountWallet() (map[string]*models.AccountData, error) { - // read config here - config := loadAccountConfig() - - var opts []options.Option[AccountWallet] - if config.BindAddress != "" { - opts = append(opts, WithClientURL(config.BindAddress)) - } - if config.AccountStatesFile != "" { - opts = append(opts, WithAccountStatesFile(config.AccountStatesFile)) - } - - opts = append(opts, WithFaucetUnspendOutputID(iotago.EmptyOutputID)) - - wallet := NewAccountWallet(opts...) - accountsData, err := wallet.readAccountsStateFile() - if err != nil { - return nil, ierrors.Wrap(err, "failed to read accounts state file") - } - - return accountsData, nil - -} - func SaveState(w *AccountWallet) error { return w.toAccountStateFile() } diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index b6d3c4d3b..7130681ea 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -12,6 +12,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" @@ -59,7 +60,7 @@ type EvilWallet struct { optFaucetSeed []byte optFaucetUnspentOutputID iotago.OutputID optsClientURLs []string - optsAccountsData map[string]*models.AccountData + optsAccountsWallet *accountwallet.AccountWallet } // NewEvilWallet creates an EvilWallet instance. @@ -849,8 +850,8 @@ func WithClients(urls ...string) options.Option[EvilWallet] { } } -func WithAccountsData(accData map[string]*models.AccountData) options.Option[EvilWallet] { +func WithAccountsWallet(wallet *accountwallet.AccountWallet) options.Option[EvilWallet] { return func(opts *EvilWallet) { - opts.optsAccountsData = accData + opts.optsAccountsWallet = wallet } } diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 917c9054d..ffe17a3b7 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -27,20 +27,9 @@ func main() { return } - // run selected test scenario - switch Script { - case "interactive": - interactive.Run() - case "basic": - // load wallet - accData, err := accountwallet.ReadAccountWallet() - if err != nil { - log.Warn(err) - return - } - - programs.CustomSpam(&customSpamParams, accData) - case "accounts": + // init account wallet + var accWallet *accountwallet.AccountWallet + if Script == "basic" || Script == "accounts" { // load wallet accWallet, err := accountwallet.Run(lastFaucetUnspendOutputID) if err != nil { @@ -54,7 +43,14 @@ func main() { log.Errorf("Error while saving wallet state: %v", err) } }(accWallet, "wallet.dat") - + } + // run selected test scenario + switch Script { + case "interactive": + interactive.Run() + case "basic": + programs.CustomSpam(&customSpamParams, accWallet) + case "accounts": accountsSubcommands(accWallet, accountsSubcommandsFlags) case "quick": programs.QuickTest(&quickTestParams) diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index 78a54b09b..d206ba34c 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -5,22 +5,22 @@ import ( "time" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" - "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" "github.com/iotaledger/iota.go/v4" ) var log = logger.New("customSpam") -func CustomSpam(params *CustomSpamParams, accData map[string]*models.AccountData) { +func CustomSpam(params *CustomSpamParams, accWallet *accountwallet.AccountWallet) { outputID := iotago.OutputIDFromTransactionIDAndIndex(snapshotcreator.GenesisTransactionID, 0) if params.Config.LastFaucetUnspentOutputID != "" { outputID, _ = iotago.OutputIDFromHex(params.Config.LastFaucetUnspentOutputID) } - w := evilwallet.NewEvilWallet(evilwallet.WithClients(params.ClientURLs...), evilwallet.WithFaucetOutputID(outputID), evilwallet.WithAccountsData(accData)) + w := evilwallet.NewEvilWallet(evilwallet.WithClients(params.ClientURLs...), evilwallet.WithFaucetOutputID(outputID), evilwallet.WithAccountsWallet(accWallet)) wg := sync.WaitGroup{} // funds are requested fro all spam types except SpammerTypeBlock From a4ff71b42fa7653b701f04977a4f7f3a4cf4237f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 14:31:05 +0200 Subject: [PATCH 43/84] Basic and accounts use the same requestfaucetFunds function --- tools/evil-spammer/accountwallet/faucet.go | 34 +++--- tools/evil-spammer/accountwallet/wallet.go | 12 +-- tools/evil-spammer/evilwallet/evilwallet.go | 111 ++------------------ 3 files changed, 31 insertions(+), 126 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 4bca91925..ba9878da6 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -12,18 +12,18 @@ import ( ) type Faucet struct { - facuetAddress *iotago.Ed25519Address - seed []byte - faucerAddr *iotago.Ed25519Address - clt models.Client - + address *iotago.Ed25519Address unspentOutput *models.Output + account iotago.AccountID + + seed []byte + clt models.Client sync.Mutex } func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet { - //get faucet output and amount + //get Faucet output and amount var faucetAmount iotago.BaseToken faucetOutput := clt.GetOutput(faucetUnspentOutputID) @@ -44,9 +44,9 @@ func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet } hdWallet := mock.NewHDWallet("", f.seed[:], 0) - f.facuetAddress = hdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address) + f.address = hdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address) f.unspentOutput = &models.Output{ - Address: f.faucerAddr, + Address: f.address, Index: 0, OutputID: faucetUnspentOutputID, Balance: faucetAmount, @@ -56,13 +56,13 @@ func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet return f } -func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { +func (f *Faucet) RequestFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { remainderAmount := f.unspentOutput.Balance - amount - txBuilder := builder.NewTransactionBuilder(f.clt.CurrentAPI()) + txBuilder := builder.NewTransactionBuilder(clt.CurrentAPI()) txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: f.facuetAddress, + UnlockTarget: f.address, InputID: f.unspentOutput.OutputID, Input: f.unspentOutput.OutputStruct, }) @@ -91,12 +91,12 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke txBuilder.AddOutput(&iotago.BasicOutput{ Amount: remainderAmount, Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: f.facuetAddress}, + &iotago.AddressUnlockCondition{Address: f.address}, }, }) - txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) - txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) + txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) + txBuilder.SetCreationSlot(clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) hdWallet := mock.NewHDWallet("", f.seed[:], 0) signedTx, err := txBuilder.Build(hdWallet.AddressSigner()) @@ -107,17 +107,17 @@ func (f *Faucet) RequestFunds(receiveAddr iotago.Address, amount iotago.BaseToke } // send transaction - _, err = f.clt.PostTransaction(signedTx) + _, err = clt.PostTransaction(signedTx) if err != nil { log.Errorf("failed to post transaction: %s", err) return nil, err } - // set remainder output to be reused by the faucet wallet + // set remainder output to be reused by the Faucet wallet f.unspentOutput = &models.Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), - Address: f.facuetAddress, + Address: f.address, Index: 0, Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), OutputStruct: signedTx.Transaction.Outputs[1], diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 9edab1fd1..55c20643f 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -49,7 +49,7 @@ func SaveState(w *AccountWallet) error { } type AccountWallet struct { - faucet *Faucet + Faucet *Faucet seed [32]byte accountsAliases map[string]*models.AccountData @@ -76,12 +76,12 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() - w.faucet = NewFaucet(w.client, w.optsFaucetUnspendOutputID) + w.Faucet = NewFaucet(w.client, w.optsFaucetUnspendOutputID) }) } func (a *AccountWallet) LastFaucetUnspentOutputID() iotago.OutputID { - return a.faucet.unspentOutput.OutputID + return a.Faucet.unspentOutput.OutputID } // toAccountStateFile write account states to file. @@ -222,9 +222,9 @@ func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) hdWallet := mock.NewHDWallet("", a.seed[:], a.latestUsedIndex+1) receiverAddr := hdWallet.Address(addressType) - createdOutput, err := a.faucet.RequestFunds(receiverAddr, iotago.BaseToken(amount)) + createdOutput, err := a.Faucet.RequestFunds(a.client, receiverAddr, iotago.BaseToken(amount)) if err != nil { - return nil, ierrors.Wrap(err, "failed to request funds from faucet") + return nil, ierrors.Wrap(err, "failed to request funds from Faucet") } a.latestUsedIndex++ @@ -257,7 +257,7 @@ func (a *AccountWallet) destroyAccount(alias string) error { txBuilder.AddOutput(&iotago.BasicOutput{ Amount: accountOutput.BaseTokenAmount(), Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: a.faucet.facuetAddress}, + &iotago.AddressUnlockCondition{Address: a.Faucet.address}, }, }) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 7130681ea..a88f6fa30 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -53,57 +53,25 @@ type EvilWallet struct { // faucet is the wallet of faucet faucet *Wallet wallets *Wallets + accWallet *accountwallet.AccountWallet connector models.Connector outputManager *OutputManager aliasManager *AliasManager - optFaucetSeed []byte - optFaucetUnspentOutputID iotago.OutputID - optsClientURLs []string - optsAccountsWallet *accountwallet.AccountWallet + optsClientURLs []string } // NewEvilWallet creates an EvilWallet instance. func NewEvilWallet(opts ...options.Option[EvilWallet]) *EvilWallet { return options.Apply(&EvilWallet{ - wallets: NewWallets(), - aliasManager: NewAliasManager(), - optFaucetSeed: dockerFaucetSeed(), - optFaucetUnspentOutputID: iotago.OutputIDFromTransactionIDAndIndex(genesisTransactionID, 0), - optsClientURLs: defaultClientsURLs, + wallets: NewWallets(), + aliasManager: NewAliasManager(), + optsClientURLs: defaultClientsURLs, }, opts, func(w *EvilWallet) { connector := models.NewWebClients(w.optsClientURLs) w.connector = connector - - clt := w.connector.GetClient() - w.outputManager = NewOutputManager(connector, w.wallets) - w.faucet = NewWallet() - w.faucet.seed = [32]byte(w.optFaucetSeed) - - // get faucet output and amount - var faucetAmount iotago.BaseToken - - faucetOutput := clt.GetOutput(w.optFaucetUnspentOutputID) - if faucetOutput != nil { - faucetAmount = faucetOutput.BaseTokenAmount() - } else { - // use the genesis output ID instead, if we relaunch the docker network - w.optFaucetUnspentOutputID = iotago.OutputIDFromTransactionIDAndIndex(genesisTransactionID, 0) - faucetOutput = clt.GetOutput(w.optFaucetUnspentOutputID) - if faucetOutput != nil { - faucetAmount = faucetOutput.BaseTokenAmount() - } - } - - w.faucet.AddUnspentOutput(&models.Output{ - Address: w.faucet.AddressOnIndex(0), - Index: 0, - OutputID: w.optFaucetUnspentOutputID, - Balance: faucetAmount, - OutputStruct: faucetOutput, - }) }) } @@ -253,68 +221,11 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *models.Output receiveAddr := wallet.AddressOnIndex(0) clt := e.connector.GetClient() - faucetAddr := e.faucet.AddressOnIndex(0) - unspentFaucet := e.faucet.UnspentOutput(faucetAddr.String()) - if unspentFaucet.OutputStruct == nil { - clt = e.connector.GetClient() - faucetOutput := clt.GetOutput(e.optFaucetUnspentOutputID) - if faucetOutput == nil { - panic("no valid faucet unspent output") - } - unspentFaucet.OutputStruct = faucetOutput - } - remainderAmount := unspentFaucet.Balance - faucetTokensPerRequest - - txBuilder := builder.NewTransactionBuilder(clt.CurrentAPI()) - - txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: faucetAddr, - InputID: unspentFaucet.OutputID, - Input: unspentFaucet.OutputStruct, - }) - - // receiver output - txBuilder.AddOutput(&iotago.BasicOutput{ - Amount: faucetTokensPerRequest, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: receiveAddr}, - }, - }) - - // remainder output - txBuilder.AddOutput(&iotago.BasicOutput{ - Amount: remainderAmount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: faucetAddr}, - }, - }) - - txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) - txBuilder.SetCreationSlot(clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) - - signedTx, err := txBuilder.Build(e.faucet.AddressSigner(faucetAddr)) + output, err := e.accWallet.Faucet.RequestFunds(clt, receiveAddr, faucetTokensPerRequest) if err != nil { - return nil, err + return nil, ierrors.Wrap(err, "failed to request funds from faucet") } - // send transaction - _, err = clt.PostTransaction(signedTx) - if err != nil { - return nil, err - } - - // requested output to split and use in spammer - output := e.outputManager.CreateOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 0), signedTx.Transaction.Outputs[0]) - - // set remainder output to be reused by the faucet wallet - e.faucet.AddUnspentOutput(&models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), - Address: faucetAddr, - Index: 0, - Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), - OutputStruct: signedTx.Transaction.Outputs[1], - }) - return output, nil } @@ -838,12 +749,6 @@ func (e *EvilWallet) SetTxOutputsSolid(outputs iotago.OutputIDs, clientID string // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// -func WithFaucetOutputID(id iotago.OutputID) options.Option[EvilWallet] { - return func(opts *EvilWallet) { - opts.optFaucetUnspentOutputID = id - } -} - func WithClients(urls ...string) options.Option[EvilWallet] { return func(opts *EvilWallet) { opts.optsClientURLs = urls @@ -852,6 +757,6 @@ func WithClients(urls ...string) options.Option[EvilWallet] { func WithAccountsWallet(wallet *accountwallet.AccountWallet) options.Option[EvilWallet] { return func(opts *EvilWallet) { - opts.optsAccountsWallet = wallet + opts.accWallet = wallet } } From 4e3610582ac2a7a554118803a0c2615dc803e077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 3 Oct 2023 14:36:00 +0200 Subject: [PATCH 44/84] Remove redundant options --- tools/evil-spammer/programs/spammers.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index d206ba34c..bf92e21fb 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -4,23 +4,16 @@ import ( "sync" "time" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" - "github.com/iotaledger/iota.go/v4" ) var log = logger.New("customSpam") func CustomSpam(params *CustomSpamParams, accWallet *accountwallet.AccountWallet) { - outputID := iotago.OutputIDFromTransactionIDAndIndex(snapshotcreator.GenesisTransactionID, 0) - if params.Config.LastFaucetUnspentOutputID != "" { - outputID, _ = iotago.OutputIDFromHex(params.Config.LastFaucetUnspentOutputID) - } - - w := evilwallet.NewEvilWallet(evilwallet.WithClients(params.ClientURLs...), evilwallet.WithFaucetOutputID(outputID), evilwallet.WithAccountsWallet(accWallet)) + w := evilwallet.NewEvilWallet(evilwallet.WithClients(params.ClientURLs...), evilwallet.WithAccountsWallet(accWallet)) wg := sync.WaitGroup{} // funds are requested fro all spam types except SpammerTypeBlock From 1c69a7ab226e493ab426afdfa436b05e150b921f Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Wed, 4 Oct 2023 14:08:43 +0800 Subject: [PATCH 45/84] Use correct outputID in destroyAccount --- tools/evil-spammer/accountwallet/wallet.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index dbea09bc7..bb7a50808 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -252,13 +252,13 @@ func (a *AccountWallet) destroyAccount(alias string) error { // get output from node // From TIP42: Indexers and node plugins shall map the account address of the output derived with Account ID to the regular address -> output mapping table, so that given an Account Address, its most recent unspent account output can be retrieved. // TODO: use correct outputID - accountOutput := a.client.GetOutput(iotago.EmptyOutputID) + accountOutput := a.client.GetOutput(accData.OutputID) txBuilder := builder.NewTransactionBuilder(a.api) txBuilder.AddInput(&builder.TxInput{ UnlockTarget: a.accountsAliases[alias].AccountID.ToAddress(), - // InputID: accountOutput.ID(), - Input: accountOutput, + InputID: accData.OutputID, + Input: accountOutput, }) // send all tokens to faucet From 8cfa9d2896e662ad01b21f5dd363c91ed1aed05e Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Wed, 4 Oct 2023 19:36:50 +0900 Subject: [PATCH 46/84] Fix accwallet initialization in evil-spammer --- tools/evil-spammer/main.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index ffe17a3b7..b1b171dec 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -29,20 +29,19 @@ func main() { } // init account wallet var accWallet *accountwallet.AccountWallet + var err error if Script == "basic" || Script == "accounts" { // load wallet - accWallet, err := accountwallet.Run(lastFaucetUnspendOutputID) + accWallet, err = accountwallet.Run(lastFaucetUnspendOutputID) if err != nil { log.Warn(err) return } // save wallet - defer func(w *accountwallet.AccountWallet, filename string) { - err = accountwallet.SaveState(w) - if err != nil { - log.Errorf("Error while saving wallet state: %v", err) - } - }(accWallet, "wallet.dat") + err = accountwallet.SaveState(accWallet) + if err != nil { + log.Errorf("Error while saving wallet state: %v", err) + } } // run selected test scenario switch Script { From 9f3f5418cef1ea3c650b26845607b087e001ff4b Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Thu, 5 Oct 2023 15:25:42 +0900 Subject: [PATCH 47/84] Add more commands for account wallets --- tools/evil-spammer/accountwallet/config.go | 104 +++++++++- tools/evil-spammer/config.go | 3 +- tools/evil-spammer/main.go | 28 ++- tools/evil-spammer/parse.go | 230 +++++++++++++++------ 4 files changed, 279 insertions(+), 86 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index d13234d33..fcb87b45b 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -14,18 +14,51 @@ import ( // commands +type AccountOperation int + const ( - CreateAccountCommand = "create" - DestroyAccountCommand = "destroy" - AllotAccountCommand = "allot" - ListAccountsCommand = "list" + OperationCreateAccount AccountOperation = iota + OperationConvertAccount + OperationDestroyAccound + OperationAllotAccount + OperationDelegateAccount + OperationStakeAccount + OperationListAccounts + + CmdNameCreateAccount = "create" + CmdNameConvertAccount = "convert" + CmdNameDestroyAccount = "destroy" + CmdNameAllotAccount = "allot" + CmdNameDelegateAccount = "delegate" + CmdNameStakeAccount = "stake" + CmdNameListAccounts = "list" ) -var AvailableCommands = map[string]types.Empty{ - CreateAccountCommand: types.Void, - DestroyAccountCommand: types.Void, - AllotAccountCommand: types.Void, - ListAccountsCommand: types.Void, +func (a AccountOperation) String() string { + return []string{ + CmdNameCreateAccount, + CmdNameConvertAccount, + CmdNameDestroyAccount, + CmdNameAllotAccount, + CmdNameDelegateAccount, + CmdNameStakeAccount, + CmdNameListAccounts, + }[a] +} + +func AvailableCommands(cmd string) bool { + availableCommands := map[string]types.Empty{ + CmdNameCreateAccount: types.Void, + CmdNameConvertAccount: types.Void, + CmdNameDestroyAccount: types.Void, + CmdNameAllotAccount: types.Void, + CmdNameDelegateAccount: types.Void, + CmdNameStakeAccount: types.Void, + CmdNameListAccounts: types.Void, + } + + _, ok := availableCommands[cmd] + return ok } type Configuration struct { @@ -68,13 +101,28 @@ func loadAccountConfig() *Configuration { return config } +type AccountSubcommands interface { + Type() AccountOperation +} + type CreateAccountParams struct { - Alias string - Amount uint64 + Alias string + Amount uint64 + NoBIF bool + Implicit bool +} + +func (c *CreateAccountParams) Type() AccountOperation { + return OperationCreateAccount } type DestroyAccountParams struct { AccountAlias string + ExpirySlot uint64 +} + +func (d *DestroyAccountParams) Type() AccountOperation { + return OperationDestroyAccound } type AllotAccountParams struct { @@ -83,6 +131,40 @@ type AllotAccountParams struct { From string // if not set we use faucet } +func (a *AllotAccountParams) Type() AccountOperation { + return OperationAllotAccount +} + +type ConvertAccountParams struct { + AccountAlias string +} + +func (d *ConvertAccountParams) Type() AccountOperation { + return OperationConvertAccount +} + +type DelegateAccountParams struct { + Amount uint64 + To string + From string // if not set we use faucet +} + +func (a *DelegateAccountParams) Type() AccountOperation { + return OperationDelegateAccount +} + +type StakeAccountParams struct { + Alias string + Amount uint64 + FixedCost uint64 + StartEpoch uint64 + EndEpoch uint64 +} + +func (a *StakeAccountParams) Type() AccountOperation { + return OperationStakeAccount +} + type StateData struct { Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index a1320d8f0..8831ae907 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -3,6 +3,7 @@ package main import ( "time" + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" @@ -44,7 +45,7 @@ var ( EnableRateSetter: false, } - accountsSubcommandsFlags = make([]*subcommand, 0) + accountsSubcommandsFlags []accountwallet.AccountSubcommands lastFaucetUnspendOutputID iotago.OutputID //nolint:godot diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index b1b171dec..eda7970b6 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -60,7 +60,7 @@ func main() { } } -func accountsSubcommands(wallet *accountwallet.AccountWallet, subcommands []*subcommand) { +func accountsSubcommands(wallet *accountwallet.AccountWallet, subcommands []accountwallet.AccountSubcommands) { for _, sub := range subcommands { accountsSubcommand(wallet, sub) } @@ -71,11 +71,11 @@ func accountsSubcommands(wallet *accountwallet.AccountWallet, subcommands []*sub }) } -func accountsSubcommand(wallet *accountwallet.AccountWallet, sub *subcommand) { - switch sub.command { - case accountwallet.CreateAccountCommand: - params := parseCreateAccountFlags(sub.flags) - log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.CreateAccountCommand, params) +func accountsSubcommand(wallet *accountwallet.AccountWallet, sub accountwallet.AccountSubcommands) { + switch sub.Type() { + case accountwallet.OperationCreateAccount: + log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.OperationCreateAccount.String(), sub) + params := sub.(*accountwallet.CreateAccountParams) accountID, err := wallet.CreateAccount(params) if err != nil { log.Errorf("Error creating account: %v", err) @@ -83,27 +83,25 @@ func accountsSubcommand(wallet *accountwallet.AccountWallet, sub *subcommand) { return } log.Infof("Created account %s with %d tokens", accountID, params.Amount) - case accountwallet.DestroyAccountCommand: - params := parseDestroyAccountFlags(sub.flags) - log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.DestroyAccountCommand, params) - + case accountwallet.OperationDestroyAccound: + log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.OperationDestroyAccound, sub) + params := sub.(*accountwallet.DestroyAccountParams) err := wallet.DestroyAccount(params) if err != nil { log.Errorf("Error destroying account: %v", err) return } - case accountwallet.ListAccountsCommand: + case accountwallet.OperationListAccounts: err := wallet.ListAccount() if err != nil { log.Errorf("Error listing accounts: %v", err) return } - case accountwallet.AllotAccountCommand: - params := parseAllotAccountFlags(sub.flags) - log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.AllotAccountCommand, params) - + case accountwallet.OperationAllotAccount: + log.Infof("Run subcommand: %s, with parametetr set: %v", accountwallet.OperationAllotAccount, sub) + params := sub.(*accountwallet.AllotAccountParams) err := wallet.AllotToAccount(params) if err != nil { log.Errorf("Error allotting account: %v", err) diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index 3df1430c3..30ac80bc7 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" @@ -32,7 +33,10 @@ func parseFlags() (help bool) { if len(os.Args) > 2 { subcommands = os.Args[2:] } - accountsSubcommandsFlags = readSubcommandsAndFlagSets(subcommands) + splitedCmds := readSubcommandsAndFlagSets(subcommands) + accountsSubcommandsFlags = parseAccountTestFlags(splitedCmds) + fmt.Println(accountsSubcommandsFlags) + basicConfig := programs.LoadBasicConfig() outputID, err := iotago.OutputIDFromHex(basicConfig.LastFaucetUnspentOutputID) if err != nil { @@ -145,90 +149,145 @@ func parseQuickTestFlags() { quickTestParams.VerifyLedger = *verifyLedger } -type subcommand struct { - command string - flags []string -} - // readSubcommandsAndFlagSets splits the subcommands on multiple flag sets. -func readSubcommandsAndFlagSets(subcommands []string) []*subcommand { +func readSubcommandsAndFlagSets(subcommands []string) [][]string { prevSplitIndex := 0 - subcommandsSplit := make([]*subcommand, 0) + subcommandsSplit := make([][]string, 0) if len(subcommands) == 0 { - accountUsage() - return nil } + + // mainCmd := make([]string, 0) for index := 0; index < len(subcommands); index++ { - _, validCommand := accountwallet.AvailableCommands[subcommands[index]] - if subcommands[index] == "-h" || subcommands[index] == "--help" { - accountUsage() + validCommand := accountwallet.AvailableCommands(subcommands[index]) - return nil - } if !strings.HasPrefix(subcommands[index], "--") && validCommand { if index != 0 { - subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1 : index]}) + subcommandsSplit = append(subcommandsSplit, subcommands[prevSplitIndex:index]) } prevSplitIndex = index } } - subcommandsSplit = append(subcommandsSplit, &subcommand{command: subcommands[prevSplitIndex], flags: subcommands[prevSplitIndex+1:]}) + subcommandsSplit = append(subcommandsSplit, subcommands[prevSplitIndex:]) + fmt.Println(subcommandsSplit) return subcommandsSplit } -func accountUsage() { - fmt.Println("Usage for accounts [COMMAND] [FLAGS], multiple commands can be chained together.") - fmt.Printf("COMMAND: %s\n", accountwallet.CreateAccountCommand) - parseCreateAccountFlags(nil) +func parseAccountTestFlags(splitedCmds [][]string) []accountwallet.AccountSubcommands { + parsedCmds := make([]accountwallet.AccountSubcommands, 0) - fmt.Printf("COMMAND: %s\n", accountwallet.DestroyAccountCommand) - parseDestroyAccountFlags(nil) + for _, cmds := range splitedCmds { + switch cmds[0] { + case "create": + createAccountParams, err := parseCreateAccountFlags(cmds[1:]) + if err != nil { + continue + } - fmt.Printf("COMMAND: %s\n", accountwallet.AllotAccountCommand) - parseAllotAccountFlags(nil) + parsedCmds = append(parsedCmds, createAccountParams) + case "convert": + convertAccountParams, err := parseConvertAccountFlags(cmds[1:]) + if err != nil { + continue + } - fmt.Printf("COMMAND: %s\n No flags available.", accountwallet.AllotAccountCommand) -} + parsedCmds = append(parsedCmds, convertAccountParams) + case "destroy": + destroyAccountParams, err := parseDestroyAccountFlags(cmds[1:]) + if err != nil { + continue + } + + parsedCmds = append(parsedCmds, destroyAccountParams) + case "allot": + allotAccountParams, err := parseAllotAccountFlags(cmds[1:]) + if err != nil { + continue + } + + parsedCmds = append(parsedCmds, allotAccountParams) + case "delegate": + delegatingAccountParams, err := parseDelegateAccountFlags(cmds[1:]) + if err != nil { + continue + } + + parsedCmds = append(parsedCmds, delegatingAccountParams) + case "stake": + stakingAccountParams, err := parseStakeAccountFlags(cmds[1:]) + if err != nil { + continue + } + + parsedCmds = append(parsedCmds, stakingAccountParams) + } + } -func parseCreateAccountFlags(subcommands []string) *accountwallet.CreateAccountParams { - flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) + return parsedCmds +} - alias := flagSet.String("alias", "", "Alias of the account to be created") - amount := flagSet.Int("amount", 100, "Amount of foucet tokens to be used for the accountcreation") +func parseCreateAccountFlags(subcommands []string) (*accountwallet.CreateAccountParams, error) { + flagSet := flag.NewFlagSet("create", flag.ExitOnError) + alias := flagSet.String("alias", "", "The alias name of new created account") + amount := flagSet.Int64("amount", 1000, "The amount to be transfered to the new account") + noBIF := flagSet.Bool("noBIF", false, "Create account without Block Issuer Feature") + implicit := flagSet.Bool("implicit", false, "Create an implicit account") if subcommands == nil { flagSet.Usage() - return nil + return nil, ierrors.Errorf("no subcommands") } log.Infof("Parsing create account flags, subcommands: %v", subcommands) - err := flagSet.Parse(subcommands) if err != nil { log.Errorf("Cannot parse first `script` parameter") - return nil + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") } - createAccountParams := &accountwallet.CreateAccountParams{ - Alias: *alias, - Amount: uint64(*amount), - } - return createAccountParams + return &accountwallet.CreateAccountParams{ + Alias: *alias, + Amount: uint64(*amount), + NoBIF: *noBIF, + Implicit: *implicit, + }, nil } -func parseDestroyAccountFlags(subcommands []string) *accountwallet.DestroyAccountParams { - flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) +func parseConvertAccountFlags(subcommands []string) (*accountwallet.ConvertAccountParams, error) { + flagSet := flag.NewFlagSet("convert", flag.ExitOnError) + alias := flagSet.String("alias", "", "The implicit account to be converted to full account") + + if subcommands == nil { + flagSet.Usage() + + return nil, ierrors.Errorf("no subcommands") + } + + log.Infof("Parsing convert account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") + } + + return &accountwallet.ConvertAccountParams{ + AccountAlias: *alias, + }, nil +} - alias := flagSet.String("alias", "", "Alias of the account to be destroyed") +func parseDestroyAccountFlags(subcommands []string) (*accountwallet.DestroyAccountParams, error) { + flagSet := flag.NewFlagSet("destroy", flag.ExitOnError) + alias := flagSet.String("alias", "", "The alias name of the account to be destroyed") + expirySlot := flagSet.Int64("expirySlot", 0, "The expiry slot of the account to be destroyed") if subcommands == nil { flagSet.Usage() - return nil + return nil, ierrors.Errorf("no subcommands") } log.Infof("Parsing destroy account flags, subcommands: %v", subcommands) @@ -236,25 +295,25 @@ func parseDestroyAccountFlags(subcommands []string) *accountwallet.DestroyAccoun if err != nil { log.Errorf("Cannot parse first `script` parameter") - return nil + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") } - createAccountParams := &accountwallet.DestroyAccountParams{ + + return &accountwallet.DestroyAccountParams{ AccountAlias: *alias, - } - return createAccountParams + ExpirySlot: uint64(*expirySlot), + }, nil } -func parseAllotAccountFlags(subcommands []string) *accountwallet.AllotAccountParams { - flagSet := flag.NewFlagSet("script flag set", flag.ExitOnError) - - to := flagSet.String("to", "", "Alias of the account to allot mana") - amount := flagSet.Int("amount", 100, "Amount of mana to allot") - from := flagSet.String("from", "", "Alias of the account we allot from, if not specified, we allot from the faucet account") +func parseAllotAccountFlags(subcommands []string) (*accountwallet.AllotAccountParams, error) { + flagSet := flag.NewFlagSet("allot", flag.ExitOnError) + from := flagSet.String("from", "", "The alias name of the account to allot mana from") + to := flagSet.String("to", "", "The alias of the account to allot mana to") + amount := flagSet.Int64("amount", 1000, "The amount of mana to allot") if subcommands == nil { flagSet.Usage() - return nil + return nil, ierrors.Errorf("no subcommands") } log.Infof("Parsing allot account flags, subcommands: %v", subcommands) @@ -262,19 +321,72 @@ func parseAllotAccountFlags(subcommands []string) *accountwallet.AllotAccountPar if err != nil { log.Errorf("Cannot parse first `script` parameter") - return nil + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") } - createAccountParams := &accountwallet.AllotAccountParams{ + return &accountwallet.AllotAccountParams{ + From: *from, To: *to, Amount: uint64(*amount), + }, nil +} + +func parseStakeAccountFlags(subcommands []string) (*accountwallet.StakeAccountParams, error) { + flagSet := flag.NewFlagSet("stake", flag.ExitOnError) + alias := flagSet.String("alias", "", "The alias name of the account to stake") + amount := flagSet.Int64("amount", 100, "The amount of tokens to stake") + fixedCost := flagSet.Int64("fixedCost", 0, "The fixed cost of the account to stake") + startEpoch := flagSet.Int64("startEpoch", 0, "The start epoch of the account to stake") + endEpoch := flagSet.Int64("endEpoch", 0, "The end epoch of the account to stake") + + if subcommands == nil { + flagSet.Usage() + + return nil, ierrors.Errorf("no subcommands") + } + + log.Infof("Parsing staking account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") + } + + return &accountwallet.StakeAccountParams{ + Alias: *alias, + Amount: uint64(*amount), + FixedCost: uint64(*fixedCost), + StartEpoch: uint64(*startEpoch), + EndEpoch: uint64(*endEpoch), + }, nil +} + +func parseDelegateAccountFlags(subcommands []string) (*accountwallet.DelegateAccountParams, error) { + flagSet := flag.NewFlagSet("delegate", flag.ExitOnError) + from := flagSet.String("from", "", "The alias name of the account to delegate mana from") + to := flagSet.String("to", "", "The alias of the account to delegate mana to") + amount := flagSet.Int64("amount", 100, "The amount of mana to delegate") + + if subcommands == nil { + flagSet.Usage() + + return nil, ierrors.Errorf("no subcommands") } - if *from != "" { - createAccountParams.From = *from + log.Infof("Parsing delegate account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") } - return createAccountParams + return &accountwallet.DelegateAccountParams{ + From: *from, + To: *to, + Amount: uint64(*amount), + }, nil } // func parseCommitmentsSpamFlags() { From d4de5b9a280d15ad8fb6a4b20072d20986a7e837 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Thu, 5 Oct 2023 15:37:43 +0900 Subject: [PATCH 48/84] Enable account commands usage description --- tools/evil-spammer/parse.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index 30ac80bc7..a274f17d0 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -35,7 +35,6 @@ func parseFlags() (help bool) { } splitedCmds := readSubcommandsAndFlagSets(subcommands) accountsSubcommandsFlags = parseAccountTestFlags(splitedCmds) - fmt.Println(accountsSubcommandsFlags) basicConfig := programs.LoadBasicConfig() outputID, err := iotago.OutputIDFromHex(basicConfig.LastFaucetUnspentOutputID) @@ -169,7 +168,6 @@ func readSubcommandsAndFlagSets(subcommands []string) [][]string { } } subcommandsSplit = append(subcommandsSplit, subcommands[prevSplitIndex:]) - fmt.Println(subcommandsSplit) return subcommandsSplit } @@ -221,12 +219,36 @@ func parseAccountTestFlags(splitedCmds [][]string) []accountwallet.AccountSubcom } parsedCmds = append(parsedCmds, stakingAccountParams) + default: + accountUsage() + return nil } } return parsedCmds } +func accountUsage() { + fmt.Println("Usage for accounts [COMMAND] [FLAGS], multiple commands can be chained together.") + fmt.Printf("COMMAND: %s\n", accountwallet.CmdNameCreateAccount) + parseCreateAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.CmdNameConvertAccount) + parseConvertAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.CmdNameDestroyAccount) + parseDestroyAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.CmdNameAllotAccount) + parseAllotAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.CmdNameDelegateAccount) + parseDelegateAccountFlags(nil) + + fmt.Printf("COMMAND: %s\n", accountwallet.CmdNameStakeAccount) + parseStakeAccountFlags(nil) +} + func parseCreateAccountFlags(subcommands []string) (*accountwallet.CreateAccountParams, error) { flagSet := flag.NewFlagSet("create", flag.ExitOnError) alias := flagSet.String("alias", "", "The alias name of new created account") From a119134e36c28b960d6991ccb8280a961e06ba65 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Thu, 5 Oct 2023 16:26:39 +0900 Subject: [PATCH 49/84] Add update command --- tools/evil-spammer/accountwallet/config.go | 16 +++++++++ tools/evil-spammer/parse.go | 38 ++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index fcb87b45b..0bf052715 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -24,6 +24,7 @@ const ( OperationDelegateAccount OperationStakeAccount OperationListAccounts + OperationUpdateAccount CmdNameCreateAccount = "create" CmdNameConvertAccount = "convert" @@ -32,6 +33,7 @@ const ( CmdNameDelegateAccount = "delegate" CmdNameStakeAccount = "stake" CmdNameListAccounts = "list" + CmdNameUpdateAccount = "update" ) func (a AccountOperation) String() string { @@ -43,6 +45,7 @@ func (a AccountOperation) String() string { CmdNameDelegateAccount, CmdNameStakeAccount, CmdNameListAccounts, + CmdNameUpdateAccount, }[a] } @@ -55,6 +58,7 @@ func AvailableCommands(cmd string) bool { CmdNameDelegateAccount: types.Void, CmdNameStakeAccount: types.Void, CmdNameListAccounts: types.Void, + CmdNameUpdateAccount: types.Void, } _, ok := availableCommands[cmd] @@ -165,6 +169,18 @@ func (a *StakeAccountParams) Type() AccountOperation { return OperationStakeAccount } +type UpdateAccountParams struct { + Alias string + BlockIssuerKey string + Mana uint64 + Amount uint64 + ExpirySlot uint64 +} + +func (a *UpdateAccountParams) Type() AccountOperation { + return OperationUpdateAccount +} + type StateData struct { Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index a274f17d0..35ee9f476 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -219,6 +219,13 @@ func parseAccountTestFlags(splitedCmds [][]string) []accountwallet.AccountSubcom } parsedCmds = append(parsedCmds, stakingAccountParams) + case "update": + updateAccountParams, err := parseUpdateAccountFlags(cmds[1:]) + if err != nil { + continue + } + + parsedCmds = append(parsedCmds, updateAccountParams) default: accountUsage() return nil @@ -411,6 +418,37 @@ func parseDelegateAccountFlags(subcommands []string) (*accountwallet.DelegateAcc }, nil } +func parseUpdateAccountFlags(subcommands []string) (*accountwallet.UpdateAccountParams, error) { + flagSet := flag.NewFlagSet("update", flag.ExitOnError) + alias := flagSet.String("alias", "", "The alias name of the account to update") + bik := flagSet.String("bik", "", "The block issuer key (in hex) to add") + amount := flagSet.Int64("addamount", 100, "The amount of token to add") + mana := flagSet.Int64("addmana", 100, "The amount of mana to add") + expirySlot := flagSet.Int64("expirySlot", 0, "Update the expiry slot of the account") + + if subcommands == nil { + flagSet.Usage() + + return nil, ierrors.Errorf("no subcommands") + } + + log.Infof("Parsing update account flags, subcommands: %v", subcommands) + err := flagSet.Parse(subcommands) + if err != nil { + log.Errorf("Cannot parse first `script` parameter") + + return nil, ierrors.Wrap(err, "cannot parse first `script` parameter") + } + + return &accountwallet.UpdateAccountParams{ + Alias: *alias, + BlockIssuerKey: *bik, + Amount: uint64(*amount), + Mana: uint64(*mana), + ExpirySlot: uint64(*expirySlot), + }, nil +} + // func parseCommitmentsSpamFlags() { // commitmentType := optionFlagSet.String("type", commitmentsSpamParams.CommitmentType, "Type of commitment spam. Possible values: 'latest' - valid commitment spam, 'random' - completely new, invalid cahin, 'fork' - forked chain, combine with 'forkAfter' parameter.") // rate := optionFlagSet.Int("rate", commitmentsSpamParams.Rate, "Commitment spam rate") From abe12f7a3af372f03f3a02bd21891f7799ab9c88 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Thu, 5 Oct 2023 17:02:44 +0900 Subject: [PATCH 50/84] Implement list command --- tools/evil-spammer/accountwallet/commands.go | 7 +++++++ tools/evil-spammer/accountwallet/config.go | 8 ++++++++ tools/evil-spammer/parse.go | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go index ceae55ba4..9c20f73db 100644 --- a/tools/evil-spammer/accountwallet/commands.go +++ b/tools/evil-spammer/accountwallet/commands.go @@ -25,6 +25,13 @@ func (a *AccountWallet) DestroyAccount(params *DestroyAccountParams) error { } func (a *AccountWallet) ListAccount() error { + fmt.Printf("%-10s \t%-33s\n\n", "Alias", "AccountID") + for _, accData := range a.accountsAliases { + fmt.Printf("%-10s \t", accData.Alias) + fmt.Printf("%-33s ", accData.AccountID.ToHex()) + fmt.Printf("\n") + } + return nil } diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 0bf052715..3c2114bb2 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -181,6 +181,14 @@ func (a *UpdateAccountParams) Type() AccountOperation { return OperationUpdateAccount } +type NoAccountParams struct { + Operation AccountOperation +} + +func (a *NoAccountParams) Type() AccountOperation { + return a.Operation +} + type StateData struct { Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index 35ee9f476..b9e7e3e8a 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -226,6 +226,10 @@ func parseAccountTestFlags(splitedCmds [][]string) []accountwallet.AccountSubcom } parsedCmds = append(parsedCmds, updateAccountParams) + case "list": + parsedCmds = append(parsedCmds, &accountwallet.NoAccountParams{ + Operation: accountwallet.OperationListAccounts, + }) default: accountUsage() return nil From 1cd688dd8511b5a946f760c1450aec99fa8c89e3 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Thu, 5 Oct 2023 17:18:19 +0900 Subject: [PATCH 51/84] Add accidentally removed defer function --- tools/evil-spammer/accountwallet/config.go | 4 ++-- tools/evil-spammer/main.go | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 3c2114bb2..7cf018ee2 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -74,7 +74,7 @@ var accountConfigFile = "account_config.json" var accountConfigJSON = `{ "bindAddress": "http://localhost:8080", - "accountStatesFile": "wallet.dat" + "accountStatesFile": "wallet.LOCK" }` // loadAccountConfig loads the config file. @@ -192,7 +192,7 @@ func (a *NoAccountParams) Type() AccountOperation { type StateData struct { Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` - AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint32"` + AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` } var dockerFaucetSeed = func() []byte { diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index eda7970b6..3b1eecf61 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -38,10 +38,12 @@ func main() { return } // save wallet - err = accountwallet.SaveState(accWallet) - if err != nil { - log.Errorf("Error while saving wallet state: %v", err) - } + defer func() { + err = accountwallet.SaveState(accWallet) + if err != nil { + log.Errorf("Error while saving wallet state: %v", err) + } + }() } // run selected test scenario switch Script { From 2b7fe2e6d4fa5ff0eb354573f47d50e9568df2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Sun, 8 Oct 2023 10:56:53 +0200 Subject: [PATCH 52/84] Create block in faucet request function --- tools/evil-spammer/accountwallet/faucet.go | 151 +++++++++++++++----- tools/evil-spammer/accountwallet/wallet.go | 11 +- tools/evil-spammer/evilwallet/evilwallet.go | 2 +- tools/evil-spammer/models/connector.go | 20 +++ 4 files changed, 146 insertions(+), 38 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index ba9878da6..556049f48 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -1,20 +1,106 @@ package accountwallet import ( + "crypto/ed25519" + "fmt" "sync" "time" + "golang.org/x/crypto/blake2b" + "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/iota-core/pkg/blockfactory" "github.com/iotaledger/iota-core/pkg/testsuite/mock" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" + "github.com/iotaledger/iota.go/v4/nodeclient/apimodels" ) -type Faucet struct { +func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { + signedTx, err := a.faucet.prepareFaucetRequest(receiveAddr, amount) + if err != nil { + log.Errorf("failed to prepare faucet request: %s", err) + + return nil, err + } + + issuerResp, err := a.client.GetBlockIssuance() + if err != nil { + log.Errorf("failed to get block issuance: %s", err) + + return nil, err + } + congestionResp, err := a.client.GetCongestion(a.faucet.account.ID()) + if err != nil { + log.Errorf("failed to get congestion: %s", err) + + return nil, err + } + + signedBlock, err := a.createBlock(issuerResp, congestionResp, signedTx) + if err != nil { + log.Errorf("failed to create block: %s", err) + + return nil, err + } + + _, err = clt.PostBlock(signedBlock) + if err != nil { + log.Errorf("failed to post block: %s", err) + + return nil, err + } + + // set remainder output to be reused by the Faucet wallet + a.faucet.unspentOutput = &models.Output{ + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), + Address: a.faucet.address, + Index: 0, + Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), + OutputStruct: signedTx.Transaction.Outputs[1], + } + + return &models.Output{ + OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 0), + Address: receiveAddr, + Index: 0, + Balance: signedTx.Transaction.Outputs[0].BaseTokenAmount(), + OutputStruct: signedTx.Transaction.Outputs[0], + }, nil +} + +func (a *AccountWallet) createBlock(issuerResp *apimodels.IssuanceBlockHeaderResponse, congestionResp *apimodels.CongestionResponse, payload iotago.Payload) (*iotago.ProtocolBlock, error) { + commitmentID, err := issuerResp.Commitment.ID() + if err != nil { + return nil, fmt.Errorf("failed to get commitment ID: %w", err) + } + + blockBuilder := builder.NewBasicBlockBuilder(a.api) + blockBuilder.SlotCommitmentID(commitmentID) + blockBuilder.LatestFinalizedSlot(issuerResp.LatestFinalizedSlot) + blockBuilder.IssuingTime(time.Now()) + blockBuilder.StrongParents(issuerResp.StrongParents) + fmt.Printf("WeakParents len: %v\n", len(issuerResp.WeakParents)) + blockBuilder.WeakParents(issuerResp.WeakParents) + fmt.Printf("ShallowLikeParents len: %v\n", len(issuerResp.ShallowLikeParents)) + blockBuilder.ShallowLikeParents(issuerResp.ShallowLikeParents) + blockBuilder.Payload(payload) + blockBuilder.MaxBurnedMana(congestionResp.ReferenceManaCost) + blockBuilder.Sign(a.faucet.account.ID(), a.faucet.account.PrivateKey()) + + blk, err := blockBuilder.Build() + if err != nil { + return nil, fmt.Errorf("failed to build block: %w", err) + } + + return blk, nil +} + +type faucet struct { address *iotago.Ed25519Address unspentOutput *models.Output - account iotago.AccountID + account blockfactory.Account seed []byte clt models.Client @@ -22,7 +108,7 @@ type Faucet struct { sync.Mutex } -func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet { +func newFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID, api iotago.API) *faucet { //get Faucet output and amount var faucetAmount iotago.BaseToken @@ -38,7 +124,7 @@ func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet } } - f := &Faucet{ + f := &faucet{ seed: dockerFaucetSeed(), clt: clt, } @@ -53,13 +139,38 @@ func NewFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID) *Faucet OutputStruct: faucetOutput, } + f.createFaucetAccountFromSeed(api) + return f } -func (f *Faucet) RequestFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { +func (f *faucet) createFaucetAccountFromSeed(api iotago.API) { + privateKey := ed25519.NewKeyFromSeed(f.seed[:]) + ed25519PubKey := privateKey.Public().(ed25519.PublicKey) + accIdBytes := blake2b.Sum256(ed25519PubKey[:]) + + var accountID iotago.AccountID + _, err := api.Decode(accIdBytes[:], &accountID) + if err != nil { + log.Panicf("failed to decode accountID: %s", err) + } + + f.account = blockfactory.NewEd25519Account(accountID, privateKey) +} + +func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken) (*iotago.SignedTransaction, error) { remainderAmount := f.unspentOutput.Balance - amount - txBuilder := builder.NewTransactionBuilder(clt.CurrentAPI()) + signedTx, err := f.createFaucetTransaction(receiveAddr, amount, remainderAmount) + if err != nil { + return nil, err + } + + return signedTx, nil +} + +func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iotago.BaseToken, remainderAmount iotago.BaseToken) (*iotago.SignedTransaction, error) { + txBuilder := builder.NewTransactionBuilder(f.clt.CurrentAPI()) txBuilder.AddInput(&builder.TxInput{ UnlockTarget: f.address, @@ -96,7 +207,7 @@ func (f *Faucet) RequestFunds(clt models.Client, receiveAddr iotago.Address, amo }) txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) - txBuilder.SetCreationSlot(clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) + txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) hdWallet := mock.NewHDWallet("", f.seed[:], 0) signedTx, err := txBuilder.Build(hdWallet.AddressSigner()) @@ -105,29 +216,5 @@ func (f *Faucet) RequestFunds(clt models.Client, receiveAddr iotago.Address, amo return nil, err } - - // send transaction - _, err = clt.PostTransaction(signedTx) - if err != nil { - log.Errorf("failed to post transaction: %s", err) - - return nil, err - } - - // set remainder output to be reused by the Faucet wallet - f.unspentOutput = &models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), - Address: f.address, - Index: 0, - Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), - OutputStruct: signedTx.Transaction.Outputs[1], - } - - return &models.Output{ - OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 0), - Address: receiveAddr, - Index: 0, - Balance: signedTx.Transaction.Outputs[0].BaseTokenAmount(), - OutputStruct: signedTx.Transaction.Outputs[0], - }, nil + return signedTx, err } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index bb7a50808..a2aa95af3 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -49,7 +49,7 @@ func SaveState(w *AccountWallet) error { } type AccountWallet struct { - Faucet *Faucet + faucet *faucet seed [32]byte accountsAliases map[string]*models.AccountData @@ -75,13 +75,14 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { optsRequestTicker: time.Second * 5, }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) + log.Infof("APi: %s", w.client.CurrentAPI()) w.api = w.client.CurrentAPI() - w.Faucet = NewFaucet(w.client, w.optsFaucetUnspendOutputID) + w.faucet = newFaucet(w.client, w.optsFaucetUnspendOutputID, w.api) }) } func (a *AccountWallet) LastFaucetUnspentOutputID() iotago.OutputID { - return a.Faucet.unspentOutput.OutputID + return a.faucet.unspentOutput.OutputID } // toAccountStateFile write account states to file. @@ -231,7 +232,7 @@ func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) hdWallet := mock.NewHDWallet("", a.seed[:], a.latestUsedIndex+1) receiverAddr := hdWallet.Address(addressType) - createdOutput, err := a.Faucet.RequestFunds(a.client, receiverAddr, iotago.BaseToken(amount)) + createdOutput, err := a.RequestFaucetFunds(a.client, receiverAddr, iotago.BaseToken(amount)) if err != nil { return nil, ierrors.Wrap(err, "failed to request funds from Faucet") } @@ -265,7 +266,7 @@ func (a *AccountWallet) destroyAccount(alias string) error { txBuilder.AddOutput(&iotago.BasicOutput{ Amount: accountOutput.BaseTokenAmount(), Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: a.Faucet.address}, + &iotago.AddressUnlockCondition{Address: a.faucet.address}, }, }) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index a88f6fa30..e056e3899 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -221,7 +221,7 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *models.Output receiveAddr := wallet.AddressOnIndex(0) clt := e.connector.GetClient() - output, err := e.accWallet.Faucet.RequestFunds(clt, receiveAddr, faucetTokensPerRequest) + output, err := e.accWallet.RequestFaucetFunds(clt, receiveAddr, faucetTokensPerRequest) if err != nil { return nil, ierrors.Wrap(err, "failed to request funds from faucet") } diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index 271bc13ac..2079725cf 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -163,6 +163,8 @@ type Client interface { URL() (cltID string) // PostTransaction sends a transaction to the Tangle via a given client. PostTransaction(tx *iotago.SignedTransaction) (iotago.BlockID, error) + // PostBlock sends a block to the Tangle via a given client. + PostBlock(block *iotago.ProtocolBlock) (iotago.BlockID, error) // PostData sends the given data (payload) by creating a block in the backend. PostData(data []byte) (blkID string, err error) // GetTransactionConfirmationState returns the AcceptanceState of a given transaction ID. @@ -239,6 +241,15 @@ func (c *WebClient) PostTransaction(tx *iotago.SignedTransaction) (blockID iotag return id, nil } +func (c *WebClient) PostBlock(block *iotago.ProtocolBlock) (blockID iotago.BlockID, err error) { + id, err := c.client.SubmitBlock(context.Background(), block) + if err != nil { + return + } + + return id, nil +} + // PostData sends the given data (payload) by creating a block in the backend. func (c *WebClient) PostData(data []byte) (blkID string, err error) { blockBuilder := builder.NewBasicBlockBuilder(c.client.CurrentAPI()) @@ -314,6 +325,15 @@ func (c *WebClient) GetBlockIssuance() (resp *apimodels.IssuanceBlockHeaderRespo return } +func (c *WebClient) GetCongestion(accountID iotago.AccountID) (resp *apimodels.CongestionResponse, err error) { + resp, err = c.client.Congestion(context.Background(), accountID) + if err != nil { + return + } + + return +} + // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// var _ Client = NewWebClient("abc") From f015002faa006c460d2a44e256b4bceb747a74ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Sun, 8 Oct 2023 14:34:12 +0200 Subject: [PATCH 53/84] Read accountID without api --- tools/evil-spammer/accountwallet/faucet.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 556049f48..8117ce4a8 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -139,21 +139,18 @@ func newFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID, api iot OutputStruct: faucetOutput, } - f.createFaucetAccountFromSeed(api) + f.createFaucetAccountFromSeed() return f } -func (f *faucet) createFaucetAccountFromSeed(api iotago.API) { +func (f *faucet) createFaucetAccountFromSeed() { privateKey := ed25519.NewKeyFromSeed(f.seed[:]) ed25519PubKey := privateKey.Public().(ed25519.PublicKey) accIdBytes := blake2b.Sum256(ed25519PubKey[:]) var accountID iotago.AccountID - _, err := api.Decode(accIdBytes[:], &accountID) - if err != nil { - log.Panicf("failed to decode accountID: %s", err) - } + copy(accountID[:], accIdBytes[:iotago.AccountIDLength]) f.account = blockfactory.NewEd25519Account(accountID, privateKey) } From e561b0f9dca521f8ab23c0b30cbe9d85ba1f177a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Sun, 8 Oct 2023 14:35:15 +0200 Subject: [PATCH 54/84] Cleanup config files, wallet uses only one file. --- tools/evil-spammer/accountwallet/config.go | 53 +++++++++++++--- tools/evil-spammer/accountwallet/faucet.go | 9 ++- tools/evil-spammer/accountwallet/options.go | 5 +- tools/evil-spammer/accountwallet/wallet.go | 11 ++-- tools/evil-spammer/config.go | 4 +- tools/evil-spammer/evilwallet/evilwallet.go | 14 ----- tools/evil-spammer/interactive/interactive.go | 3 +- tools/evil-spammer/main.go | 14 ++--- tools/evil-spammer/parse.go | 10 --- tools/evil-spammer/programs/params.go | 62 ------------------- tools/evil-spammer/programs/spammers.go | 3 - 11 files changed, 66 insertions(+), 122 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 7cf018ee2..9c0ee270a 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -66,19 +66,32 @@ func AvailableCommands(cmd string) bool { } type Configuration struct { - BindAddress string `json:"bindAddress,omitempty"` - AccountStatesFile string `json:"accountStatesFile,omitempty"` + BindAddress string `json:"bindAddress,omitempty"` + AccountStatesFile string `json:"accountStatesFile,omitempty"` + GenesisSeed string `json:"genesisSeed,omitempty"` + LastFauctUnspentOutputID string `json:"lastFaucetUnspentOutputID,omitempty"` + BlockIssuerPrivateKey string `json:"blockIssuerPrivateKey,omitempty"` + AccountID string `json:"accountID,omitempty"` } -var accountConfigFile = "account_config.json" +func (c *Configuration) Update(latestFaucetOutput iotago.OutputID) { + c.LastFauctUnspentOutputID = latestFaucetOutput.ToHex() +} + +var accountConfigFile = "config.json" -var accountConfigJSON = `{ +var ( + dockerAccountConfigJSON = `{ "bindAddress": "http://localhost:8080", - "accountStatesFile": "wallet.LOCK" -}` + "accountStatesFile": "wallet.dat", + "lastFaucetUnspentOutputID": "", + "genesisSeed": "7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih", + "blockIssuerPrivateKey": "db39d2fde6301d313b108dc9db1ee724d0f405f6fde966bd776365bc5f4a5fb31e4b21eb51dcddf65c20db1065e1f1514658b23a3ddbf48d30c0efc926a9a648", + "accountID": "0x6aee704f25558e8aa7630fed0121da53074188abc423b3c5810f80be4936eb6e"}` +) -// loadAccountConfig loads the config file. -func loadAccountConfig() *Configuration { +// LoadConfiguration loads the config file. +func LoadConfiguration() *Configuration { // open config file config := new(Configuration) file, err := os.Open(accountConfigFile) @@ -88,7 +101,7 @@ func loadAccountConfig() *Configuration { } //nolint:gosec // users should be able to read the file - if err = os.WriteFile(accountConfigFile, []byte(accountConfigJSON), 0o644); err != nil { + if err = os.WriteFile(accountConfigFile, []byte(dockerAccountConfigJSON), 0o644); err != nil { panic(err) } if file, err = os.Open(accountConfigFile); err != nil { @@ -105,6 +118,26 @@ func loadAccountConfig() *Configuration { return config } +func SaveConfiguration(config *Configuration) { + // open config file + file, err := os.Open(accountConfigFile) + if err != nil { + panic(err) + } + defer file.Close() + + jsonConfigs, err := json.MarshalIndent(config, "", " ") + + if err != nil { + log.Errorf("failed to write configs to file %s", err) + } + + //nolint:gosec // users should be able to read the file + if err = os.WriteFile(accountConfigFile, jsonConfigs, 0o644); err != nil { + panic(err) + } +} + type AccountSubcommands interface { Type() AccountOperation } @@ -195,7 +228,7 @@ type StateData struct { AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` } -var dockerFaucetSeed = func() []byte { +var dockerGenesisSeed = func() []byte { genesisSeed, err := base58.Decode("7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih") if err != nil { fmt.Printf("failed to decode base58 seed, using the default one: %v", err) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 8117ce4a8..45802119c 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -108,10 +108,15 @@ type faucet struct { sync.Mutex } -func newFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID, api iotago.API) *faucet { +func newFaucet(clt models.Client, hexFaucetUnspentOutputID string) *faucet { //get Faucet output and amount var faucetAmount iotago.BaseToken + faucetUnspentOutputID, err := iotago.OutputIDFromHex(hexFaucetUnspentOutputID) + if err != nil { + log.Warnf("Cannot parse faucet output id from config: %v", err) + } + faucetOutput := clt.GetOutput(faucetUnspentOutputID) if faucetOutput != nil { faucetAmount = faucetOutput.BaseTokenAmount() @@ -125,7 +130,7 @@ func newFaucet(clt models.Client, faucetUnspentOutputID iotago.OutputID, api iot } f := &faucet{ - seed: dockerFaucetSeed(), + seed: dockerGenesisSeed(), clt: clt, } diff --git a/tools/evil-spammer/accountwallet/options.go b/tools/evil-spammer/accountwallet/options.go index 02f63c174..fb3dc82ea 100644 --- a/tools/evil-spammer/accountwallet/options.go +++ b/tools/evil-spammer/accountwallet/options.go @@ -2,7 +2,6 @@ package accountwallet import ( "github.com/iotaledger/hive.go/runtime/options" - iotago "github.com/iotaledger/iota.go/v4" ) // WithClientURL sets the client bind address. @@ -18,8 +17,8 @@ func WithAccountStatesFile(fileName string) options.Option[AccountWallet] { } } -func WithFaucetUnspendOutputID(id iotago.OutputID) options.Option[AccountWallet] { +func WithFaucetUnspendOutputID(hexID string) options.Option[AccountWallet] { return func(w *AccountWallet) { - w.optsFaucetUnspendOutputID = id + w.optsFaucetUnspendOutputID = hexID } } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index a2aa95af3..4991088b2 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -19,9 +19,7 @@ import ( var log = logger.New("AccountWallet") -func Run(lastFaucetUnspentOutputID iotago.OutputID) (*AccountWallet, error) { - // read config here - config := loadAccountConfig() +func Run(config *Configuration) (*AccountWallet, error) { var opts []options.Option[AccountWallet] if config.BindAddress != "" { @@ -31,7 +29,7 @@ func Run(lastFaucetUnspentOutputID iotago.OutputID) (*AccountWallet, error) { opts = append(opts, WithAccountStatesFile(config.AccountStatesFile)) } - opts = append(opts, WithFaucetUnspendOutputID(lastFaucetUnspentOutputID)) + opts = append(opts, WithFaucetUnspendOutputID(config.LastFauctUnspentOutputID)) wallet := NewAccountWallet(opts...) @@ -62,7 +60,7 @@ type AccountWallet struct { optsClientBindAddress string optsAccountStatesFile string - optsFaucetUnspendOutputID iotago.OutputID + optsFaucetUnspendOutputID string optsRequestTimeout time.Duration optsRequestTicker time.Duration } @@ -75,9 +73,8 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { optsRequestTicker: time.Second * 5, }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) - log.Infof("APi: %s", w.client.CurrentAPI()) w.api = w.client.CurrentAPI() - w.faucet = newFaucet(w.client, w.optsFaucetUnspendOutputID, w.api) + w.faucet = newFaucet(w.client, w.optsFaucetUnspendOutputID) }) } diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index 8831ae907..7803dd982 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -7,7 +7,6 @@ import ( "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/programs" "github.com/iotaledger/iota-core/tools/evil-spammer/spammer" - iotago "github.com/iotaledger/iota.go/v4" ) // Nodes used during the test, use at least two nodes to be able to doublespend. @@ -45,8 +44,7 @@ var ( EnableRateSetter: false, } - accountsSubcommandsFlags []accountwallet.AccountSubcommands - lastFaucetUnspendOutputID iotago.OutputID + accountsSubcommandsFlags []accountwallet.AccountSubcommands //nolint:godot // commitmentsSpamParams = CommitmentsSpamParams{ diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index e056e3899..2e20e6759 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -2,12 +2,9 @@ package evilwallet import ( "fmt" - "log" "sync" "time" - "github.com/mr-tron/base58" - "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" @@ -33,17 +30,6 @@ const ( var ( defaultClientsURLs = []string{"http://localhost:8080", "http://localhost:8090"} - - genesisTransactionID = iotago.TransactionIDRepresentingData(0, []byte("genesis")) - - dockerFaucetSeed = func() []byte { - genesisSeed, err := base58.Decode("7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih") - if err != nil { - log.Fatal(ierrors.Errorf("failed to decode base58 seed, using the default one: %w", err)) - } - - return genesisSeed - } ) // region EvilWallet /////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/evil-spammer/interactive/interactive.go b/tools/evil-spammer/interactive/interactive.go index a3a92ff55..620f1c9b7 100644 --- a/tools/evil-spammer/interactive/interactive.go +++ b/tools/evil-spammer/interactive/interactive.go @@ -26,6 +26,7 @@ const ( maxConcurrentSpams = 5 lastSpamsShowed = 15 timeFormat = "2006/01/02 15:04:05" + configFilename = "interactive_config.json" ) const ( @@ -704,7 +705,7 @@ func (m *Mode) updateSentStatistic(s *spammer.Spammer, id int) { // load the config file. func (m *Mode) loadConfig() { // open config file - file, err := os.Open("config.json") + file, err := os.Open(configFilename) if err != nil { if !os.IsNotExist(err) { panic(err) diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 3b1eecf61..660a2f62a 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -31,18 +31,23 @@ func main() { var accWallet *accountwallet.AccountWallet var err error if Script == "basic" || Script == "accounts" { + // read config here + config := accountwallet.LoadConfiguration() // load wallet - accWallet, err = accountwallet.Run(lastFaucetUnspendOutputID) + accWallet, err = accountwallet.Run(config) if err != nil { log.Warn(err) return } - // save wallet + // save wallet and latest faucet output defer func() { err = accountwallet.SaveState(accWallet) if err != nil { log.Errorf("Error while saving wallet state: %v", err) } + config.Update(accWallet.LastFaucetUnspentOutputID()) + accountwallet.SaveConfiguration(config) + }() } // run selected test scenario @@ -66,11 +71,6 @@ func accountsSubcommands(wallet *accountwallet.AccountWallet, subcommands []acco for _, sub := range subcommands { accountsSubcommand(wallet, sub) } - - // save faucet unspent output id - programs.SaveConfigsToFile(&programs.BasicConfig{ - LastFaucetUnspentOutputID: wallet.LastFaucetUnspentOutputID().ToHex(), - }) } func accountsSubcommand(wallet *accountwallet.AccountWallet, sub accountwallet.AccountSubcommands) { diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index b9e7e3e8a..51e732386 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -11,8 +11,6 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" - "github.com/iotaledger/iota-core/tools/evil-spammer/programs" - iotago "github.com/iotaledger/iota.go/v4" ) func parseFlags() (help bool) { @@ -36,12 +34,6 @@ func parseFlags() (help bool) { splitedCmds := readSubcommandsAndFlagSets(subcommands) accountsSubcommandsFlags = parseAccountTestFlags(splitedCmds) - basicConfig := programs.LoadBasicConfig() - outputID, err := iotago.OutputIDFromHex(basicConfig.LastFaucetUnspentOutputID) - if err != nil { - log.Warnf("Cannot parse faucet output id from config: %v", err) - } - lastFaucetUnspendOutputID = outputID case "quick": parseQuickTestFlags() // case SpammerTypeCommitments: @@ -123,8 +115,6 @@ func parseBasicSpamFlags() { if *blkNum == "" && *duration != "" { customSpamParams.BlkToBeSent = make([]int, len(customSpamParams.Durations)) } - - customSpamParams.Config = programs.LoadBasicConfig() } func parseQuickTestFlags() { diff --git a/tools/evil-spammer/programs/params.go b/tools/evil-spammer/programs/params.go index 009d18f9f..f0e1d2070 100644 --- a/tools/evil-spammer/programs/params.go +++ b/tools/evil-spammer/programs/params.go @@ -1,8 +1,6 @@ package programs import ( - "encoding/json" - "os" "time" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" @@ -21,64 +19,4 @@ type CustomSpamParams struct { DeepSpam bool EnableRateSetter bool AccountAlias string - - Config *BasicConfig -} - -type BasicConfig struct { - LastFaucetUnspentOutputID string `json:"lastFaucetUnspentOutputId"` -} - -var basicConfigFile = "basic_config.json" - -var basicConfigJSON = `{ - "lastFaucetUnspentOutputId": "" -}` - -// LoadBasicConfig loads the config file. -func LoadBasicConfig() *BasicConfig { - // open config file - config := new(BasicConfig) - file, err := os.Open(basicConfigFile) - if err != nil { - if !os.IsNotExist(err) { - panic(err) - } - - //nolint:gosec // users should be able to read the file - if err = os.WriteFile(basicConfigFile, []byte(basicConfigJSON), 0o644); err != nil { - panic(err) - } - if file, err = os.Open(basicConfigFile); err != nil { - panic(err) - } - } - defer file.Close() - - // decode config file - if err = json.NewDecoder(file).Decode(config); err != nil { - panic(err) - } - - return config -} - -func SaveConfigsToFile(config *BasicConfig) { - // open config file - file, err := os.Open(basicConfigFile) - if err != nil { - panic(err) - } - defer file.Close() - - jsonConfigs, err := json.MarshalIndent(config, "", " ") - - if err != nil { - log.Errorf("failed to write configs to file %s", err) - } - - //nolint:gosec // users should be able to read the file - if err = os.WriteFile(basicConfigFile, jsonConfigs, 0o644); err != nil { - panic(err) - } } diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index bf92e21fb..4cf3799f0 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -28,9 +28,6 @@ func CustomSpam(params *CustomSpamParams, accWallet *accountwallet.AccountWallet if err != nil { panic(err) } - SaveConfigsToFile(&BasicConfig{ - LastFaucetUnspentOutputID: w.LastFaucetUnspentOutput().ToHex(), - }) } for i, sType := range params.SpamTypes { From 59aea8d6c356ad73b1b8805f07625d6e84c18ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Sun, 8 Oct 2023 15:56:49 +0200 Subject: [PATCH 55/84] Refactor faucet and genesis config --- tools/evil-spammer/accountwallet/config.go | 12 ----- tools/evil-spammer/accountwallet/faucet.go | 59 ++++++++++----------- tools/evil-spammer/accountwallet/options.go | 4 +- tools/evil-spammer/accountwallet/wallet.go | 22 ++++---- 4 files changed, 42 insertions(+), 55 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 9c0ee270a..f3ccc6133 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -2,11 +2,8 @@ package accountwallet import ( "encoding/json" - "fmt" "os" - "github.com/mr-tron/base58/base58" - "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" @@ -228,13 +225,4 @@ type StateData struct { AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` } -var dockerGenesisSeed = func() []byte { - genesisSeed, err := base58.Decode("7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih") - if err != nil { - fmt.Printf("failed to decode base58 seed, using the default one: %v", err) - } - - return genesisSeed -} - var genesisTransactionID = iotago.TransactionIDRepresentingData(0, []byte("genesis")) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 45802119c..efdb444d3 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -1,12 +1,11 @@ package accountwallet import ( - "crypto/ed25519" "fmt" "sync" "time" - "golang.org/x/crypto/blake2b" + "github.com/mr-tron/base58" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/iota-core/pkg/blockfactory" @@ -55,7 +54,7 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago // set remainder output to be reused by the Faucet wallet a.faucet.unspentOutput = &models.Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), - Address: a.faucet.address, + Address: a.faucet.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address), Index: 0, Balance: signedTx.Transaction.Outputs[1].BaseTokenAmount(), OutputStruct: signedTx.Transaction.Outputs[1], @@ -97,22 +96,28 @@ func (a *AccountWallet) createBlock(issuerResp *apimodels.IssuanceBlockHeaderRes return blk, nil } +type faucetParams struct { + latestUsedOutputID string + faucetPrivateKey string + faucetAccountID string + genesisSeed string +} + type faucet struct { - address *iotago.Ed25519Address - unspentOutput *models.Output - account blockfactory.Account + unspentOutput *models.Output + account blockfactory.Account + genesisHdWallet *mock.HDWallet - seed []byte - clt models.Client + clt models.Client sync.Mutex } -func newFaucet(clt models.Client, hexFaucetUnspentOutputID string) *faucet { +func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { //get Faucet output and amount var faucetAmount iotago.BaseToken - faucetUnspentOutputID, err := iotago.OutputIDFromHex(hexFaucetUnspentOutputID) + faucetUnspentOutputID, err := iotago.OutputIDFromHex(faucetParams.latestUsedOutputID) if err != nil { log.Warnf("Cannot parse faucet output id from config: %v", err) } @@ -128,38 +133,29 @@ func newFaucet(clt models.Client, hexFaucetUnspentOutputID string) *faucet { faucetAmount = faucetOutput.BaseTokenAmount() } } + genesisSeed, err := base58.Decode(faucetParams.genesisSeed) + if err != nil { + fmt.Printf("failed to decode base58 seed, using the default one: %v", err) + } f := &faucet{ - seed: dockerGenesisSeed(), - clt: clt, + clt: clt, + account: blockfactory.AccountFromParams(faucetParams.faucetAccountID, faucetParams.faucetPrivateKey), + genesisHdWallet: mock.NewHDWallet("", genesisSeed, 0), } - hdWallet := mock.NewHDWallet("", f.seed[:], 0) - f.address = hdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address) + f.genesisHdWallet.Address() f.unspentOutput = &models.Output{ - Address: f.address, + Address: f.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address), Index: 0, OutputID: faucetUnspentOutputID, Balance: faucetAmount, OutputStruct: faucetOutput, } - f.createFaucetAccountFromSeed() - return f } -func (f *faucet) createFaucetAccountFromSeed() { - privateKey := ed25519.NewKeyFromSeed(f.seed[:]) - ed25519PubKey := privateKey.Public().(ed25519.PublicKey) - accIdBytes := blake2b.Sum256(ed25519PubKey[:]) - - var accountID iotago.AccountID - copy(accountID[:], accIdBytes[:iotago.AccountIDLength]) - - f.account = blockfactory.NewEd25519Account(accountID, privateKey) -} - func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken) (*iotago.SignedTransaction, error) { remainderAmount := f.unspentOutput.Balance - amount @@ -175,7 +171,7 @@ func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iota txBuilder := builder.NewTransactionBuilder(f.clt.CurrentAPI()) txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: f.address, + UnlockTarget: f.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address), InputID: f.unspentOutput.OutputID, Input: f.unspentOutput.OutputStruct, }) @@ -204,15 +200,14 @@ func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iota txBuilder.AddOutput(&iotago.BasicOutput{ Amount: remainderAmount, Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: f.address}, + &iotago.AddressUnlockCondition{Address: f.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address)}, }, }) txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) - hdWallet := mock.NewHDWallet("", f.seed[:], 0) - signedTx, err := txBuilder.Build(hdWallet.AddressSigner()) + signedTx, err := txBuilder.Build(f.genesisHdWallet.AddressSigner()) if err != nil { log.Errorf("failed to build transaction: %s", err) diff --git a/tools/evil-spammer/accountwallet/options.go b/tools/evil-spammer/accountwallet/options.go index fb3dc82ea..51b28fcd7 100644 --- a/tools/evil-spammer/accountwallet/options.go +++ b/tools/evil-spammer/accountwallet/options.go @@ -17,8 +17,8 @@ func WithAccountStatesFile(fileName string) options.Option[AccountWallet] { } } -func WithFaucetUnspendOutputID(hexID string) options.Option[AccountWallet] { +func WithFaucetAccountParams(params *faucetParams) options.Option[AccountWallet] { return func(w *AccountWallet) { - w.optsFaucetUnspendOutputID = hexID + w.optsFaucetParams = params } } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 4991088b2..e6950a8f6 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -20,7 +20,6 @@ import ( var log = logger.New("AccountWallet") func Run(config *Configuration) (*AccountWallet, error) { - var opts []options.Option[AccountWallet] if config.BindAddress != "" { opts = append(opts, WithClientURL(config.BindAddress)) @@ -29,7 +28,12 @@ func Run(config *Configuration) (*AccountWallet, error) { opts = append(opts, WithAccountStatesFile(config.AccountStatesFile)) } - opts = append(opts, WithFaucetUnspendOutputID(config.LastFauctUnspentOutputID)) + opts = append(opts, WithFaucetAccountParams(&faucetParams{ + latestUsedOutputID: config.LastFauctUnspentOutputID, + genesisSeed: config.GenesisSeed, + faucetPrivateKey: config.BlockIssuerPrivateKey, + faucetAccountID: config.AccountID, + })) wallet := NewAccountWallet(opts...) @@ -58,11 +62,11 @@ type AccountWallet struct { client *models.WebClient api iotago.API - optsClientBindAddress string - optsAccountStatesFile string - optsFaucetUnspendOutputID string - optsRequestTimeout time.Duration - optsRequestTicker time.Duration + optsClientBindAddress string + optsAccountStatesFile string + optsFaucetParams *faucetParams + optsRequestTimeout time.Duration + optsRequestTicker time.Duration } func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { @@ -74,7 +78,7 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() - w.faucet = newFaucet(w.client, w.optsFaucetUnspendOutputID) + w.faucet = newFaucet(w.client, w.optsFaucetParams) }) } @@ -263,7 +267,7 @@ func (a *AccountWallet) destroyAccount(alias string) error { txBuilder.AddOutput(&iotago.BasicOutput{ Amount: accountOutput.BaseTokenAmount(), Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: a.faucet.address}, + &iotago.AddressUnlockCondition{Address: a.faucet.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address)}, }, }) From 0eac6ac92c3617d73372cf45a770faa89c5e2bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Mon, 9 Oct 2023 09:38:25 +0200 Subject: [PATCH 56/84] Start replacing post tx with post block --- tools/evil-spammer/accountwallet/faucet.go | 58 +++++++++++++++---- tools/evil-spammer/accountwallet/wallet.go | 5 +- tools/evil-spammer/evilwallet/evilwallet.go | 5 ++ tools/evil-spammer/models/connector.go | 22 ------- tools/evil-spammer/spammer/errors.go | 3 +- tools/evil-spammer/spammer/spammer.go | 52 ++++++----------- .../spammer/spamming_functions.go | 15 +++-- 7 files changed, 82 insertions(+), 78 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index efdb444d3..0424b695f 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -24,20 +24,12 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago return nil, err } - issuerResp, err := a.client.GetBlockIssuance() - if err != nil { - log.Errorf("failed to get block issuance: %s", err) - - return nil, err - } - congestionResp, err := a.client.GetCongestion(a.faucet.account.ID()) + issuerResp, congestionResp, err := a.requestBlockData() if err != nil { - log.Errorf("failed to get congestion: %s", err) - return nil, err } - signedBlock, err := a.createBlock(issuerResp, congestionResp, signedTx) + signedBlock, err := a.createBlock(issuerResp, congestionResp, signedTx, a.faucet.account) if err != nil { log.Errorf("failed to create block: %s", err) @@ -69,7 +61,49 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago }, nil } -func (a *AccountWallet) createBlock(issuerResp *apimodels.IssuanceBlockHeaderResponse, congestionResp *apimodels.CongestionResponse, payload iotago.Payload) (*iotago.ProtocolBlock, error) { +func (a *AccountWallet) requestBlockData() (*apimodels.IssuanceBlockHeaderResponse, *apimodels.CongestionResponse, error) { + issuerResp, err := a.client.GetBlockIssuance() + if err != nil { + log.Errorf("failed to get block issuance: %s", err) + + return nil, nil, err + } + + congestionResp, err := a.client.GetCongestion(a.faucet.account.ID()) + if err != nil { + log.Errorf("failed to get congestion: %s", err) + + return nil, nil, err + } + + return issuerResp, congestionResp, nil +} + +func (a *AccountWallet) PostBlock(clt models.Client, payload iotago.Payload, issuer blockfactory.Account) error { + issuerResp, congestionResp, err := a.requestBlockData() + if err != nil { + return err + } + + signedBlock, err := a.createBlock(issuerResp, congestionResp, payload, issuer) + if err != nil { + log.Errorf("failed to create block: %s", err) + + return err + } + + _, err = clt.PostBlock(signedBlock) + if err != nil { + log.Errorf("failed to post block: %s", err) + + return err + } + + return nil + +} + +func (a *AccountWallet) createBlock(issuerResp *apimodels.IssuanceBlockHeaderResponse, congestionResp *apimodels.CongestionResponse, payload iotago.Payload, issuer blockfactory.Account) (*iotago.ProtocolBlock, error) { commitmentID, err := issuerResp.Commitment.ID() if err != nil { return nil, fmt.Errorf("failed to get commitment ID: %w", err) @@ -86,7 +120,7 @@ func (a *AccountWallet) createBlock(issuerResp *apimodels.IssuanceBlockHeaderRes blockBuilder.ShallowLikeParents(issuerResp.ShallowLikeParents) blockBuilder.Payload(payload) blockBuilder.MaxBurnedMana(congestionResp.ReferenceManaCost) - blockBuilder.Sign(a.faucet.account.ID(), a.faucet.account.PrivateKey()) + blockBuilder.Sign(issuer.ID(), issuer.PrivateKey()) blk, err := blockBuilder.Build() if err != nil { diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index e6950a8f6..d8829f55f 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -276,10 +276,7 @@ func (a *AccountWallet) destroyAccount(alias string) error { return ierrors.Wrap(err, "failed to build transaction") } - _, err = a.client.PostTransaction(tx) - if err != nil { - return ierrors.Wrap(err, "failed to post transaction") - } + // TODO createa and post block // remove account from wallet delete(a.accountsAliases, alias) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 2e20e6759..8e1de12cb 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -105,6 +105,11 @@ func (e *EvilWallet) RemoveClient(clientURL string) { e.connector.RemoveClient(clientURL) } +func (e *EvilWallet) CreateBlock() *iotago.ProtocolBlock { + e.accWallet.PostBlock(clt, tx, issuer) + +} + // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region EvilWallet Faucet Requests /////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index dd7f2fdde..c0d4098ea 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -161,8 +161,6 @@ func (c *WebClients) RemoveClient(url string) { type Client interface { // URL returns a client API url. URL() (cltID string) - // PostTransaction sends a transaction to the Tangle via a given client. - PostTransaction(tx *iotago.SignedTransaction) (iotago.BlockID, error) // PostBlock sends a block to the Tangle via a given client. PostBlock(block *iotago.ProtocolBlock) (iotago.BlockID, error) // PostData sends the given data (payload) by creating a block in the backend. @@ -221,26 +219,6 @@ func NewWebClient(url string, opts ...options.Option[WebClient]) *WebClient { }) } -// PostTransaction sends a transaction to the Tangle via a given client. -func (c *WebClient) PostTransaction(tx *iotago.SignedTransaction) (blockID iotago.BlockID, err error) { - blockBuilder := builder.NewBasicBlockBuilder(c.client.CurrentAPI()) - - blockBuilder.Payload(tx) - blockBuilder.IssuingTime(time.Time{}) - - blk, err := blockBuilder.Build() - if err != nil { - return iotago.EmptyBlockID(), err - } - - id, err := c.client.SubmitBlock(context.Background(), blk) - if err != nil { - return - } - - return id, nil -} - func (c *WebClient) PostBlock(block *iotago.ProtocolBlock) (blockID iotago.BlockID, err error) { id, err := c.client.SubmitBlock(context.Background(), block) if err != nil { diff --git a/tools/evil-spammer/spammer/errors.go b/tools/evil-spammer/spammer/errors.go index 95f8a5b91..667ddf2ae 100644 --- a/tools/evil-spammer/spammer/errors.go +++ b/tools/evil-spammer/spammer/errors.go @@ -10,10 +10,11 @@ import ( ) var ( - ErrFailPostTransaction = ierrors.New("failed to post transaction") + ErrFailPostBlock = ierrors.New("failed to post block") ErrFailSendDataBlock = ierrors.New("failed to send a data block") ErrFailGetReferences = ierrors.New("failed to get references") ErrTransactionIsNil = ierrors.New("provided transaction is nil") + ErrBlockIsNil = ierrors.New("provided block is nil") ErrFailToPrepareBatch = ierrors.New("custom conflict batch could not be prepared") ErrInsufficientClients = ierrors.New("insufficient clients to send conflicts") ErrInputsNotSolid = ierrors.New("not all inputs are solid") diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index a0794bcba..6056ed3c6 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -9,7 +9,6 @@ import ( appLogger "github.com/iotaledger/hive.go/app/logger" "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" @@ -232,50 +231,35 @@ func (s *Spammer) StopSpamming() { s.shutdown <- types.Void } -// PostTransaction use provided client to issue a transaction. It chooses API method based on Spammer options. Counts errors, -// counts transactions and provides debug logs. -func (s *Spammer) PostTransaction(signedTx *iotago.SignedTransaction, clt models.Client) { - if signedTx == nil { - s.log.Debug(ErrTransactionIsNil) - s.ErrCounter.CountError(ErrTransactionIsNil) +func (s *Spammer) PrepareAndPostBlock(payload iotago.Payload, clt models.Client) { + if block == nil { + s.log.Debug(ErrBlockIsNil) + s.ErrCounter.CountError(ErrBlockIsNil) return } - txID := lo.PanicOnErr(signedTx.Transaction.ID()) - allSolid := s.handleSolidityForReuseOutputs(clt, signedTx) - if !allSolid { - s.log.Debug(ErrInputsNotSolid) - s.ErrCounter.CountError(ierrors.Wrapf(ErrInputsNotSolid, "txID: %s", txID.ToHex())) - - return - } - - blockID, err := clt.PostTransaction(signedTx) + s.EvilWallet. + _, err := clt.PostBlock(block) if err != nil { - s.log.Debug(ierrors.Wrapf(ErrFailPostTransaction, err.Error())) - s.ErrCounter.CountError(ierrors.Wrapf(ErrFailPostTransaction, err.Error())) + s.log.Debug(ierrors.Wrapf(ErrFailPostBlock, err.Error())) + s.ErrCounter.CountError(ierrors.Wrapf(ErrFailPostBlock, err.Error())) return } - if s.EvilScenario.OutputWallet.Type() == evilwallet.Reuse { - var outputIDs iotago.OutputIDs - for index := range signedTx.Transaction.Outputs { - outputIDs = append(outputIDs, iotago.OutputIDFromTransactionIDAndIndex(txID, uint16(index))) + + // reuse outputs + if payload.PayloadType() == iotago.PayloadSignedTransaction { + if s.EvilScenario.OutputWallet.Type() == evilwallet.Reuse { + var outputIDs iotago.OutputIDs + for index := range signedTx.Transaction.Outputs { + outputIDs = append(outputIDs, iotago.OutputIDFromTransactionIDAndIndex(txID, uint16(index))) + } + s.EvilWallet.SetTxOutputsSolid(outputIDs, clt.URL()) } - s.EvilWallet.SetTxOutputsSolid(outputIDs, clt.URL()) } - count := s.State.txSent.Add(1) - s.log.Debugf("%s: Last transaction sent, ID: %s, txCount: %d", blockID.ToHex(), txID.ToHex(), count) -} - -func (s *Spammer) handleSolidityForReuseOutputs(_ models.Client, _ *iotago.SignedTransaction) (ok bool) { - // ok = s.EvilWallet.AwaitInputsSolidity(tx.SignedTransaction().Inputs(), clt) - // if s.EvilScenario.OutputWallet.Type() == wallet.Reuse { - // s.EvilWallet.AddReuseOutputsToThePool(tx.SignedTransaction().Outputs()) - // } - return true + s.log.Debugf("Last block sent, ID: %s, txCount: %d", blockID.ToHex(), count) } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/evil-spammer/spammer/spamming_functions.go b/tools/evil-spammer/spammer/spamming_functions.go index cf189f381..77fce19d4 100644 --- a/tools/evil-spammer/spammer/spamming_functions.go +++ b/tools/evil-spammer/spammer/spamming_functions.go @@ -56,10 +56,8 @@ func CustomConflictSpammingFunc(s *Spammer) { // sleep randomly to avoid issuing blocks in different goroutines at once //nolint:gosec time.Sleep(time.Duration(rand.Float64()*100) * time.Millisecond) - // if err = wallet.RateSetterSleep(clt, s.UseRateSetter); err != nil { - // s.ErrCounter.CountError(err) - // } - s.PostTransaction(tx, clt) + + s.PostBlock(tx, clt) }(clients[i], tx) } wg.Wait() @@ -77,7 +75,14 @@ func AccountSpammingFunction(s *Spammer) { s.log.Debugf(ierrors.Wrap(ErrFailToPrepareBatch, err.Error()).Error()) s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) } - s.PostTransaction(tx, clt) + blk, err := s.EvilWallet.PrepareBlock(tx, clt) + if err != nil { + s.ErrCounter.CountError(ierrors.Wrap(ErrFailPrepareBlock, err.Error())) + + return + } + + s.PostBlock(blk, tx, clt) s.State.batchPrepared.Add(1) s.EvilWallet.ClearAliases(aliases) From 530931f62759a060cb97616ce10cd25b7ad73613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 10 Oct 2023 17:36:01 +0200 Subject: [PATCH 57/84] Move block issuance to evilwallet --- tools/evil-spammer/accountwallet/commands.go | 8 +- tools/evil-spammer/accountwallet/faucet.go | 82 +++++-------------- tools/evil-spammer/accountwallet/wallet.go | 53 ++++++++---- tools/evil-spammer/config.go | 4 +- tools/evil-spammer/evilwallet/evilscenario.go | 3 +- tools/evil-spammer/evilwallet/evilwallet.go | 27 ++++-- tools/evil-spammer/models/connector.go | 7 +- tools/evil-spammer/models/output.go | 11 +-- tools/evil-spammer/programs/spammers.go | 5 ++ tools/evil-spammer/spammer/errors.go | 4 +- tools/evil-spammer/spammer/options.go | 7 ++ tools/evil-spammer/spammer/spammer.go | 59 ++++++++----- .../spammer/spamming_functions.go | 11 +-- 13 files changed, 159 insertions(+), 122 deletions(-) diff --git a/tools/evil-spammer/accountwallet/commands.go b/tools/evil-spammer/accountwallet/commands.go index 9c20f73db..37a7843cb 100644 --- a/tools/evil-spammer/accountwallet/commands.go +++ b/tools/evil-spammer/accountwallet/commands.go @@ -8,12 +8,12 @@ import ( ) func (a *AccountWallet) CreateAccount(params *CreateAccountParams) (iotago.AccountID, error) { - accountOutput, err := a.getFunds(params.Amount, iotago.AddressImplicitAccountCreation) + implicitAccountOutput, privateKey, err := a.getFunds(params.Amount, iotago.AddressImplicitAccountCreation) if err != nil { - return iotago.EmptyAccountID(), ierrors.Wrap(err, "Failed to create account") + return iotago.EmptyAccountID, ierrors.Wrap(err, "Failed to create account") } - accountID := a.registerAccount(params.Alias, accountOutput.OutputID, a.latestUsedIndex) + accountID := a.registerAccount(params.Alias, implicitAccountOutput.OutputID, a.latestUsedIndex, privateKey) fmt.Printf("Created account %s with %d tokens\n", accountID.ToHex(), params.Amount) @@ -28,7 +28,7 @@ func (a *AccountWallet) ListAccount() error { fmt.Printf("%-10s \t%-33s\n\n", "Alias", "AccountID") for _, accData := range a.accountsAliases { fmt.Printf("%-10s \t", accData.Alias) - fmt.Printf("%-33s ", accData.AccountID.ToHex()) + fmt.Printf("%-33s ", accData.Account.ID().ToHex()) fmt.Printf("\n") } diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 0424b695f..250cc0fab 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -8,14 +8,16 @@ import ( "github.com/mr-tron/base58" "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/iota-core/pkg/blockfactory" + "github.com/iotaledger/iota-core/pkg/blockhandler" "github.com/iotaledger/iota-core/pkg/testsuite/mock" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" - "github.com/iotaledger/iota.go/v4/nodeclient/apimodels" + "github.com/iotaledger/iota.go/v4/nodeclient" ) +const FaucetAccountAlias = "faucet" + func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { signedTx, err := a.faucet.prepareFaucetRequest(receiveAddr, amount) if err != nil { @@ -24,25 +26,13 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago return nil, err } - issuerResp, congestionResp, err := a.requestBlockData() - if err != nil { - return nil, err - } - - signedBlock, err := a.createBlock(issuerResp, congestionResp, signedTx, a.faucet.account) + _, err = a.PostWithBlock(clt, signedTx, a.faucet.account) if err != nil { log.Errorf("failed to create block: %s", err) return nil, err } - _, err = clt.PostBlock(signedBlock) - if err != nil { - log.Errorf("failed to post block: %s", err) - - return nil, err - } - // set remainder output to be reused by the Faucet wallet a.faucet.unspentOutput = &models.Output{ OutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(signedTx.Transaction.ID()), 1), @@ -61,65 +51,37 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago }, nil } -func (a *AccountWallet) requestBlockData() (*apimodels.IssuanceBlockHeaderResponse, *apimodels.CongestionResponse, error) { - issuerResp, err := a.client.GetBlockIssuance() - if err != nil { - log.Errorf("failed to get block issuance: %s", err) - - return nil, nil, err - } - - congestionResp, err := a.client.GetCongestion(a.faucet.account.ID()) +func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account) (iotago.BlockID, error) { + signedBlock, err := a.CreateBlock(clt.Client(), payload, issuer) if err != nil { - log.Errorf("failed to get congestion: %s", err) - - return nil, nil, err - } - - return issuerResp, congestionResp, nil -} + log.Errorf("failed to create block: %s", err) -func (a *AccountWallet) PostBlock(clt models.Client, payload iotago.Payload, issuer blockfactory.Account) error { - issuerResp, congestionResp, err := a.requestBlockData() - if err != nil { - return err + return iotago.EmptyBlockID, err } - signedBlock, err := a.createBlock(issuerResp, congestionResp, payload, issuer) + _, err = clt.PostBlock(signedBlock) if err != nil { - log.Errorf("failed to create block: %s", err) + log.Errorf("failed to post block: %s", err) - return err + return iotago.EmptyBlockID, err } - _, err = clt.PostBlock(signedBlock) + blockID, err := signedBlock.ID() if err != nil { - log.Errorf("failed to post block: %s", err) + log.Errorf("failed to get block id: %s", err) - return err + return iotago.EmptyBlockID, err } - return nil + return blockID, nil } -func (a *AccountWallet) createBlock(issuerResp *apimodels.IssuanceBlockHeaderResponse, congestionResp *apimodels.CongestionResponse, payload iotago.Payload, issuer blockfactory.Account) (*iotago.ProtocolBlock, error) { - commitmentID, err := issuerResp.Commitment.ID() - if err != nil { - return nil, fmt.Errorf("failed to get commitment ID: %w", err) - } - +func (a *AccountWallet) CreateBlock(clt *nodeclient.Client, payload iotago.Payload, issuer blockhandler.Account) (*iotago.ProtocolBlock, error) { blockBuilder := builder.NewBasicBlockBuilder(a.api) - blockBuilder.SlotCommitmentID(commitmentID) - blockBuilder.LatestFinalizedSlot(issuerResp.LatestFinalizedSlot) - blockBuilder.IssuingTime(time.Now()) - blockBuilder.StrongParents(issuerResp.StrongParents) - fmt.Printf("WeakParents len: %v\n", len(issuerResp.WeakParents)) - blockBuilder.WeakParents(issuerResp.WeakParents) - fmt.Printf("ShallowLikeParents len: %v\n", len(issuerResp.ShallowLikeParents)) - blockBuilder.ShallowLikeParents(issuerResp.ShallowLikeParents) + blockBuilder.RequestNodeBuildData(clt, issuer.ID()) + blockBuilder.Payload(payload) - blockBuilder.MaxBurnedMana(congestionResp.ReferenceManaCost) blockBuilder.Sign(issuer.ID(), issuer.PrivateKey()) blk, err := blockBuilder.Build() @@ -139,7 +101,7 @@ type faucetParams struct { type faucet struct { unspentOutput *models.Output - account blockfactory.Account + account blockhandler.Account genesisHdWallet *mock.HDWallet clt models.Client @@ -151,7 +113,7 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { //get Faucet output and amount var faucetAmount iotago.BaseToken - faucetUnspentOutputID, err := iotago.OutputIDFromHex(faucetParams.latestUsedOutputID) + faucetUnspentOutputID, err := iotago.OutputIDFromHexString(faucetParams.latestUsedOutputID) if err != nil { log.Warnf("Cannot parse faucet output id from config: %v", err) } @@ -174,7 +136,7 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { f := &faucet{ clt: clt, - account: blockfactory.AccountFromParams(faucetParams.faucetAccountID, faucetParams.faucetPrivateKey), + account: blockhandler.AccountFromParams(faucetParams.faucetAccountID, faucetParams.faucetPrivateKey), genesisHdWallet: mock.NewHDWallet("", genesisSeed, 0), } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index d8829f55f..eac77cc29 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -1,6 +1,7 @@ package accountwallet import ( + "crypto/ed25519" "os" "time" @@ -9,6 +10,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/hive.go/runtime/timeutil" + "github.com/iotaledger/iota-core/pkg/blockhandler" "github.com/iotaledger/iota-core/pkg/testsuite/mock" "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/models" @@ -79,6 +81,13 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() w.faucet = newFaucet(w.client, w.optsFaucetParams) + w.accountsAliases[FaucetAccountAlias] = &models.AccountData{ + Alias: FaucetAccountAlias, + Status: models.AccountReady, + OutputID: iotago.EmptyOutputID, + Index: 0, + Account: w.faucet.account, + } }) } @@ -152,14 +161,16 @@ func (a *AccountWallet) readAccountsStateFile() (map[string]*models.AccountData, return a.accountsAliases, nil } -func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, index uint64) iotago.AccountID { +func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, index uint64, privKey ed25519.PrivateKey) iotago.AccountID { accountID := iotago.AccountIDFromOutputID(outputID) + account := blockhandler.NewEd25519Account(accountID, privKey) + a.accountsAliases[alias] = &models.AccountData{ - Alias: alias, - AccountID: accountID, - Status: models.AccountPending, - OutputID: outputID, - Index: index, + Alias: alias, + Account: account, + Status: models.AccountPending, + OutputID: outputID, + Index: index, } return accountID @@ -181,7 +192,7 @@ func (a *AccountWallet) updateAccountStatus(alias string, status models.AccountS return accData, true } -func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { +func (a *AccountWallet) GetReadyAccount(alias string) (*models.AccountData, error) { accData, exists := a.accountsAliases[alias] if !exists { return nil, ierrors.Errorf("account with alias %s does not exist", alias) @@ -198,6 +209,15 @@ func (a *AccountWallet) getAccount(alias string) (*models.AccountData, error) { return accData, nil } +func (a *AccountWallet) GetAccount(alias string) (*models.AccountData, error) { + accData, exists := a.accountsAliases[alias] + if !exists { + return nil, ierrors.Errorf("account with alias %s does not exist", alias) + } + + return accData, nil +} + func (a *AccountWallet) isAccountReady(accData *models.AccountData) bool { if accData.Status == models.AccountReady { return true @@ -229,23 +249,23 @@ func (a *AccountWallet) isAccountReady(accData *models.AccountData) bool { return true } -func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) (*models.Output, error) { +func (a *AccountWallet) getFunds(amount uint64, addressType iotago.AddressType) (*models.Output, ed25519.PrivateKey, error) { hdWallet := mock.NewHDWallet("", a.seed[:], a.latestUsedIndex+1) - + privKey, _ := hdWallet.KeyPair() receiverAddr := hdWallet.Address(addressType) createdOutput, err := a.RequestFaucetFunds(a.client, receiverAddr, iotago.BaseToken(amount)) if err != nil { - return nil, ierrors.Wrap(err, "failed to request funds from Faucet") + return nil, nil, ierrors.Wrap(err, "failed to request funds from Faucet") } a.latestUsedIndex++ createdOutput.Index = a.latestUsedIndex - return createdOutput, nil + return createdOutput, privKey, nil } func (a *AccountWallet) destroyAccount(alias string) error { - accData, err := a.getAccount(alias) + accData, err := a.GetAccount(alias) if err != nil { return err } @@ -258,7 +278,7 @@ func (a *AccountWallet) destroyAccount(alias string) error { txBuilder := builder.NewTransactionBuilder(a.api) txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: a.accountsAliases[alias].AccountID.ToAddress(), + UnlockTarget: a.accountsAliases[alias].Account.ID().ToAddress(), InputID: accData.OutputID, Input: accountOutput, }) @@ -273,10 +293,13 @@ func (a *AccountWallet) destroyAccount(alias string) error { tx, err := txBuilder.Build(hdWallet.AddressSigner()) if err != nil { - return ierrors.Wrap(err, "failed to build transaction") + return ierrors.Wrapf(err, "failed to build transaction for account alias destruction %s", alias) } - // TODO createa and post block + blockID, err := a.PostWithBlock(a.client, tx, a.faucet.account) + if err != nil { + return ierrors.Wrapf(err, "failed to post block with ID %s", blockID) + } // remove account from wallet delete(a.accountsAliases, alias) diff --git a/tools/evil-spammer/config.go b/tools/evil-spammer/config.go index 7803dd982..c8fc6e93d 100644 --- a/tools/evil-spammer/config.go +++ b/tools/evil-spammer/config.go @@ -32,7 +32,7 @@ var ( Scenario: evilwallet.Scenario1(), DeepSpam: false, EnableRateSetter: false, - AccountAlias: "faucet", + AccountAlias: accountwallet.FaucetAccountAlias, } quickTestParams = programs.QuickTestParams{ @@ -53,7 +53,7 @@ var ( // TimeUnit: time.Second, // NetworkAlias: "docker", // SpammerAlias: "peer_master", - // ValidAlias: "faucet", + // ValidAlias: accountwallet.FaucetAccountAlias, // CommitmentType: "latest", // ForkAfter: 10, // } diff --git a/tools/evil-spammer/evilwallet/evilscenario.go b/tools/evil-spammer/evilwallet/evilscenario.go index 32a171bd0..00f15d968 100644 --- a/tools/evil-spammer/evilwallet/evilscenario.go +++ b/tools/evil-spammer/evilwallet/evilscenario.go @@ -51,7 +51,8 @@ type EvilScenario struct { // if not provided evil wallet will use Reuse wallet if any is available. Accepts only RestrictedReuse wallet type. RestrictedInputWallet *Wallet // used together with scenario ID to create a prefix for distinct batch alias creation - BatchesCreated *atomic.Uint64 + BatchesCreated *atomic.Uint64 + // used to determine how many clients are needed to run this scenario, some double spends need more than one client to pass the filter NumOfClientsNeeded int } diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 8e1de12cb..40cca4aa2 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -1,7 +1,6 @@ package evilwallet import ( - "fmt" "sync" "time" @@ -9,6 +8,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/blockhandler" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" @@ -105,9 +105,22 @@ func (e *EvilWallet) RemoveClient(clientURL string) { e.connector.RemoveClient(clientURL) } -func (e *EvilWallet) CreateBlock() *iotago.ProtocolBlock { - e.accWallet.PostBlock(clt, tx, issuer) +func (e *EvilWallet) GetAccount(alias string) (blockhandler.Account, error) { + account, err := e.accWallet.GetAccount(alias) + if err != nil { + return nil, err + } + + return account.Account, nil +} + +func (e *EvilWallet) PrepareAndPostBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account) (iotago.BlockID, error) { + blockID, err := e.accWallet.PostWithBlock(clt, payload, issuer) + if err != nil { + return iotago.EmptyBlockID, err + } + return blockID, nil } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -233,9 +246,13 @@ func (e *EvilWallet) splitOutputs(splitOutput *models.Output, inputWallet, outpu return iotago.TransactionID{}, err } - _, err = e.connector.GetClient().PostTransaction(signedTx) + faucetAccount, err := e.accWallet.GetAccount(accountwallet.FaucetAccountAlias) + if err != nil { + return iotago.TransactionID{}, err + } + + _, err = e.PrepareAndPostBlock(e.connector.GetClient(), signedTx, faucetAccount.Account) if err != nil { - fmt.Println(err) return iotago.TransactionID{}, err } diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index b36bc5a9b..b0fa35f2f 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -1,4 +1,4 @@ -package wallet +package models import ( "context" @@ -159,6 +159,7 @@ func (c *WebClients) RemoveClient(url string) { } type Client interface { + Client() *nodeclient.Client // URL returns a client API url. URL() (cltID string) // PostBlock sends a block to the Tangle via a given client. @@ -185,6 +186,10 @@ type WebClient struct { url string } +func (c *WebClient) Client() *nodeclient.Client { + return c.client +} + func (c *WebClient) APIForVersion(version iotago.Version) (iotago.API, error) { return c.client.APIForVersion(version) } diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index b65c1750b..96a879116 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -1,6 +1,7 @@ package models import ( + "github.com/iotaledger/iota-core/pkg/blockhandler" iotago "github.com/iotaledger/iota.go/v4" ) @@ -31,9 +32,9 @@ const ( ) type AccountData struct { - Alias string `serix:"0,lengthPrefixType=uint8"` - Status AccountStatus `serix:"1"` - AccountID iotago.AccountID `serix:"2"` - OutputID iotago.OutputID `serix:"3"` - Index uint64 `serix:"4"` + Alias string `serix:"0,lengthPrefixType=uint8"` + Status AccountStatus `serix:"1"` + Account blockhandler.Account `serix:"2"` + OutputID iotago.OutputID `serix:"3"` + Index uint64 `serix:"4"` } diff --git a/tools/evil-spammer/programs/spammers.go b/tools/evil-spammer/programs/spammers.go index 4cf3799f0..b8ca4845f 100644 --- a/tools/evil-spammer/programs/spammers.go +++ b/tools/evil-spammer/programs/spammers.go @@ -116,6 +116,7 @@ func SpamTransaction(w *evilwallet.EvilWallet, rate int, timeUnit, duration time spammer.WithRateSetter(enableRateSetter), spammer.WithEvilWallet(w), spammer.WithEvilScenario(scenarioTx), + spammer.WithAccountAlias(accountAlias), } s := spammer.NewSpammer(options...) @@ -147,6 +148,7 @@ func SpamDoubleSpends(w *evilwallet.EvilWallet, rate, nSpent int, timeUnit, dura spammer.WithRateSetter(enableRateSetter), spammer.WithTimeDelayForDoubleSpend(delayBetweenConflicts), spammer.WithEvilScenario(scenarioDs), + spammer.WithAccountAlias(accountAlias), } s := spammer.NewSpammer(options...) @@ -179,6 +181,7 @@ func SpamNestedConflicts(w *evilwallet.EvilWallet, rate int, timeUnit, duration spammer.WithEvilWallet(w), spammer.WithRateSetter(enableRateSetter), spammer.WithEvilScenario(scenario), + spammer.WithAccountAlias(accountAlias), } return spammer.NewSpammer(options...) @@ -196,6 +199,7 @@ func SpamBlocks(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Dura spammer.WithRateSetter(enableRateSetter), spammer.WithEvilWallet(w), spammer.WithSpammingFunc(spammer.DataSpammingFunction), + spammer.WithAccountAlias(accountAlias), } return spammer.NewSpammer(options...) @@ -219,6 +223,7 @@ func SpamAccounts(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Du spammer.WithEvilWallet(w), spammer.WithSpammingFunc(spammer.AccountSpammingFunction), spammer.WithEvilScenario(scenarioAccount), + spammer.WithAccountAlias(accountAlias), } return spammer.NewSpammer(options...) diff --git a/tools/evil-spammer/spammer/errors.go b/tools/evil-spammer/spammer/errors.go index 667ddf2ae..4c056ffaa 100644 --- a/tools/evil-spammer/spammer/errors.go +++ b/tools/evil-spammer/spammer/errors.go @@ -14,11 +14,13 @@ var ( ErrFailSendDataBlock = ierrors.New("failed to send a data block") ErrFailGetReferences = ierrors.New("failed to get references") ErrTransactionIsNil = ierrors.New("provided transaction is nil") - ErrBlockIsNil = ierrors.New("provided block is nil") + ErrTransactionInvalid = ierrors.New("provided transaction is invalid") + ErrPayloadIsNil = ierrors.New("provided payload is nil") ErrFailToPrepareBatch = ierrors.New("custom conflict batch could not be prepared") ErrInsufficientClients = ierrors.New("insufficient clients to send conflicts") ErrInputsNotSolid = ierrors.New("not all inputs are solid") ErrFailPrepareBlock = ierrors.New("failed to prepare block") + ErrFailGetAccount = ierrors.New("failed to get account from the account wallet") ) // ErrorCounter counts errors that appeared during the spam, diff --git a/tools/evil-spammer/spammer/options.go b/tools/evil-spammer/spammer/options.go index 51ef08ea0..daf9c152c 100644 --- a/tools/evil-spammer/spammer/options.go +++ b/tools/evil-spammer/spammer/options.go @@ -61,6 +61,13 @@ func WithSpammingFunc(spammerFunc func(s *Spammer)) Options { } } +// WithAccountAlias sets the alias of the account that will be used to pay with mana for sent blocks. +func WithAccountAlias(alias string) Options { + return func(s *Spammer) { + s.IssuerAccountAlias = alias + } +} + // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // region Spammer EvilWallet options /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index 6056ed3c6..d4730817e 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -11,6 +11,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" @@ -54,14 +55,15 @@ const ( // Not mandatory options, if not provided spammer will use default settings: // WithSpamDetails, WithEvilWallet, WithErrorCounter, WithLogTickerInterval. type Spammer struct { - SpamDetails *SpamDetails - State *State - UseRateSetter bool - SpamType SpamType - Clients models.Connector - EvilWallet *evilwallet.EvilWallet - EvilScenario *evilwallet.EvilScenario - IdentityManager *IdentityManager + SpamDetails *SpamDetails + State *State + UseRateSetter bool + SpamType SpamType + IssuerAccountAlias string + Clients models.Connector + EvilWallet *evilwallet.EvilWallet + EvilScenario *evilwallet.EvilScenario + IdentityManager *IdentityManager // CommitmentManager *CommitmentManager ErrCounter *ErrorCounter @@ -88,12 +90,13 @@ func NewSpammer(options ...Options) *Spammer { logTickTime: time.Second * 30, } s := &Spammer{ - SpamDetails: &SpamDetails{}, - spamFunc: CustomConflictSpammingFunc, - State: state, - SpamType: SpamEvilWallet, - EvilScenario: evilwallet.NewEvilScenario(), - IdentityManager: NewIdentityManager(), + SpamDetails: &SpamDetails{}, + spamFunc: CustomConflictSpammingFunc, + State: state, + SpamType: SpamEvilWallet, + IssuerAccountAlias: accountwallet.FaucetAccountAlias, + EvilScenario: evilwallet.NewEvilScenario(), + IdentityManager: NewIdentityManager(), // CommitmentManager: NewCommitmentManager(), UseRateSetter: true, done: make(chan bool), @@ -232,15 +235,20 @@ func (s *Spammer) StopSpamming() { } func (s *Spammer) PrepareAndPostBlock(payload iotago.Payload, clt models.Client) { - if block == nil { - s.log.Debug(ErrBlockIsNil) - s.ErrCounter.CountError(ErrBlockIsNil) + if payload == nil { + s.log.Debug(ErrPayloadIsNil) + s.ErrCounter.CountError(ErrPayloadIsNil) return } + issuerAccount, err := s.EvilWallet.GetAccount(s.IssuerAccountAlias) + if err != nil { + s.log.Debug(ierrors.Wrapf(ErrFailGetAccount, err.Error())) + s.ErrCounter.CountError(ierrors.Wrapf(ErrFailGetAccount, err.Error())) - s.EvilWallet. - _, err := clt.PostBlock(block) + return + } + blockID, err := s.EvilWallet.PrepareAndPostBlock(clt, payload, issuerAccount) if err != nil { s.log.Debug(ierrors.Wrapf(ErrFailPostBlock, err.Error())) s.ErrCounter.CountError(ierrors.Wrapf(ErrFailPostBlock, err.Error())) @@ -248,6 +256,19 @@ func (s *Spammer) PrepareAndPostBlock(payload iotago.Payload, clt models.Client) return } + if payload.PayloadType() != iotago.PayloadSignedTransaction { + return + } + + signedTx := payload.(*iotago.SignedTransaction) + txID, err := signedTx.Transaction.ID() + if err != nil { + s.log.Debug(ierrors.Wrapf(ErrTransactionInvalid, err.Error())) + s.ErrCounter.CountError(ierrors.Wrapf(ErrTransactionInvalid, err.Error())) + + return + } + // reuse outputs if payload.PayloadType() == iotago.PayloadSignedTransaction { if s.EvilScenario.OutputWallet.Type() == evilwallet.Reuse { diff --git a/tools/evil-spammer/spammer/spamming_functions.go b/tools/evil-spammer/spammer/spamming_functions.go index 77fce19d4..047cbf73f 100644 --- a/tools/evil-spammer/spammer/spamming_functions.go +++ b/tools/evil-spammer/spammer/spamming_functions.go @@ -57,7 +57,7 @@ func CustomConflictSpammingFunc(s *Spammer) { //nolint:gosec time.Sleep(time.Duration(rand.Float64()*100) * time.Millisecond) - s.PostBlock(tx, clt) + s.PrepareAndPostBlock(tx, clt) }(clients[i], tx) } wg.Wait() @@ -75,14 +75,7 @@ func AccountSpammingFunction(s *Spammer) { s.log.Debugf(ierrors.Wrap(ErrFailToPrepareBatch, err.Error()).Error()) s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) } - blk, err := s.EvilWallet.PrepareBlock(tx, clt) - if err != nil { - s.ErrCounter.CountError(ierrors.Wrap(ErrFailPrepareBlock, err.Error())) - - return - } - - s.PostBlock(blk, tx, clt) + s.PrepareAndPostBlock(tx, clt) s.State.batchPrepared.Add(1) s.EvilWallet.ClearAliases(aliases) From 889b37458175fdebbc220fcfe9e400206117157e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 07:24:39 +0200 Subject: [PATCH 58/84] Fix import cycle --- tools/evil-spammer/accountwallet/faucet.go | 27 +++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 250cc0fab..010e33a04 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -1,12 +1,14 @@ package accountwallet import ( + "context" "fmt" "sync" "time" "github.com/mr-tron/base58" + "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/iota-core/pkg/blockhandler" "github.com/iotaledger/iota-core/pkg/testsuite/mock" @@ -79,7 +81,30 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, func (a *AccountWallet) CreateBlock(clt *nodeclient.Client, payload iotago.Payload, issuer blockhandler.Account) (*iotago.ProtocolBlock, error) { blockBuilder := builder.NewBasicBlockBuilder(a.api) - blockBuilder.RequestNodeBuildData(clt, issuer.ID()) + + congestionResp, err := clt.Congestion(context.Background(), issuer.ID()) + if err != nil { + return nil, ierrors.Wrapf(err, "failed to get congestion data for issuer %s", issuer.ID().ToHex()) + } + // TODO: modify block issuance api to indicate the slot index for commitment, to make sure it maches with congestion response + issuerResp, err := clt.BlockIssuance(context.Background()) + if err != nil { + return nil, ierrors.Wrap(err, "failed to get block issuance data") + } + + commitmentID, err := issuerResp.Commitment.ID() + if err != nil { + return nil, ierrors.Wrap(err, "failed to get commitment id") + } + + blockBuilder.ProtocolVersion(clt.CurrentAPI().ProtocolParameters().Version()) + blockBuilder.SlotCommitmentID(commitmentID) + blockBuilder.LatestFinalizedSlot(issuerResp.LatestFinalizedSlot) + blockBuilder.IssuingTime(time.Now()) + blockBuilder.StrongParents(issuerResp.StrongParents) + blockBuilder.WeakParents(issuerResp.WeakParents) + blockBuilder.ShallowLikeParents(issuerResp.ShallowLikeParents) + blockBuilder.MaxBurnedMana(congestionResp.ReferenceManaCost) blockBuilder.Payload(payload) blockBuilder.Sign(issuer.ID(), issuer.PrivateKey()) From 8e9f3b7c8f3845c805ba65576823156cedd431ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 13:27:39 +0200 Subject: [PATCH 59/84] Add serializable wallet accountState --- tools/evil-spammer/accountwallet/config.go | 6 ++--- tools/evil-spammer/accountwallet/wallet.go | 28 +++++++++++++--------- tools/evil-spammer/models/output.go | 20 ++++++++++++---- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index f3ccc6133..9a87a9aea 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -220,9 +220,9 @@ func (a *NoAccountParams) Type() AccountOperation { } type StateData struct { - Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` - LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` - AccountsData []*models.AccountData `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` + Seed string `serix:"0,mapKey=seed,lengthPrefixType=uint8"` + LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` + AccountsData []*models.AccountState `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` } var genesisTransactionID = iotago.TransactionIDRepresentingData(0, []byte("genesis")) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index eac77cc29..efd4ead30 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -97,10 +97,16 @@ func (a *AccountWallet) LastFaucetUnspentOutputID() iotago.OutputID { // toAccountStateFile write account states to file. func (a *AccountWallet) toAccountStateFile() error { - accounts := make([]*models.AccountData, 0) + accounts := make([]*models.AccountState, 0) for _, acc := range a.accountsAliases { - accounts = append(accounts, acc) + accounts = append(accounts, &models.AccountState{ + Alias: acc.Alias, + AccountID: acc.Account.ID(), + PrivateKey: acc.Account.PrivateKey(), + OutputID: acc.OutputID, + Index: acc.Index, + }) } stateBytes, err := a.api.Encode(&StateData{ @@ -147,20 +153,20 @@ func (a *AccountWallet) fromAccountStateFile() error { // account data for _, acc := range data.AccountsData { - a.accountsAliases[acc.Alias] = acc + a.accountsAliases[acc.Alias] = &models.AccountData{ + Alias: acc.Alias, + Account: blockhandler.NewEd25519Account(acc.AccountID, acc.PrivateKey), + OutputID: acc.OutputID, + Index: acc.Index, + } + if acc.Alias == FaucetAccountAlias { + a.accountsAliases[acc.Alias].Status = models.AccountReady + } } return nil } -func (a *AccountWallet) readAccountsStateFile() (map[string]*models.AccountData, error) { - err := a.fromAccountStateFile() - if err != nil { - return nil, ierrors.Wrap(err, "failed to load wallet from file") - } - return a.accountsAliases, nil -} - func (a *AccountWallet) registerAccount(alias string, outputID iotago.OutputID, index uint64, privKey ed25519.PrivateKey) iotago.AccountID { accountID := iotago.AccountIDFromOutputID(outputID) account := blockhandler.NewEd25519Account(accountID, privKey) diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index 96a879116..6668a0bb8 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -1,6 +1,8 @@ package models import ( + "crypto/ed25519" + "github.com/iotaledger/iota-core/pkg/blockhandler" iotago "github.com/iotaledger/iota.go/v4" ) @@ -32,9 +34,17 @@ const ( ) type AccountData struct { - Alias string `serix:"0,lengthPrefixType=uint8"` - Status AccountStatus `serix:"1"` - Account blockhandler.Account `serix:"2"` - OutputID iotago.OutputID `serix:"3"` - Index uint64 `serix:"4"` + Alias string + Status AccountStatus + Account blockhandler.Account + OutputID iotago.OutputID + Index uint64 +} + +type AccountState struct { + Alias string `serix:"0,lengthPrefixType=uint8"` + AccountID iotago.AccountID `serix:"2"` + PrivateKey ed25519.PrivateKey `serix:"3,lengthPrefixType=uint64"` + OutputID iotago.OutputID `serix:"4"` + Index uint64 `serix:"5"` } From e29490a281d3500e437bcda8debf3727c1436446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 13:29:55 +0200 Subject: [PATCH 60/84] Fix prefix --- tools/evil-spammer/models/output.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index 6668a0bb8..42f47b316 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -44,7 +44,7 @@ type AccountData struct { type AccountState struct { Alias string `serix:"0,lengthPrefixType=uint8"` AccountID iotago.AccountID `serix:"2"` - PrivateKey ed25519.PrivateKey `serix:"3,lengthPrefixType=uint64"` + PrivateKey ed25519.PrivateKey `serix:"3,lengthPrefixType=uint8"` OutputID iotago.OutputID `serix:"4"` Index uint64 `serix:"5"` } From 8e7b032d5d8754225d4b0a3cd1263d92f2ae999c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 13:47:51 +0200 Subject: [PATCH 61/84] Fix RMC API nil pointer --- components/restapi/core/accounts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/restapi/core/accounts.go b/components/restapi/core/accounts.go index 35d3fcf5a..4790b3d58 100644 --- a/components/restapi/core/accounts.go +++ b/components/restapi/core/accounts.go @@ -36,7 +36,7 @@ func congestionForAccountID(c echo.Context) (*apimodels.CongestionResponse, erro if err != nil { rmcSlot = 0 } - rmc, err := deps.Protocol.CandidateEngineInstance().Ledger.RMCManager().RMC(rmcSlot) + rmc, err := deps.Protocol.MainEngineInstance().Ledger.RMCManager().RMC(rmcSlot) if err != nil { return nil, ierrors.Wrapf(err, "failed to get RMC for slot: %d", rmcSlot) } From 198f41f75d13ca1c7ee5c9ec556721bc5b7fd8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 14:31:49 +0200 Subject: [PATCH 62/84] Fix: save faucet output to wallet during the split --- tools/evil-spammer/evilwallet/evilwallet.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 40cca4aa2..c8f76d2f4 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -230,6 +230,9 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *models.Output return nil, ierrors.Wrap(err, "failed to request funds from faucet") } + // update wallet with newly created output + e.outputManager.CreateOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, output.OutputID, output.OutputStruct) + return output, nil } From 35ecc1abb6064b95f76f0c91f6ad1074d7eeb21e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 15:25:02 +0200 Subject: [PATCH 63/84] Add more debug logs --- tools/evil-spammer/evilwallet/evilwallet.go | 20 ++++++++++++++++--- .../evil-spammer/evilwallet/output_manager.go | 10 +++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index c8f76d2f4..d4dae901a 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -4,12 +4,16 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/log" + "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/blockhandler" "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" + evillogger "github.com/iotaledger/iota-core/tools/evil-spammer/logger" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" @@ -45,6 +49,7 @@ type EvilWallet struct { aliasManager *AliasManager optsClientURLs []string + log *logger.Logger } // NewEvilWallet creates an EvilWallet instance. @@ -53,10 +58,11 @@ func NewEvilWallet(opts ...options.Option[EvilWallet]) *EvilWallet { wallets: NewWallets(), aliasManager: NewAliasManager(), optsClientURLs: defaultClientsURLs, + log: evillogger.New("EvilWallet"), }, opts, func(w *EvilWallet) { connector := models.NewWebClients(w.optsClientURLs) w.connector = connector - w.outputManager = NewOutputManager(connector, w.wallets) + w.outputManager = NewOutputManager(connector, w.wallets, w.log) }) } @@ -142,6 +148,8 @@ func (e *EvilWallet) RequestFundsFromFaucet(options ...FaucetRequestOption) (ini e.aliasManager.AddInputAlias(output, buildOptions.outputAliasName) } + log.Debug("Funds requested succesfully") + return } @@ -179,7 +187,7 @@ func (e *EvilWallet) RequestFreshBigFaucetWallet() error { txIDs := make(iotago.TransactionIDs, 0) // TODO: calculate the exact number of required funds so we don't run out after a while - for i := 0; i < 300; i++ { + for i := 0; i < 1; i++ { txID, err := e.requestAndSplitFaucetFunds(initWallet, receiveWallet) if err != nil { return ierrors.Wrap(err, "failed to request big funds from faucet") @@ -217,6 +225,8 @@ func (e *EvilWallet) requestAndSplitFaucetFunds(initWallet, receiveWallet *Walle if err != nil { return iotago.TransactionID{}, err } + + e.log.Debugf("Faucet funds received, continue spliting output: %s", splitOutput.OutputID.ToHex()) // first split 1 to FaucetRequestSplitNumber outputs return e.splitOutputs(splitOutput, initWallet, receiveWallet) } @@ -259,7 +269,11 @@ func (e *EvilWallet) splitOutputs(splitOutput *models.Output, inputWallet, outpu return iotago.TransactionID{}, err } - return lo.PanicOnErr(signedTx.Transaction.ID()), nil + txID := lo.PanicOnErr(signedTx.Transaction.ID()) + + e.log.Debugf("Splitting output %s finished with tx: %s", splitOutput.OutputID.ToHex(), txID.ToHex()) + + return txID, nil } func (e *EvilWallet) handleInputOutputDuringSplitOutputs(splitOutput *models.Output, splitNumber int, receiveWallet *Wallet) (input *models.Output, outputs []*OutputOption) { diff --git a/tools/evil-spammer/evilwallet/output_manager.go b/tools/evil-spammer/evilwallet/output_manager.go index 57811c2bd..f705dec09 100644 --- a/tools/evil-spammer/evilwallet/output_manager.go +++ b/tools/evil-spammer/evilwallet/output_manager.go @@ -7,6 +7,7 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/runtime/syncutils" "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" @@ -26,17 +27,20 @@ type OutputManager struct { // stores solid outputs per node issuerSolidOutIDMap map[string]map[iotago.OutputID]types.Empty + log *logger.Logger + syncutils.RWMutex } // NewOutputManager creates an OutputManager instance. -func NewOutputManager(connector models.Connector, wallets *Wallets) *OutputManager { +func NewOutputManager(connector models.Connector, wallets *Wallets, log *logger.Logger) *OutputManager { return &OutputManager{ connector: connector, wallets: wallets, outputIDWalletMap: make(map[string]*Wallet), outputIDAddrMap: make(map[string]string), issuerSolidOutIDMap: make(map[string]map[iotago.OutputID]types.Empty), + log: log, } } @@ -271,6 +275,8 @@ func (o *OutputManager) AwaitTransactionsConfirmation(txIDs ...iotago.Transactio wg := sync.WaitGroup{} semaphore := make(chan bool, 1) + o.log.Debugf("Awaiting confirmation of %d transactions", len(txIDs)) + for _, txID := range txIDs { wg.Add(1) go func(txID iotago.TransactionID) { @@ -304,6 +310,8 @@ func (o *OutputManager) AwaitTransactionToBeAccepted(txID iotago.TransactionID, return ierrors.Errorf("transaction %s not accepted in time", txID) } + o.log.Debugf("Transaction %s accepted", txID) + return nil } From f2fecb14a45ae10cf182ead9acf2bf62173d6cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 15:26:06 +0200 Subject: [PATCH 64/84] Fix default alias setup --- tools/evil-spammer/parse.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/evil-spammer/parse.go b/tools/evil-spammer/parse.go index 51e732386..b62b85292 100644 --- a/tools/evil-spammer/parse.go +++ b/tools/evil-spammer/parse.go @@ -106,7 +106,9 @@ func parseBasicSpamFlags() { customSpamParams.DeepSpam = *deepSpam customSpamParams.TimeUnit = *timeunit customSpamParams.DelayBetweenConflicts = *delayBetweenConflicts - customSpamParams.AccountAlias = *account + if *account != "" { + customSpamParams.AccountAlias = *account + } // fill in unused parameter: blkNum or duration with zeros if *duration == "" && *blkNum != "" { From 076304a000642e533e91f0b8eadb4b87eaadc0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Wed, 11 Oct 2023 15:32:48 +0200 Subject: [PATCH 65/84] Shorten max awaiting times --- tools/evil-spammer/evilwallet/evilwallet.go | 8 ++++---- tools/evil-spammer/evilwallet/output_manager.go | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index d4dae901a..852173f96 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -25,10 +25,10 @@ const ( FaucetRequestSplitNumber = 100 faucetTokensPerRequest iotago.BaseToken = 1_000_000 - waitForConfirmation = 150 * time.Second - waitForSolidification = 150 * time.Second + waitForConfirmation = 15 * time.Second + waitForSolidification = 10 * time.Second - awaitConfirmationSleep = 3 * time.Second + awaitConfirmationSleep = 2 * time.Second awaitSolidificationSleep = time.Millisecond * 500 ) @@ -241,7 +241,7 @@ func (e *EvilWallet) requestFaucetFunds(wallet *Wallet) (outputID *models.Output } // update wallet with newly created output - e.outputManager.CreateOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, output.OutputID, output.OutputStruct) + e.outputManager.createOutputFromAddress(wallet, receiveAddr, faucetTokensPerRequest, output.OutputID, output.OutputStruct) return output, nil } diff --git a/tools/evil-spammer/evilwallet/output_manager.go b/tools/evil-spammer/evilwallet/output_manager.go index f705dec09..e86ac7448 100644 --- a/tools/evil-spammer/evilwallet/output_manager.go +++ b/tools/evil-spammer/evilwallet/output_manager.go @@ -13,8 +13,8 @@ import ( iotago "github.com/iotaledger/iota.go/v4" ) -var ( - awaitOutputToBeConfirmed = 150 * time.Second +const ( + awaitOutputToBeConfirmed = 10 * time.Second ) // OutputManager keeps track of the output statuses. @@ -126,9 +126,9 @@ func (o *OutputManager) Track(outputIDs ...iotago.OutputID) (allConfirmed bool) return !unconfirmedOutputFound.Load() } -// CreateOutputFromAddress creates output, retrieves outputID, and adds it to the wallet. +// createOutputFromAddress creates output, retrieves outputID, and adds it to the wallet. // Provided address should be generated from provided wallet. Considers only first output found on address. -func (o *OutputManager) CreateOutputFromAddress(w *Wallet, addr *iotago.Ed25519Address, balance iotago.BaseToken, outputID iotago.OutputID, outputStruct iotago.Output) *models.Output { +func (o *OutputManager) createOutputFromAddress(w *Wallet, addr *iotago.Ed25519Address, balance iotago.BaseToken, outputID iotago.OutputID, outputStruct iotago.Output) *models.Output { index := w.AddrIndexMap(addr.String()) out := &models.Output{ Address: addr, @@ -300,8 +300,9 @@ func (o *OutputManager) AwaitTransactionToBeAccepted(txID iotago.TransactionID, clt := o.connector.GetClient() var accepted bool for ; time.Since(s) < waitFor; time.Sleep(awaitConfirmationSleep) { - // TODO: need to change to pending for now - if confirmationState := clt.GetTransactionConfirmationState(txID); confirmationState == "confirmed" || confirmationState == "finalized" { + confirmationState := clt.GetTransactionConfirmationState(txID) + o.log.Debugf("Tx %s confirmationState: %s", txID.ToHex(), confirmationState) + if confirmationState == "confirmed" || confirmationState == "finalized" { accepted = true break } From 469fadd87c809be9d9daf9c8c8c215c1d2d4c181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 12 Oct 2023 11:23:15 +0200 Subject: [PATCH 66/84] Fix: genesis output creation is now read from config file --- tools/evil-spammer/accountwallet/config.go | 6 ++--- tools/evil-spammer/accountwallet/faucet.go | 26 +++++++++++++++++----- tools/evil-spammer/accountwallet/wallet.go | 1 + 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index 9a87a9aea..d0824fe92 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -66,6 +66,7 @@ type Configuration struct { BindAddress string `json:"bindAddress,omitempty"` AccountStatesFile string `json:"accountStatesFile,omitempty"` GenesisSeed string `json:"genesisSeed,omitempty"` + GenesisOutputID string `json:"genesisOutputID,omitempty"` LastFauctUnspentOutputID string `json:"lastFaucetUnspentOutputID,omitempty"` BlockIssuerPrivateKey string `json:"blockIssuerPrivateKey,omitempty"` AccountID string `json:"accountID,omitempty"` @@ -81,8 +82,9 @@ var ( dockerAccountConfigJSON = `{ "bindAddress": "http://localhost:8080", "accountStatesFile": "wallet.dat", - "lastFaucetUnspentOutputID": "", + "lastFaucetUnspentOutputID": "0x2ee87e6c33a99118c381310b3a2df78234837fdfd3aac4bcde0c32456eaff349000000000000", "genesisSeed": "7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih", + "genesisOutputID": "0x2ee87e6c33a99118c381310b3a2df78234837fdfd3aac4bcde0c32456eaff349000000000000", "blockIssuerPrivateKey": "db39d2fde6301d313b108dc9db1ee724d0f405f6fde966bd776365bc5f4a5fb31e4b21eb51dcddf65c20db1065e1f1514658b23a3ddbf48d30c0efc926a9a648", "accountID": "0x6aee704f25558e8aa7630fed0121da53074188abc423b3c5810f80be4936eb6e"}` ) @@ -224,5 +226,3 @@ type StateData struct { LastUsedIndex uint64 `serix:"1,mapKey=lastUsedIndex"` AccountsData []*models.AccountState `serix:"2,mapKey=accounts,lengthPrefixType=uint8"` } - -var genesisTransactionID = iotago.TransactionIDRepresentingData(0, []byte("genesis")) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 010e33a04..be7485cfc 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -8,6 +8,7 @@ import ( "github.com/mr-tron/base58" + "github.com/iotaledger/hive.go/core/safemath" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/iota-core/pkg/blockhandler" @@ -18,7 +19,9 @@ import ( "github.com/iotaledger/iota.go/v4/nodeclient" ) -const FaucetAccountAlias = "faucet" +const ( + FaucetAccountAlias = "faucet" +) func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { signedTx, err := a.faucet.prepareFaucetRequest(receiveAddr, amount) @@ -79,6 +82,7 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, } +// TODO: create validation blocks too func (a *AccountWallet) CreateBlock(clt *nodeclient.Client, payload iotago.Payload, issuer blockhandler.Account) (*iotago.ProtocolBlock, error) { blockBuilder := builder.NewBasicBlockBuilder(a.api) @@ -122,6 +126,7 @@ type faucetParams struct { faucetPrivateKey string faucetAccountID string genesisSeed string + genesisOutputID string } type faucet struct { @@ -148,11 +153,15 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { faucetAmount = faucetOutput.BaseTokenAmount() } else { // use the genesis output ID instead, if we relaunch the docker network - faucetUnspentOutputID = iotago.OutputIDFromTransactionIDAndIndex(genesisTransactionID, 0) + faucetUnspentOutputID, err = iotago.OutputIDFromHexString(faucetParams.genesisOutputID) + if err != nil { + panic("cannot parse genesis output id, please update config file with genesis OutputID created in the snapshot") + } faucetOutput = clt.GetOutput(faucetUnspentOutputID) - if faucetOutput != nil { - faucetAmount = faucetOutput.BaseTokenAmount() + if faucetOutput == nil { + panic("cannot find faucet output") } + faucetAmount = faucetOutput.BaseTokenAmount() } genesisSeed, err := base58.Decode(faucetParams.genesisSeed) if err != nil { @@ -178,7 +187,10 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { } func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken) (*iotago.SignedTransaction, error) { - remainderAmount := f.unspentOutput.Balance - amount + remainderAmount, err := safemath.SafeSub(f.unspentOutput.Balance, amount) + if err != nil { + panic(err) + } signedTx, err := f.createFaucetTransaction(receiveAddr, amount, remainderAmount) if err != nil { @@ -227,7 +239,9 @@ func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iota txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) - + // TODO: if we want to test allotting exactly the same amount as for burning mana we need to update and join tx and block creation brocess + // txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput() + // BuildAndSwapToBlockBuilder signedTx, err := txBuilder.Build(f.genesisHdWallet.AddressSigner()) if err != nil { log.Errorf("failed to build transaction: %s", err) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index efd4ead30..31fcdf73d 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -35,6 +35,7 @@ func Run(config *Configuration) (*AccountWallet, error) { genesisSeed: config.GenesisSeed, faucetPrivateKey: config.BlockIssuerPrivateKey, faucetAccountID: config.AccountID, + genesisOutputID: config.GenesisOutputID, })) wallet := NewAccountWallet(opts...) From 90fa9b9214f2ad51f2a649a2a126b7deba40469f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 12 Oct 2023 13:37:35 +0200 Subject: [PATCH 67/84] Remove TODOs already listed in the issue TODO list --- tools/evil-spammer/accountwallet/faucet.go | 5 ----- tools/evil-spammer/evilwallet/evilwallet.go | 1 - 2 files changed, 6 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index be7485cfc..54aae3915 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -82,7 +82,6 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, } -// TODO: create validation blocks too func (a *AccountWallet) CreateBlock(clt *nodeclient.Client, payload iotago.Payload, issuer blockhandler.Account) (*iotago.ProtocolBlock, error) { blockBuilder := builder.NewBasicBlockBuilder(a.api) @@ -90,7 +89,6 @@ func (a *AccountWallet) CreateBlock(clt *nodeclient.Client, payload iotago.Paylo if err != nil { return nil, ierrors.Wrapf(err, "failed to get congestion data for issuer %s", issuer.ID().ToHex()) } - // TODO: modify block issuance api to indicate the slot index for commitment, to make sure it maches with congestion response issuerResp, err := clt.BlockIssuance(context.Background()) if err != nil { return nil, ierrors.Wrap(err, "failed to get block issuance data") @@ -239,9 +237,6 @@ func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iota txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) - // TODO: if we want to test allotting exactly the same amount as for burning mana we need to update and join tx and block creation brocess - // txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput() - // BuildAndSwapToBlockBuilder signedTx, err := txBuilder.Build(f.genesisHdWallet.AddressSigner()) if err != nil { log.Errorf("failed to build transaction: %s", err) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 8f55d4d06..ff5ac1519 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -186,7 +186,6 @@ func (e *EvilWallet) RequestFreshBigFaucetWallet() error { receiveWallet := e.NewWallet(Fresh) txIDs := make(iotago.TransactionIDs, 0) - // TODO: calculate the exact number of required funds so we don't run out after a while for i := 0; i < 1; i++ { txID, err := e.requestAndSplitFaucetFunds(initWallet, receiveWallet) if err != nil { From 202ae6a2ee1296b49e8801798d0cf70059dba73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 12 Oct 2023 13:38:27 +0200 Subject: [PATCH 68/84] Cleanup Account data transition during serialization --- tools/evil-spammer/accountwallet/wallet.go | 15 ++------------- tools/evil-spammer/models/output.go | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 31fcdf73d..6c8309004 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -101,13 +101,7 @@ func (a *AccountWallet) toAccountStateFile() error { accounts := make([]*models.AccountState, 0) for _, acc := range a.accountsAliases { - accounts = append(accounts, &models.AccountState{ - Alias: acc.Alias, - AccountID: acc.Account.ID(), - PrivateKey: acc.Account.PrivateKey(), - OutputID: acc.OutputID, - Index: acc.Index, - }) + accounts = append(accounts, models.AccountStateFromAccountData(acc)) } stateBytes, err := a.api.Encode(&StateData{ @@ -154,12 +148,7 @@ func (a *AccountWallet) fromAccountStateFile() error { // account data for _, acc := range data.AccountsData { - a.accountsAliases[acc.Alias] = &models.AccountData{ - Alias: acc.Alias, - Account: blockhandler.NewEd25519Account(acc.AccountID, acc.PrivateKey), - OutputID: acc.OutputID, - Index: acc.Index, - } + a.accountsAliases[acc.Alias] = acc.ToAccountData() if acc.Alias == FaucetAccountAlias { a.accountsAliases[acc.Alias].Status = models.AccountReady } diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index 42f47b316..304dafd0a 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -48,3 +48,22 @@ type AccountState struct { OutputID iotago.OutputID `serix:"4"` Index uint64 `serix:"5"` } + +func AccountStateFromAccountData(acc *AccountData) *AccountState { + return &AccountState{ + Alias: acc.Alias, + AccountID: acc.Account.ID(), + PrivateKey: acc.Account.PrivateKey(), + OutputID: acc.OutputID, + Index: acc.Index, + } +} + +func (a *AccountState) ToAccountData() *AccountData { + return &AccountData{ + Alias: a.Alias, + Account: blockhandler.NewEd25519Account(a.AccountID, a.PrivateKey), + OutputID: a.OutputID, + Index: a.Index, + } +} From 261b533f115ee412019b8a0c587e9d1007ed8c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 12 Oct 2023 15:23:16 +0200 Subject: [PATCH 69/84] Pay with the potential or stored mana of the faucet output. --- tools/evil-spammer/accountwallet/faucet.go | 68 +++++++++++++-------- tools/evil-spammer/accountwallet/wallet.go | 7 ++- tools/evil-spammer/evilwallet/evilwallet.go | 6 +- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 54aae3915..819d779b5 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -17,21 +17,41 @@ import ( iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" "github.com/iotaledger/iota.go/v4/nodeclient" + "github.com/iotaledger/iota.go/v4/nodeclient/apimodels" ) const ( FaucetAccountAlias = "faucet" ) +func (a *AccountWallet) RequestBlockBuiltData(clt *nodeclient.Client, issuerID iotago.AccountID) (*apimodels.CongestionResponse, *apimodels.IssuanceBlockHeaderResponse, iotago.Version, error) { + congestionResp, err := clt.Congestion(context.Background(), issuerID) + if err != nil { + return nil, nil, 0, ierrors.Wrapf(err, "failed to get congestion data for issuer %s", issuerID.ToHex()) + } + + issuerResp, err := clt.BlockIssuance(context.Background()) + if err != nil { + return nil, nil, 0, ierrors.Wrap(err, "failed to get block issuance data") + } + + return congestionResp, issuerResp, clt.CurrentAPI().Version(), nil +} + func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { - signedTx, err := a.faucet.prepareFaucetRequest(receiveAddr, amount) + congestionResp, issuerResp, version, err := a.RequestBlockBuiltData(clt.Client(), a.faucet.account.ID()) + if err != nil { + return nil, ierrors.Wrapf(err, "failed to get block built data for issuer %s", a.faucet.account.ID().ToHex()) + } + + signedTx, err := a.faucet.prepareFaucetRequest(receiveAddr, amount, congestionResp.ReferenceManaCost) if err != nil { log.Errorf("failed to prepare faucet request: %s", err) return nil, err } - _, err = a.PostWithBlock(clt, signedTx, a.faucet.account) + _, err = a.PostWithBlock(clt, signedTx, a.faucet.account, congestionResp, issuerResp, version) if err != nil { log.Errorf("failed to create block: %s", err) @@ -56,8 +76,8 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago }, nil } -func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account) (iotago.BlockID, error) { - signedBlock, err := a.CreateBlock(clt.Client(), payload, issuer) +func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account, congestionResp *apimodels.CongestionResponse, issuerResp *apimodels.IssuanceBlockHeaderResponse, version iotago.Version) (iotago.BlockID, error) { + signedBlock, err := a.CreateBlock(payload, issuer, congestionResp, issuerResp, version) if err != nil { log.Errorf("failed to create block: %s", err) @@ -82,24 +102,15 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, } -func (a *AccountWallet) CreateBlock(clt *nodeclient.Client, payload iotago.Payload, issuer blockhandler.Account) (*iotago.ProtocolBlock, error) { +func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler.Account, congestionResp *apimodels.CongestionResponse, issuerResp *apimodels.IssuanceBlockHeaderResponse, version iotago.Version) (*iotago.ProtocolBlock, error) { blockBuilder := builder.NewBasicBlockBuilder(a.api) - congestionResp, err := clt.Congestion(context.Background(), issuer.ID()) - if err != nil { - return nil, ierrors.Wrapf(err, "failed to get congestion data for issuer %s", issuer.ID().ToHex()) - } - issuerResp, err := clt.BlockIssuance(context.Background()) - if err != nil { - return nil, ierrors.Wrap(err, "failed to get block issuance data") - } - commitmentID, err := issuerResp.Commitment.ID() if err != nil { return nil, ierrors.Wrap(err, "failed to get commitment id") } - blockBuilder.ProtocolVersion(clt.CurrentAPI().ProtocolParameters().Version()) + blockBuilder.ProtocolVersion(version) blockBuilder.SlotCommitmentID(commitmentID) blockBuilder.LatestFinalizedSlot(issuerResp.LatestFinalizedSlot) blockBuilder.IssuingTime(time.Now()) @@ -184,21 +195,31 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { return f } -func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken) (*iotago.SignedTransaction, error) { +func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken, rmc iotago.Mana) (*iotago.SignedTransaction, error) { remainderAmount, err := safemath.SafeSub(f.unspentOutput.Balance, amount) if err != nil { panic(err) } - signedTx, err := f.createFaucetTransaction(receiveAddr, amount, remainderAmount) + txBuilder, remainderIndex, err := f.createFaucetTransactionNoManaHandling(receiveAddr, amount, remainderAmount) + if err != nil { + return nil, err + } + + // faucet will allot exact mana to be burnt, rest of the mana is alloted to faucet output remainder + txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput(txBuilder.CreationSlot(), rmc, f.account.ID(), remainderIndex) + + signedTx, err := txBuilder.Build(f.genesisHdWallet.AddressSigner()) if err != nil { + log.Errorf("failed to build transaction: %s", err) + return nil, err } return signedTx, nil } -func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iotago.BaseToken, remainderAmount iotago.BaseToken) (*iotago.SignedTransaction, error) { +func (f *faucet) createFaucetTransactionNoManaHandling(receiveAddr iotago.Address, amount iotago.BaseToken, remainderAmount iotago.BaseToken) (*builder.TransactionBuilder, int, error) { txBuilder := builder.NewTransactionBuilder(f.clt.CurrentAPI()) txBuilder.AddInput(&builder.TxInput{ @@ -222,26 +243,21 @@ func (f *faucet) createFaucetTransaction(receiveAddr iotago.Address, amount iota if err != nil { log.Errorf("failed to build account output: %s", err) - return nil, err + return nil, 0, err } txBuilder.AddOutput(output) } // remainder output + remainderIndex := 1 txBuilder.AddOutput(&iotago.BasicOutput{ Amount: remainderAmount, Conditions: iotago.BasicOutputUnlockConditions{ &iotago.AddressUnlockCondition{Address: f.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address)}, }, }) - txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) - signedTx, err := txBuilder.Build(f.genesisHdWallet.AddressSigner()) - if err != nil { - log.Errorf("failed to build transaction: %s", err) - return nil, err - } - return signedTx, err + return txBuilder, remainderIndex, nil } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index 6c8309004..ac010a06e 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -292,7 +292,12 @@ func (a *AccountWallet) destroyAccount(alias string) error { return ierrors.Wrapf(err, "failed to build transaction for account alias destruction %s", alias) } - blockID, err := a.PostWithBlock(a.client, tx, a.faucet.account) + congestionResp, issuerResp, version, err := a.RequestBlockBuiltData(a.client.Client(), a.faucet.account.ID()) + if err != nil { + return ierrors.Wrap(err, "failed to request block built data for the faucet account") + } + + blockID, err := a.PostWithBlock(a.client, tx, a.faucet.account, congestionResp, issuerResp, version) if err != nil { return ierrors.Wrapf(err, "failed to post block with ID %s", blockID) } diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index ff5ac1519..aac28adb2 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -121,7 +121,11 @@ func (e *EvilWallet) GetAccount(alias string) (blockhandler.Account, error) { } func (e *EvilWallet) PrepareAndPostBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account) (iotago.BlockID, error) { - blockID, err := e.accWallet.PostWithBlock(clt, payload, issuer) + congestionResp, issuerResp, version, err := e.accWallet.RequestBlockBuiltData(clt.Client(), issuer.ID()) + if err != nil { + return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to get block built data for issuer %s", issuer.ID().ToHex()) + } + blockID, err := e.accWallet.PostWithBlock(clt, payload, issuer, congestionResp, issuerResp, version) if err != nil { return iotago.EmptyBlockID, err } From bac39b4d032bbd470d20e62f5a8a68e4819b9c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Thu, 12 Oct 2023 16:33:29 +0200 Subject: [PATCH 70/84] Use AllotAllMana from txBuilder --- tools/evil-spammer/evilwallet/evilwallet.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index aac28adb2..01cf39d9f 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -664,7 +664,11 @@ func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Out inputPrivateKey, _ := wallet.KeyPair(index) walletKeys[i] = iotago.AddressKeys{Address: addr, Keys: inputPrivateKey} } - txBuilder.SetCreationSlot(clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) + targetSlot := clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now()) + txBuilder.SetCreationSlot(targetSlot) + // allot all mana to the faucet output + // TODO; request block issuer data and congestion, make the same data is used for block issuance + txBuilder.AllotAllMana(targetSlot, rmc, blockIssuerAccountID) return txBuilder.Build(iotago.NewInMemoryAddressSigner(walletKeys...)) } From 93493950a72ff0404def4af321a27c1be3a42907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 13 Oct 2023 09:24:24 +0200 Subject: [PATCH 71/84] Add allotment strategy to transaction creation process --- tools/evil-spammer/evilwallet/evilscenario.go | 6 ++ tools/evil-spammer/evilwallet/evilwallet.go | 99 ++++++++++++++----- tools/evil-spammer/evilwallet/options.go | 13 ++- tools/evil-spammer/models/connector.go | 2 + tools/evil-spammer/models/output.go | 19 ++++ tools/evil-spammer/spammer/options.go | 2 +- tools/evil-spammer/spammer/spammer.go | 50 +++++----- .../spammer/spamming_functions.go | 19 ++-- 8 files changed, 143 insertions(+), 67 deletions(-) diff --git a/tools/evil-spammer/evilwallet/evilscenario.go b/tools/evil-spammer/evilwallet/evilscenario.go index 00f15d968..b8033ee36 100644 --- a/tools/evil-spammer/evilwallet/evilscenario.go +++ b/tools/evil-spammer/evilwallet/evilscenario.go @@ -8,6 +8,7 @@ import ( "go.uber.org/atomic" "github.com/iotaledger/hive.go/ds/types" + "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" ) @@ -54,6 +55,8 @@ type EvilScenario struct { BatchesCreated *atomic.Uint64 // used to determine how many clients are needed to run this scenario, some double spends need more than one client to pass the filter NumOfClientsNeeded int + // used to indicate if and how to include allotment into a transaction. + IssuancePaymentStrategy *models.IssuancePaymentStrategy } func NewEvilScenario(options ...ScenarioOption) *EvilScenario { @@ -63,6 +66,9 @@ func NewEvilScenario(options ...ScenarioOption) *EvilScenario { OutputType: iotago.OutputBasic, OutputWallet: NewWallet(), BatchesCreated: atomic.NewUint64(0), + IssuancePaymentStrategy: &models.IssuancePaymentStrategy{ + AllotmentStrategy: models.AllotmentStrategyNone, + }, } for _, option := range options { diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 01cf39d9f..2a462a195 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -17,6 +17,7 @@ import ( "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/builder" + "github.com/iotaledger/iota.go/v4/nodeclient/apimodels" "github.com/iotaledger/iota.go/v4/tpkg" ) @@ -120,7 +121,7 @@ func (e *EvilWallet) GetAccount(alias string) (blockhandler.Account, error) { return account.Account, nil } -func (e *EvilWallet) PrepareAndPostBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account) (iotago.BlockID, error) { +func (e *EvilWallet) PrepareAndPostBlock(clt models.Client, payload iotago.Payload, congestionResp *apimodels.CongestionResponse, issuer blockhandler.Account) (iotago.BlockID, error) { congestionResp, issuerResp, version, err := e.accWallet.RequestBlockBuiltData(clt.Client(), issuer.ID()) if err != nil { return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to get block built data for issuer %s", issuer.ID().ToHex()) @@ -257,22 +258,28 @@ func (e *EvilWallet) splitOutputs(splitOutput *models.Output, inputWallet, outpu input, outputs := e.handleInputOutputDuringSplitOutputs(splitOutput, FaucetRequestSplitNumber, outputWallet) - signedTx, err := e.CreateTransaction(WithInputs(input), WithOutputs(outputs), WithIssuer(inputWallet), WithOutputWallet(outputWallet)) + faucetAccount, err := e.accWallet.GetAccount(accountwallet.FaucetAccountAlias) if err != nil { return iotago.EmptyTransactionID, err } + txData, err := e.CreateTransaction( + WithInputs(input), + WithOutputs(outputs), + WithInputWallet(inputWallet), + WithOutputWallet(outputWallet), + WithIssuanceStrategy(models.AllotmentStrategyAll, faucetAccount.Account.ID()), + ) - faucetAccount, err := e.accWallet.GetAccount(accountwallet.FaucetAccountAlias) if err != nil { - return iotago.TransactionID{}, err + return iotago.EmptyTransactionID, err } - _, err = e.PrepareAndPostBlock(e.connector.GetClient(), signedTx, faucetAccount.Account) + _, err = e.PrepareAndPostBlock(e.connector.GetClient(), txData.Transaction, txData.CongestionResponse, faucetAccount.Account) if err != nil { return iotago.TransactionID{}, err } - txID := lo.PanicOnErr(signedTx.Transaction.ID()) + txID := lo.PanicOnErr(txData.Transaction.Transaction.ID()) e.log.Debugf("Splitting output %s finished with tx: %s", splitOutput.OutputID.ToHex(), txID.ToHex()) @@ -304,27 +311,27 @@ func (e *EvilWallet) ClearAllAliases() { e.aliasManager.ClearAllAliases() } -func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conflictBatch [][]*iotago.SignedTransaction, err error) { +func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conflictBatch [][]*models.TransactionIssuanceData, err error) { for _, conflictMap := range conflictsMaps { - var txs []*iotago.SignedTransaction + var txsData []*models.TransactionIssuanceData for _, conflictOptions := range conflictMap { - tx, err2 := e.CreateTransaction(conflictOptions...) + txData, err2 := e.CreateTransaction(conflictOptions...) if err2 != nil { return nil, err2 } - txs = append(txs, tx) + txsData = append(txsData, txData) } - conflictBatch = append(conflictBatch, txs) + conflictBatch = append(conflictBatch, txsData) } - return + return conflictBatch, nil } // CreateTransaction creates a transaction based on provided options. If no input wallet is provided, the next non-empty faucet wallet is used. // Inputs of the transaction are determined in three ways: // 1 - inputs are provided directly without associated alias, 2- alias is provided, and input is already stored in an alias manager, // 3 - alias is provided, and there are no inputs assigned in Alias manager, so aliases are assigned to next ready inputs from input wallet. -func (e *EvilWallet) CreateTransaction(options ...Option) (signedTx *iotago.SignedTransaction, err error) { +func (e *EvilWallet) CreateTransaction(options ...Option) (*models.TransactionIssuanceData, error) { buildOptions, err := NewOptions(options...) if err != nil { return nil, err @@ -355,15 +362,28 @@ func (e *EvilWallet) CreateTransaction(options ...Option) (signedTx *iotago.Sign } } - signedTx, err = e.makeTransaction(inputs, outputs, buildOptions.inputWallet) + var congestionResp *apimodels.CongestionResponse + // request congestion endpoint if allotment strategy configured + if buildOptions.allotmentStrategy != models.AllotmentStrategyNone { + congestionResp, err = e.connector.GetClient().GetCongestion(buildOptions.issuerAccountID) + if err != nil { + return nil, err + } + } + + signedTx, err := e.makeTransaction(inputs, outputs, buildOptions.inputWallet, congestionResp, buildOptions.allotmentStrategy, buildOptions.issuerAccountID) if err != nil { return nil, err } + txData := &models.TransactionIssuanceData{ + Transaction: signedTx, + CongestionResponse: congestionResp, + } e.addOutputsToOutputManager(signedTx, buildOptions.outputWallet, tempWallet, tempAddresses) e.registerOutputAliases(signedTx, addrAliasMap) - return + return txData, nil } // addOutputsToOutputManager adds output to the OutputManager if. @@ -635,7 +655,7 @@ func (e *EvilWallet) updateOutputBalances(buildOptions *Options) (err error) { return } -func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Outputs[iotago.Output], w *Wallet) (tx *iotago.SignedTransaction, err error) { +func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Outputs[iotago.Output], w *Wallet, congestionResponse *apimodels.CongestionResponse, allotmentStrategy models.AllotmentStrategy, issuerAccountID iotago.AccountID) (tx *iotago.SignedTransaction, err error) { clt := e.Connector().GetClient() txBuilder := builder.NewTransactionBuilder(clt.CurrentAPI()) @@ -666,26 +686,46 @@ func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Out } targetSlot := clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now()) txBuilder.SetCreationSlot(targetSlot) - // allot all mana to the faucet output - // TODO; request block issuer data and congestion, make the same data is used for block issuance - txBuilder.AllotAllMana(targetSlot, rmc, blockIssuerAccountID) + // no allotment strategy + if congestionResponse == nil || allotmentStrategy == models.AllotmentStrategyNone { + return txBuilder.Build(iotago.NewInMemoryAddressSigner(walletKeys...)) + } + switch allotmentStrategy { + case models.AllotmentStrategyAll: + txBuilder.AllotAllMana(targetSlot, congestionResponse.ReferenceManaCost, issuerAccountID) + case models.AllotmentStrategyMinCost: + txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput(targetSlot, congestionResponse.ReferenceManaCost, issuerAccountID, 0) + } return txBuilder.Build(iotago.NewInMemoryAddressSigner(walletKeys...)) } -func (e *EvilWallet) PrepareCustomConflictsSpam(scenario *EvilScenario) (signedTxs [][]*iotago.SignedTransaction, allAliases ScenarioAlias, err error) { +func (e *EvilWallet) PrepareCustomConflictsSpam(scenario *EvilScenario) (txsData [][]*models.TransactionIssuanceData, allAliases ScenarioAlias, err error) { conflicts, allAliases := e.prepareConflictSliceForScenario(scenario) - signedTxs, err = e.PrepareCustomConflicts(conflicts) + txsData, err = e.PrepareCustomConflicts(conflicts) - return + return txsData, allAliases, err } -func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario) (*iotago.SignedTransaction, ScenarioAlias, error) { +func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario) (*models.TransactionIssuanceData, ScenarioAlias, error) { accountSpamOptions, allAliases := e.prepareFlatOptionsForAccountScenario(scenario) - tx, err := e.CreateTransaction(accountSpamOptions...) + txData, err := e.CreateTransaction(accountSpamOptions...) - return tx, allAliases, err + return txData, allAliases, err +} + +func (e *EvilWallet) evaluateIssuanceStrategy(strategy *models.IssuancePaymentStrategy) (models.AllotmentStrategy, iotago.AccountID) { + var issuerAccountID iotago.AccountID + if strategy.AllotmentStrategy != models.AllotmentStrategyNone { + // get issuer accountID + accData, err := e.accWallet.GetAccount(strategy.IssuerAlias) + if err != nil { + panic("could not get issuer accountID while preparing conflicts") + } + issuerAccountID = accData.Account.ID() + } + return strategy.AllotmentStrategy, issuerAccountID } func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (conflictSlice []ConflictSlice, allAliases ScenarioAlias) { @@ -710,11 +750,12 @@ func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (co option = append(option, WithOutputWallet(scenario.OutputWallet)) } if scenario.RestrictedInputWallet != nil { - option = append(option, WithIssuer(scenario.RestrictedInputWallet)) + option = append(option, WithInputWallet(scenario.RestrictedInputWallet)) } if scenario.Reuse { option = append(option, WithReuseOutputs()) } + option = append(option, WithIssuanceStrategy(e.evaluateIssuanceStrategy(scenario.IssuancePaymentStrategy))) conflicts = append(conflicts, option) } conflictSlice = append(conflictSlice, conflicts) @@ -748,7 +789,11 @@ func (e *EvilWallet) prepareFlatOptionsForAccountScenario(scenario *EvilScenario scenarioAlias := evilBatch[0] outs := genOutputOptions(scenarioAlias.Outputs) - return []Option{WithInputs(scenarioAlias.Inputs), WithOutputs(outs)}, allAliases + return []Option{ + WithInputs(scenarioAlias.Inputs), + WithOutputs(outs), + WithIssuanceStrategy(e.evaluateIssuanceStrategy(scenario.IssuancePaymentStrategy)), + }, allAliases } // AwaitInputsSolidity waits for all inputs to be solid for client clt. diff --git a/tools/evil-spammer/evilwallet/options.go b/tools/evil-spammer/evilwallet/options.go index 35dec30da..7b0b581f8 100644 --- a/tools/evil-spammer/evilwallet/options.go +++ b/tools/evil-spammer/evilwallet/options.go @@ -23,6 +23,8 @@ type Options struct { outputBatchAliases map[string]types.Empty reuse bool issuingTime time.Time + allotmentStrategy models.AllotmentStrategy + issuerAccountID iotago.AccountID // maps input alias to desired output type, used to create account output types specialOutputTypes map[string]iotago.OutputType } @@ -163,8 +165,15 @@ func WithOutputs(outputsOptions []*OutputOption) Option { } } -// WithIssuer returns a BlockOption that is used to define the inputWallet of the Block. -func WithIssuer(issuer *Wallet) Option { +func WithIssuanceStrategy(strategy models.AllotmentStrategy, issuerID iotago.AccountID) Option { + return func(options *Options) { + options.allotmentStrategy = strategy + options.issuerAccountID = issuerID + } +} + +// WithInputWallet returns a BlockOption that is used to define the inputWallet of the Block. +func WithInputWallet(issuer *Wallet) Option { return func(options *Options) { options.inputWallet = issuer } diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index b0fa35f2f..35ec8207c 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -176,6 +176,8 @@ type Client interface { GetTransaction(txID iotago.TransactionID) (resp *iotago.SignedTransaction, err error) // GetBlockIssuance returns the latest commitment and data needed to create a new block. GetBlockIssuance() (resp *apimodels.IssuanceBlockHeaderResponse, err error) + // GetCongestion returns congestion data such as rmc or issuing readiness. + GetCongestion(id iotago.AccountID) (resp *apimodels.CongestionResponse, err error) iotago.APIProvider } diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index 304dafd0a..a64b20daa 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -5,6 +5,7 @@ import ( "github.com/iotaledger/iota-core/pkg/blockhandler" iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/nodeclient/apimodels" ) // Input contains details of an input. @@ -67,3 +68,21 @@ func (a *AccountState) ToAccountData() *AccountData { Index: a.Index, } } + +type TransactionIssuanceData struct { + Transaction *iotago.SignedTransaction + CongestionResponse *apimodels.CongestionResponse +} + +type AllotmentStrategy uint8 + +const ( + AllotmentStrategyNone AllotmentStrategy = iota + AllotmentStrategyMinCost + AllotmentStrategyAll +) + +type IssuancePaymentStrategy struct { + AllotmentStrategy AllotmentStrategy + IssuerAlias string +} diff --git a/tools/evil-spammer/spammer/options.go b/tools/evil-spammer/spammer/options.go index daf9c152c..9437f95d3 100644 --- a/tools/evil-spammer/spammer/options.go +++ b/tools/evil-spammer/spammer/options.go @@ -64,7 +64,7 @@ func WithSpammingFunc(spammerFunc func(s *Spammer)) Options { // WithAccountAlias sets the alias of the account that will be used to pay with mana for sent blocks. func WithAccountAlias(alias string) Options { return func(s *Spammer) { - s.IssuerAccountAlias = alias + // TODO add param for allotment strategy } } diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index d4730817e..48b8ff132 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -11,7 +11,6 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" - "github.com/iotaledger/iota-core/tools/evil-spammer/accountwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/evilwallet" "github.com/iotaledger/iota-core/tools/evil-spammer/models" "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" @@ -28,7 +27,7 @@ const ( ) // region Spammer ////////////////////////////////////////////////////////////////////////////////////////////////////// -// + //nolint:revive type SpammerFunc func(*Spammer) @@ -55,15 +54,14 @@ const ( // Not mandatory options, if not provided spammer will use default settings: // WithSpamDetails, WithEvilWallet, WithErrorCounter, WithLogTickerInterval. type Spammer struct { - SpamDetails *SpamDetails - State *State - UseRateSetter bool - SpamType SpamType - IssuerAccountAlias string - Clients models.Connector - EvilWallet *evilwallet.EvilWallet - EvilScenario *evilwallet.EvilScenario - IdentityManager *IdentityManager + SpamDetails *SpamDetails + State *State + UseRateSetter bool + SpamType SpamType + Clients models.Connector + EvilWallet *evilwallet.EvilWallet + EvilScenario *evilwallet.EvilScenario + IdentityManager *IdentityManager // CommitmentManager *CommitmentManager ErrCounter *ErrorCounter @@ -90,13 +88,12 @@ func NewSpammer(options ...Options) *Spammer { logTickTime: time.Second * 30, } s := &Spammer{ - SpamDetails: &SpamDetails{}, - spamFunc: CustomConflictSpammingFunc, - State: state, - SpamType: SpamEvilWallet, - IssuerAccountAlias: accountwallet.FaucetAccountAlias, - EvilScenario: evilwallet.NewEvilScenario(), - IdentityManager: NewIdentityManager(), + SpamDetails: &SpamDetails{}, + spamFunc: CustomConflictSpammingFunc, + State: state, + SpamType: SpamEvilWallet, + EvilScenario: evilwallet.NewEvilScenario(), + IdentityManager: NewIdentityManager(), // CommitmentManager: NewCommitmentManager(), UseRateSetter: true, done: make(chan bool), @@ -234,21 +231,21 @@ func (s *Spammer) StopSpamming() { s.shutdown <- types.Void } -func (s *Spammer) PrepareAndPostBlock(payload iotago.Payload, clt models.Client) { - if payload == nil { +func (s *Spammer) PrepareAndPostBlock(txData *models.TransactionIssuanceData, issuerAlias string, clt models.Client) { + if txData.Transaction == nil { s.log.Debug(ErrPayloadIsNil) s.ErrCounter.CountError(ErrPayloadIsNil) return } - issuerAccount, err := s.EvilWallet.GetAccount(s.IssuerAccountAlias) + issuerAccount, err := s.EvilWallet.GetAccount(issuerAlias) if err != nil { s.log.Debug(ierrors.Wrapf(ErrFailGetAccount, err.Error())) s.ErrCounter.CountError(ierrors.Wrapf(ErrFailGetAccount, err.Error())) return } - blockID, err := s.EvilWallet.PrepareAndPostBlock(clt, payload, issuerAccount) + blockID, err := s.EvilWallet.PrepareAndPostBlock(clt, txData.Transaction, txData.CongestionResponse, issuerAccount) if err != nil { s.log.Debug(ierrors.Wrapf(ErrFailPostBlock, err.Error())) s.ErrCounter.CountError(ierrors.Wrapf(ErrFailPostBlock, err.Error())) @@ -256,12 +253,11 @@ func (s *Spammer) PrepareAndPostBlock(payload iotago.Payload, clt models.Client) return } - if payload.PayloadType() != iotago.PayloadSignedTransaction { + if txData.Transaction.PayloadType() != iotago.PayloadSignedTransaction { return } - signedTx := payload.(*iotago.SignedTransaction) - txID, err := signedTx.Transaction.ID() + txID, err := txData.Transaction.Transaction.ID() if err != nil { s.log.Debug(ierrors.Wrapf(ErrTransactionInvalid, err.Error())) s.ErrCounter.CountError(ierrors.Wrapf(ErrTransactionInvalid, err.Error())) @@ -270,10 +266,10 @@ func (s *Spammer) PrepareAndPostBlock(payload iotago.Payload, clt models.Client) } // reuse outputs - if payload.PayloadType() == iotago.PayloadSignedTransaction { + if txData.Transaction.PayloadType() == iotago.PayloadSignedTransaction { if s.EvilScenario.OutputWallet.Type() == evilwallet.Reuse { var outputIDs iotago.OutputIDs - for index := range signedTx.Transaction.Outputs { + for index := range txData.Transaction.Transaction.Outputs { outputIDs = append(outputIDs, iotago.OutputIDFromTransactionIDAndIndex(txID, uint16(index))) } s.EvilWallet.SetTxOutputsSolid(outputIDs, clt.URL()) diff --git a/tools/evil-spammer/spammer/spamming_functions.go b/tools/evil-spammer/spammer/spamming_functions.go index 047cbf73f..4bdb068cd 100644 --- a/tools/evil-spammer/spammer/spamming_functions.go +++ b/tools/evil-spammer/spammer/spamming_functions.go @@ -7,7 +7,6 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/iota-core/tools/evil-spammer/models" - iotago "github.com/iotaledger/iota.go/v4" ) func DataSpammingFunction(s *Spammer) { @@ -39,26 +38,26 @@ func CustomConflictSpammingFunc(s *Spammer) { s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) } - for _, txs := range conflictBatch { - clients := s.Clients.GetClients(len(txs)) - if len(txs) > len(clients) { + for _, txsData := range conflictBatch { + clients := s.Clients.GetClients(len(txsData)) + if len(txsData) > len(clients) { s.log.Debug(ErrFailToPrepareBatch) s.ErrCounter.CountError(ErrInsufficientClients) } // send transactions in parallel wg := sync.WaitGroup{} - for i, tx := range txs { + for i, txData := range txsData { wg.Add(1) - go func(clt models.Client, tx *iotago.SignedTransaction) { + go func(clt models.Client, tx *models.TransactionIssuanceData) { defer wg.Done() // sleep randomly to avoid issuing blocks in different goroutines at once //nolint:gosec time.Sleep(time.Duration(rand.Float64()*100) * time.Millisecond) - s.PrepareAndPostBlock(tx, clt) - }(clients[i], tx) + s.PrepareAndPostBlock(tx, s.EvilScenario.IssuancePaymentStrategy.IssuerAlias, clt) + }(clients[i], txData) } wg.Wait() } @@ -70,12 +69,12 @@ func CustomConflictSpammingFunc(s *Spammer) { func AccountSpammingFunction(s *Spammer) { clt := s.Clients.GetClient() // update scenario - tx, aliases, err := s.EvilWallet.PrepareAccountSpam(s.EvilScenario) + txData, aliases, err := s.EvilWallet.PrepareAccountSpam(s.EvilScenario) if err != nil { s.log.Debugf(ierrors.Wrap(ErrFailToPrepareBatch, err.Error()).Error()) s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) } - s.PrepareAndPostBlock(tx, clt) + s.PrepareAndPostBlock(txData, s.EvilScenario.IssuancePaymentStrategy.IssuerAlias, clt) s.State.batchPrepared.Add(1) s.EvilWallet.ClearAliases(aliases) From 96937a2231386d063ae02a8e3b2a9ff86c83f197 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Fri, 13 Oct 2023 15:46:35 +0800 Subject: [PATCH 72/84] Use latest outputID from TxID and index method --- components/restapi/core/transaction.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/restapi/core/transaction.go b/components/restapi/core/transaction.go index 0ee22c7d4..356392dca 100644 --- a/components/restapi/core/transaction.go +++ b/components/restapi/core/transaction.go @@ -22,8 +22,7 @@ func blockIDByTransactionID(c echo.Context) (iotago.BlockID, error) { func blockIDFromTransactionID(transactionID iotago.TransactionID) (iotago.BlockID, error) { // Get the first output of that transaction (using index 0) - outputID := iotago.OutputID{} - copy(outputID[:], transactionID[:]) + outputID := iotago.OutputIDFromTransactionIDAndIndex(transactionID, 0) output, err := deps.Protocol.MainEngineInstance().Ledger.Output(outputID) if err != nil { From 1026cf49489c09bda626581dff62c9921529855a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 13 Oct 2023 11:22:06 +0200 Subject: [PATCH 73/84] Use allotAll strategy for all tx spams, and noAllotment for data spam --- tools/evil-spammer/evilwallet/evilscenario.go | 6 --- tools/evil-spammer/evilwallet/evilwallet.go | 44 +++++++++++-------- tools/evil-spammer/models/output.go | 4 +- tools/evil-spammer/spammer/options.go | 2 +- tools/evil-spammer/spammer/spammer.go | 19 ++++---- .../spammer/spamming_functions.go | 36 ++++++++------- 6 files changed, 59 insertions(+), 52 deletions(-) diff --git a/tools/evil-spammer/evilwallet/evilscenario.go b/tools/evil-spammer/evilwallet/evilscenario.go index b8033ee36..00f15d968 100644 --- a/tools/evil-spammer/evilwallet/evilscenario.go +++ b/tools/evil-spammer/evilwallet/evilscenario.go @@ -8,7 +8,6 @@ import ( "go.uber.org/atomic" "github.com/iotaledger/hive.go/ds/types" - "github.com/iotaledger/iota-core/tools/evil-spammer/models" iotago "github.com/iotaledger/iota.go/v4" ) @@ -55,8 +54,6 @@ type EvilScenario struct { BatchesCreated *atomic.Uint64 // used to determine how many clients are needed to run this scenario, some double spends need more than one client to pass the filter NumOfClientsNeeded int - // used to indicate if and how to include allotment into a transaction. - IssuancePaymentStrategy *models.IssuancePaymentStrategy } func NewEvilScenario(options ...ScenarioOption) *EvilScenario { @@ -66,9 +63,6 @@ func NewEvilScenario(options ...ScenarioOption) *EvilScenario { OutputType: iotago.OutputBasic, OutputWallet: NewWallet(), BatchesCreated: atomic.NewUint64(0), - IssuancePaymentStrategy: &models.IssuancePaymentStrategy{ - AllotmentStrategy: models.AllotmentStrategyNone, - }, } for _, option := range options { diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 2a462a195..c28a9c96c 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -1,6 +1,7 @@ package evilwallet import ( + "fmt" "sync" "time" @@ -274,12 +275,16 @@ func (e *EvilWallet) splitOutputs(splitOutput *models.Output, inputWallet, outpu return iotago.EmptyTransactionID, err } - _, err = e.PrepareAndPostBlock(e.connector.GetClient(), txData.Transaction, txData.CongestionResponse, faucetAccount.Account) + _, err = e.PrepareAndPostBlock(e.connector.GetClient(), txData.Payload, txData.CongestionResponse, faucetAccount.Account) if err != nil { return iotago.TransactionID{}, err } - txID := lo.PanicOnErr(txData.Transaction.Transaction.ID()) + if txData.Payload.PayloadType() != iotago.PayloadSignedTransaction { + return iotago.EmptyTransactionID, ierrors.New("payload type is not signed transaction") + } + + txID := lo.PanicOnErr(txData.Payload.(*iotago.SignedTransaction).Transaction.ID()) e.log.Debugf("Splitting output %s finished with tx: %s", splitOutput.OutputID.ToHex(), txID.ToHex()) @@ -311,9 +316,9 @@ func (e *EvilWallet) ClearAllAliases() { e.aliasManager.ClearAllAliases() } -func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conflictBatch [][]*models.TransactionIssuanceData, err error) { +func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conflictBatch [][]*models.PayloadIssuanceData, err error) { for _, conflictMap := range conflictsMaps { - var txsData []*models.TransactionIssuanceData + var txsData []*models.PayloadIssuanceData for _, conflictOptions := range conflictMap { txData, err2 := e.CreateTransaction(conflictOptions...) if err2 != nil { @@ -331,7 +336,7 @@ func (e *EvilWallet) PrepareCustomConflicts(conflictsMaps []ConflictSlice) (conf // Inputs of the transaction are determined in three ways: // 1 - inputs are provided directly without associated alias, 2- alias is provided, and input is already stored in an alias manager, // 3 - alias is provided, and there are no inputs assigned in Alias manager, so aliases are assigned to next ready inputs from input wallet. -func (e *EvilWallet) CreateTransaction(options ...Option) (*models.TransactionIssuanceData, error) { +func (e *EvilWallet) CreateTransaction(options ...Option) (*models.PayloadIssuanceData, error) { buildOptions, err := NewOptions(options...) if err != nil { return nil, err @@ -364,7 +369,7 @@ func (e *EvilWallet) CreateTransaction(options ...Option) (*models.TransactionIs var congestionResp *apimodels.CongestionResponse // request congestion endpoint if allotment strategy configured - if buildOptions.allotmentStrategy != models.AllotmentStrategyNone { + if buildOptions.allotmentStrategy == models.AllotmentStrategyMinCost { congestionResp, err = e.connector.GetClient().GetCongestion(buildOptions.issuerAccountID) if err != nil { return nil, err @@ -375,8 +380,8 @@ func (e *EvilWallet) CreateTransaction(options ...Option) (*models.TransactionIs if err != nil { return nil, err } - txData := &models.TransactionIssuanceData{ - Transaction: signedTx, + txData := &models.PayloadIssuanceData{ + Payload: signedTx, CongestionResponse: congestionResp, } @@ -687,28 +692,31 @@ func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Out targetSlot := clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now()) txBuilder.SetCreationSlot(targetSlot) // no allotment strategy - if congestionResponse == nil || allotmentStrategy == models.AllotmentStrategyNone { + if congestionResponse == nil { + fmt.Printf("Make transaction no allotment\n") return txBuilder.Build(iotago.NewInMemoryAddressSigner(walletKeys...)) } switch allotmentStrategy { case models.AllotmentStrategyAll: - txBuilder.AllotAllMana(targetSlot, congestionResponse.ReferenceManaCost, issuerAccountID) + fmt.Printf("MakeTransaction, issuerAccID %s, congestionResponse %v\n", issuerAccountID.ToHex(), congestionResponse) + txBuilder.AllotAllMana(targetSlot, issuerAccountID) case models.AllotmentStrategyMinCost: + fmt.Printf("Allot only required\n") txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput(targetSlot, congestionResponse.ReferenceManaCost, issuerAccountID, 0) } return txBuilder.Build(iotago.NewInMemoryAddressSigner(walletKeys...)) } -func (e *EvilWallet) PrepareCustomConflictsSpam(scenario *EvilScenario) (txsData [][]*models.TransactionIssuanceData, allAliases ScenarioAlias, err error) { - conflicts, allAliases := e.prepareConflictSliceForScenario(scenario) +func (e *EvilWallet) PrepareCustomConflictsSpam(scenario *EvilScenario, strategy *models.IssuancePaymentStrategy) (txsData [][]*models.PayloadIssuanceData, allAliases ScenarioAlias, err error) { + conflicts, allAliases := e.prepareConflictSliceForScenario(scenario, strategy) txsData, err = e.PrepareCustomConflicts(conflicts) return txsData, allAliases, err } -func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario) (*models.TransactionIssuanceData, ScenarioAlias, error) { - accountSpamOptions, allAliases := e.prepareFlatOptionsForAccountScenario(scenario) +func (e *EvilWallet) PrepareAccountSpam(scenario *EvilScenario, strategy *models.IssuancePaymentStrategy) (*models.PayloadIssuanceData, ScenarioAlias, error) { + accountSpamOptions, allAliases := e.prepareFlatOptionsForAccountScenario(scenario, strategy) txData, err := e.CreateTransaction(accountSpamOptions...) @@ -728,7 +736,7 @@ func (e *EvilWallet) evaluateIssuanceStrategy(strategy *models.IssuancePaymentSt return strategy.AllotmentStrategy, issuerAccountID } -func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (conflictSlice []ConflictSlice, allAliases ScenarioAlias) { +func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario, strategy *models.IssuancePaymentStrategy) (conflictSlice []ConflictSlice, allAliases ScenarioAlias) { genOutputOptions := func(aliases []string) []*OutputOption { outputOptions := make([]*OutputOption, 0) for _, o := range aliases { @@ -755,7 +763,7 @@ func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (co if scenario.Reuse { option = append(option, WithReuseOutputs()) } - option = append(option, WithIssuanceStrategy(e.evaluateIssuanceStrategy(scenario.IssuancePaymentStrategy))) + option = append(option, WithIssuanceStrategy(e.evaluateIssuanceStrategy(strategy))) conflicts = append(conflicts, option) } conflictSlice = append(conflictSlice, conflicts) @@ -764,7 +772,7 @@ func (e *EvilWallet) prepareConflictSliceForScenario(scenario *EvilScenario) (co return } -func (e *EvilWallet) prepareFlatOptionsForAccountScenario(scenario *EvilScenario) ([]Option, ScenarioAlias) { +func (e *EvilWallet) prepareFlatOptionsForAccountScenario(scenario *EvilScenario, strategy *models.IssuancePaymentStrategy) ([]Option, ScenarioAlias) { // we do not care about batchedOutputs, because we do not support saving account spam result in evil wallet for now prefixedBatch, allAliases, _ := scenario.ConflictBatchWithPrefix() if len(prefixedBatch) != 1 { @@ -792,7 +800,7 @@ func (e *EvilWallet) prepareFlatOptionsForAccountScenario(scenario *EvilScenario return []Option{ WithInputs(scenarioAlias.Inputs), WithOutputs(outs), - WithIssuanceStrategy(e.evaluateIssuanceStrategy(scenario.IssuancePaymentStrategy)), + WithIssuanceStrategy(e.evaluateIssuanceStrategy(strategy)), }, allAliases } diff --git a/tools/evil-spammer/models/output.go b/tools/evil-spammer/models/output.go index a64b20daa..539da3a19 100644 --- a/tools/evil-spammer/models/output.go +++ b/tools/evil-spammer/models/output.go @@ -69,8 +69,8 @@ func (a *AccountState) ToAccountData() *AccountData { } } -type TransactionIssuanceData struct { - Transaction *iotago.SignedTransaction +type PayloadIssuanceData struct { + Payload iotago.Payload CongestionResponse *apimodels.CongestionResponse } diff --git a/tools/evil-spammer/spammer/options.go b/tools/evil-spammer/spammer/options.go index 9437f95d3..0077ab1af 100644 --- a/tools/evil-spammer/spammer/options.go +++ b/tools/evil-spammer/spammer/options.go @@ -64,7 +64,7 @@ func WithSpammingFunc(spammerFunc func(s *Spammer)) Options { // WithAccountAlias sets the alias of the account that will be used to pay with mana for sent blocks. func WithAccountAlias(alias string) Options { return func(s *Spammer) { - // TODO add param for allotment strategy + s.IssuerAlias = alias } } diff --git a/tools/evil-spammer/spammer/spammer.go b/tools/evil-spammer/spammer/spammer.go index 48b8ff132..5037556f6 100644 --- a/tools/evil-spammer/spammer/spammer.go +++ b/tools/evil-spammer/spammer/spammer.go @@ -63,7 +63,8 @@ type Spammer struct { EvilScenario *evilwallet.EvilScenario IdentityManager *IdentityManager // CommitmentManager *CommitmentManager - ErrCounter *ErrorCounter + ErrCounter *ErrorCounter + IssuerAlias string log Logger api iotago.API @@ -231,8 +232,8 @@ func (s *Spammer) StopSpamming() { s.shutdown <- types.Void } -func (s *Spammer) PrepareAndPostBlock(txData *models.TransactionIssuanceData, issuerAlias string, clt models.Client) { - if txData.Transaction == nil { +func (s *Spammer) PrepareAndPostBlock(txData *models.PayloadIssuanceData, issuerAlias string, clt models.Client) { + if txData.Payload == nil { s.log.Debug(ErrPayloadIsNil) s.ErrCounter.CountError(ErrPayloadIsNil) @@ -245,7 +246,7 @@ func (s *Spammer) PrepareAndPostBlock(txData *models.TransactionIssuanceData, is return } - blockID, err := s.EvilWallet.PrepareAndPostBlock(clt, txData.Transaction, txData.CongestionResponse, issuerAccount) + blockID, err := s.EvilWallet.PrepareAndPostBlock(clt, txData.Payload, txData.CongestionResponse, issuerAccount) if err != nil { s.log.Debug(ierrors.Wrapf(ErrFailPostBlock, err.Error())) s.ErrCounter.CountError(ierrors.Wrapf(ErrFailPostBlock, err.Error())) @@ -253,11 +254,13 @@ func (s *Spammer) PrepareAndPostBlock(txData *models.TransactionIssuanceData, is return } - if txData.Transaction.PayloadType() != iotago.PayloadSignedTransaction { + if txData.Payload.PayloadType() != iotago.PayloadSignedTransaction { return } - txID, err := txData.Transaction.Transaction.ID() + signedTx := txData.Payload.(*iotago.SignedTransaction) + + txID, err := signedTx.Transaction.ID() if err != nil { s.log.Debug(ierrors.Wrapf(ErrTransactionInvalid, err.Error())) s.ErrCounter.CountError(ierrors.Wrapf(ErrTransactionInvalid, err.Error())) @@ -266,10 +269,10 @@ func (s *Spammer) PrepareAndPostBlock(txData *models.TransactionIssuanceData, is } // reuse outputs - if txData.Transaction.PayloadType() == iotago.PayloadSignedTransaction { + if txData.Payload.PayloadType() == iotago.PayloadSignedTransaction { if s.EvilScenario.OutputWallet.Type() == evilwallet.Reuse { var outputIDs iotago.OutputIDs - for index := range txData.Transaction.Transaction.Outputs { + for index := range signedTx.Transaction.Outputs { outputIDs = append(outputIDs, iotago.OutputIDFromTransactionIDAndIndex(txID, uint16(index))) } s.EvilWallet.SetTxOutputsSolid(outputIDs, clt.URL()) diff --git a/tools/evil-spammer/spammer/spamming_functions.go b/tools/evil-spammer/spammer/spamming_functions.go index 4bdb068cd..2462c07ca 100644 --- a/tools/evil-spammer/spammer/spamming_functions.go +++ b/tools/evil-spammer/spammer/spamming_functions.go @@ -7,6 +7,7 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/iota-core/tools/evil-spammer/models" + iotago "github.com/iotaledger/iota.go/v4" ) func DataSpammingFunction(s *Spammer) { @@ -14,25 +15,23 @@ func DataSpammingFunction(s *Spammer) { // sleep randomly to avoid issuing blocks in different goroutines at once //nolint:gosec time.Sleep(time.Duration(rand.Float64()*20) * time.Millisecond) - // if err := wallet.RateSetterSleep(clt, s.UseRateSetter); err != nil { - // s.ErrCounter.CountError(err) - // } - blkID, err := clt.PostData([]byte("SPAM")) - if err != nil { - s.ErrCounter.CountError(ErrFailSendDataBlock) - s.log.Error(err) - } - count := s.State.txSent.Add(1) - if count%int64(s.SpamDetails.Rate*2) == 0 { - s.log.Debugf("Last sent block, ID: %s; blkCount: %d", blkID, count) - } + s.PrepareAndPostBlock(&models.PayloadIssuanceData{ + Payload: &iotago.TaggedData{ + Tag: []byte("SPAM"), + }, + }, s.IssuerAlias, clt) + s.State.batchPrepared.Add(1) s.CheckIfAllSent() } func CustomConflictSpammingFunc(s *Spammer) { - conflictBatch, aliases, err := s.EvilWallet.PrepareCustomConflictsSpam(s.EvilScenario) + conflictBatch, aliases, err := s.EvilWallet.PrepareCustomConflictsSpam(s.EvilScenario, &models.IssuancePaymentStrategy{ + AllotmentStrategy: models.AllotmentStrategyAll, + IssuerAlias: s.IssuerAlias, + }) + if err != nil { s.log.Debugf(ierrors.Wrap(ErrFailToPrepareBatch, err.Error()).Error()) s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) @@ -49,14 +48,14 @@ func CustomConflictSpammingFunc(s *Spammer) { wg := sync.WaitGroup{} for i, txData := range txsData { wg.Add(1) - go func(clt models.Client, tx *models.TransactionIssuanceData) { + go func(clt models.Client, tx *models.PayloadIssuanceData) { defer wg.Done() // sleep randomly to avoid issuing blocks in different goroutines at once //nolint:gosec time.Sleep(time.Duration(rand.Float64()*100) * time.Millisecond) - s.PrepareAndPostBlock(tx, s.EvilScenario.IssuancePaymentStrategy.IssuerAlias, clt) + s.PrepareAndPostBlock(tx, s.IssuerAlias, clt) }(clients[i], txData) } wg.Wait() @@ -69,12 +68,15 @@ func CustomConflictSpammingFunc(s *Spammer) { func AccountSpammingFunction(s *Spammer) { clt := s.Clients.GetClient() // update scenario - txData, aliases, err := s.EvilWallet.PrepareAccountSpam(s.EvilScenario) + txData, aliases, err := s.EvilWallet.PrepareAccountSpam(s.EvilScenario, &models.IssuancePaymentStrategy{ + AllotmentStrategy: models.AllotmentStrategyAll, + IssuerAlias: s.IssuerAlias, + }) if err != nil { s.log.Debugf(ierrors.Wrap(ErrFailToPrepareBatch, err.Error()).Error()) s.ErrCounter.CountError(ierrors.Wrap(ErrFailToPrepareBatch, err.Error())) } - s.PrepareAndPostBlock(txData, s.EvilScenario.IssuancePaymentStrategy.IssuerAlias, clt) + s.PrepareAndPostBlock(txData, s.IssuerAlias, clt) s.State.batchPrepared.Add(1) s.EvilWallet.ClearAliases(aliases) From 71339f8cde82644e3c6cbf43a6d06fc12740c201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 13 Oct 2023 11:45:36 +0200 Subject: [PATCH 74/84] Add fallback strategy if potential mana on genesis is not enough --- tools/evil-spammer/accountwallet/faucet.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 819d779b5..5613aaa3f 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -206,14 +206,18 @@ func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago. return nil, err } + rmcAllotedTxBuilder := txBuilder.Clone() // faucet will allot exact mana to be burnt, rest of the mana is alloted to faucet output remainder - txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput(txBuilder.CreationSlot(), rmc, f.account.ID(), remainderIndex) + rmcAllotedTxBuilder.AllotRequiredManaAndStoreRemainingManaInOutput(txBuilder.CreationSlot(), rmc, f.account.ID(), remainderIndex) - signedTx, err := txBuilder.Build(f.genesisHdWallet.AddressSigner()) + var signedTx *iotago.SignedTransaction + signedTx, err = rmcAllotedTxBuilder.Build(f.genesisHdWallet.AddressSigner()) if err != nil { - log.Errorf("failed to build transaction: %s", err) - - return nil, err + log.Infof("WARN: failed to build tx with min required mana allotted, genesis potential mana was not enough, fallback to faucet account") + txBuilder.AllotAllMana(txBuilder.CreationSlot(), f.account.ID()) + if signedTx, err = txBuilder.Build(f.genesisHdWallet.AddressSigner()); err != nil { + return nil, ierrors.Wrapf(err, "failed to build transaction with all mana allotted, after not having enough mana required based on RMC") + } } return signedTx, nil From c715d6c41929cb7a711e535902a064e5fe6f7204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Fri, 13 Oct 2023 12:03:23 +0200 Subject: [PATCH 75/84] Update go mod --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 06abbdcd7..76a675061 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/iotaledger/hive.go/stringify v0.0.0-20231010133617-cdbd5387e2af github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231011161248-cf0bd6e08811 github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231011154428-257141868dad - github.com/iotaledger/iota.go/v4 v4.0.0-20231011161154-7004432004e1 + github.com/iotaledger/iota.go/v4 v4.0.0-20231013092100-ad2a52b5ac9a github.com/labstack/echo/v4 v4.11.2 github.com/labstack/gommon v0.4.0 github.com/libp2p/go-libp2p v0.30.0 diff --git a/go.sum b/go.sum index 864310299..42d166a1e 100644 --- a/go.sum +++ b/go.sum @@ -311,6 +311,8 @@ github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231011154428-257141868dad h1:TRM9Ek github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231011154428-257141868dad/go.mod h1:plZ0+8yLdDWHedj3SfHUwQtIETD+lcS6M1iEAxcjzJ4= github.com/iotaledger/iota.go/v4 v4.0.0-20231011161154-7004432004e1 h1:mz5E00q1U/LDiUi/wVAbwdhGNKX0dNThaO99Fsyjkgs= github.com/iotaledger/iota.go/v4 v4.0.0-20231011161154-7004432004e1/go.mod h1:XmgOVYZ7805zVEYPwhvqBDVa7XieXRgPrCEGZW35W8k= +github.com/iotaledger/iota.go/v4 v4.0.0-20231013092100-ad2a52b5ac9a h1:S/n3ZTjnnl0IIMCx+S0pu5CZNArO6Z+omiXt6dDmPK4= +github.com/iotaledger/iota.go/v4 v4.0.0-20231013092100-ad2a52b5ac9a/go.mod h1:XmgOVYZ7805zVEYPwhvqBDVa7XieXRgPrCEGZW35W8k= 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= From 5f52f91b298ce120957f574a096a9a16733fe744 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Tue, 17 Oct 2023 15:07:43 +0800 Subject: [PATCH 76/84] Minor refactor --- components/restapi/core/accounts.go | 2 +- tools/evil-spammer/accountwallet/faucet.go | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/components/restapi/core/accounts.go b/components/restapi/core/accounts.go index 675a266d3..7d1e33fb4 100644 --- a/components/restapi/core/accounts.go +++ b/components/restapi/core/accounts.go @@ -141,7 +141,7 @@ func rewardsByOutputID(c echo.Context) (*apimodels.ManaRewardsResponse, error) { utxoOutput, err := deps.Protocol.MainEngineInstance().Ledger.Output(outputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get output %s from ledger", outputID) + return nil, ierrors.Wrapf(err, "failed to get output %s from ledger", outputID.ToHex()) } var reward iotago.Mana diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 5613aaa3f..570d86929 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -84,22 +84,14 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, return iotago.EmptyBlockID, err } - _, err = clt.PostBlock(signedBlock) + blockID, err := clt.PostBlock(signedBlock) if err != nil { log.Errorf("failed to post block: %s", err) return iotago.EmptyBlockID, err } - blockID, err := signedBlock.ID() - if err != nil { - log.Errorf("failed to get block id: %s", err) - - return iotago.EmptyBlockID, err - } - return blockID, nil - } func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler.Account, congestionResp *apimodels.CongestionResponse, issuerResp *apimodels.IssuanceBlockHeaderResponse, version iotago.Version) (*iotago.ProtocolBlock, error) { From 3fdf36967a527269bd5a4013a15ccbe62e9a13a0 Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Tue, 17 Oct 2023 15:08:32 +0800 Subject: [PATCH 77/84] Read OutputOrSpent in blockIDFromTransactionID --- components/restapi/core/transaction.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/restapi/core/transaction.go b/components/restapi/core/transaction.go index 356392dca..44575426a 100644 --- a/components/restapi/core/transaction.go +++ b/components/restapi/core/transaction.go @@ -24,12 +24,16 @@ func blockIDFromTransactionID(transactionID iotago.TransactionID) (iotago.BlockI // Get the first output of that transaction (using index 0) outputID := iotago.OutputIDFromTransactionIDAndIndex(transactionID, 0) - output, err := deps.Protocol.MainEngineInstance().Ledger.Output(outputID) + output, spent, err := deps.Protocol.MainEngineInstance().Ledger.OutputOrSpent(outputID) if err != nil { - return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to get output: %s", outputID.String()) + return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to get output: %s", outputID.ToHex()) } - return output.BlockID(), nil + if output != nil { + return output.BlockID(), nil + } + + return spent.BlockID(), nil } func blockByTransactionID(c echo.Context) (*model.Block, error) { From 46dcf5b42c4044e85f38109cacef838578c542ab Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Tue, 17 Oct 2023 15:11:03 +0800 Subject: [PATCH 78/84] Add .dat to gitignore --- tools/evil-spammer/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/evil-spammer/.gitignore b/tools/evil-spammer/.gitignore index 97be5e00b..301d5d62d 100644 --- a/tools/evil-spammer/.gitignore +++ b/tools/evil-spammer/.gitignore @@ -1,2 +1,3 @@ *.log -*.json \ No newline at end of file +*.json +*.dat \ No newline at end of file From 539024063360a2adad00c2813eec7a79514916ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 17 Oct 2023 14:02:32 +0200 Subject: [PATCH 79/84] go mod tidy --- tools/evil-spammer/go.mod | 7 ++++--- tools/evil-spammer/go.sum | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/evil-spammer/go.mod b/tools/evil-spammer/go.mod index 2381fe759..30cc8c60c 100644 --- a/tools/evil-spammer/go.mod +++ b/tools/evil-spammer/go.mod @@ -8,7 +8,9 @@ replace github.com/iotaledger/iota-core/tools/genesis-snapshot => ../genesis-sna require ( github.com/AlecAivazis/survey/v2 v2.3.7 + github.com/ethereum/go-ethereum v1.13.2 github.com/iotaledger/hive.go/app v0.0.0-20231010133617-cdbd5387e2af + github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231010133617-cdbd5387e2af github.com/iotaledger/hive.go/crypto v0.0.0-20231010133617-cdbd5387e2af github.com/iotaledger/hive.go/ds v0.0.0-20231010133617-cdbd5387e2af github.com/iotaledger/hive.go/ierrors v0.0.0-20231010133617-cdbd5387e2af @@ -17,7 +19,7 @@ require ( github.com/iotaledger/hive.go/runtime v0.0.0-20231010133617-cdbd5387e2af github.com/iotaledger/iota-core v0.0.0-00010101000000-000000000000 github.com/iotaledger/iota-core/tools/genesis-snapshot v0.0.0-00010101000000-000000000000 - github.com/iotaledger/iota.go/v4 v4.0.0-20231011161154-7004432004e1 + github.com/iotaledger/iota.go/v4 v4.0.0-20231013092100-ad2a52b5ac9a github.com/mr-tron/base58 v1.2.0 go.uber.org/atomic v1.11.0 ) @@ -28,9 +30,9 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/eclipse/paho.mqtt.golang v1.4.3 // indirect - github.com/ethereum/go-ethereum v1.13.2 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect github.com/google/uuid v1.3.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/holiman/uint256 v1.2.3 // indirect @@ -38,7 +40,6 @@ require ( github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 // indirect github.com/iotaledger/hive.go/ads v0.0.0-20231010133617-cdbd5387e2af // indirect github.com/iotaledger/hive.go/constraints v0.0.0-20231010133617-cdbd5387e2af // indirect - github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231010133617-cdbd5387e2af // indirect github.com/iotaledger/hive.go/kvstore v0.0.0-20231010133617-cdbd5387e2af // indirect github.com/iotaledger/hive.go/log v0.0.0-20231010133617-cdbd5387e2af // indirect github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231010133617-cdbd5387e2af // indirect diff --git a/tools/evil-spammer/go.sum b/tools/evil-spammer/go.sum index c5109f6b5..db0f63d48 100644 --- a/tools/evil-spammer/go.sum +++ b/tools/evil-spammer/go.sum @@ -82,6 +82,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -197,8 +199,8 @@ github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231010133617-cdbd538 github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231010133617-cdbd5387e2af/go.mod h1:IJgaaxbgKCsNat18jlJJEAxCY2oVYR3F30B+M4vJ89I= github.com/iotaledger/hive.go/stringify v0.0.0-20231010133617-cdbd5387e2af h1:2/8In9gw03NW1hL4qyXuFYFoWZScHmyZtYUG0kHPmo4= github.com/iotaledger/hive.go/stringify v0.0.0-20231010133617-cdbd5387e2af/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/iotaledger/iota.go/v4 v4.0.0-20231011161154-7004432004e1 h1:mz5E00q1U/LDiUi/wVAbwdhGNKX0dNThaO99Fsyjkgs= -github.com/iotaledger/iota.go/v4 v4.0.0-20231011161154-7004432004e1/go.mod h1:XmgOVYZ7805zVEYPwhvqBDVa7XieXRgPrCEGZW35W8k= +github.com/iotaledger/iota.go/v4 v4.0.0-20231013092100-ad2a52b5ac9a h1:S/n3ZTjnnl0IIMCx+S0pu5CZNArO6Z+omiXt6dDmPK4= +github.com/iotaledger/iota.go/v4 v4.0.0-20231013092100-ad2a52b5ac9a/go.mod h1:XmgOVYZ7805zVEYPwhvqBDVa7XieXRgPrCEGZW35W8k= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= From 9e8499dd741bd0be3c723b64491fbbfe3a024a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 17 Oct 2023 14:02:41 +0200 Subject: [PATCH 80/84] Remove prints --- tools/evil-spammer/accountwallet/faucet.go | 5 ++--- tools/evil-spammer/evilwallet/evilwallet.go | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 570d86929..352bda995 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -2,7 +2,6 @@ package accountwallet import ( "context" - "fmt" "sync" "time" @@ -116,7 +115,7 @@ func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler. blk, err := blockBuilder.Build() if err != nil { - return nil, fmt.Errorf("failed to build block: %w", err) + return nil, ierrors.Errorf("failed to build block: %w", err) } return blk, nil @@ -166,7 +165,7 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { } genesisSeed, err := base58.Decode(faucetParams.genesisSeed) if err != nil { - fmt.Printf("failed to decode base58 seed, using the default one: %v", err) + log.Warnf("failed to decode base58 seed, using the default one: %v", err) } f := &faucet{ diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index c28a9c96c..35b22cddb 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -1,7 +1,6 @@ package evilwallet import ( - "fmt" "sync" "time" @@ -693,15 +692,12 @@ func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Out txBuilder.SetCreationSlot(targetSlot) // no allotment strategy if congestionResponse == nil { - fmt.Printf("Make transaction no allotment\n") return txBuilder.Build(iotago.NewInMemoryAddressSigner(walletKeys...)) } switch allotmentStrategy { case models.AllotmentStrategyAll: - fmt.Printf("MakeTransaction, issuerAccID %s, congestionResponse %v\n", issuerAccountID.ToHex(), congestionResponse) txBuilder.AllotAllMana(targetSlot, issuerAccountID) case models.AllotmentStrategyMinCost: - fmt.Printf("Allot only required\n") txBuilder.AllotRequiredManaAndStoreRemainingManaInOutput(targetSlot, congestionResponse.ReferenceManaCost, issuerAccountID, 0) } From b7182f9dabadea50580fa0f7f394e4b273978862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 17 Oct 2023 14:34:11 +0200 Subject: [PATCH 81/84] Do not use currentAPI, use latest and slot specific --- tools/evil-spammer/accountwallet/faucet.go | 18 ++++++++++++++---- tools/evil-spammer/accountwallet/wallet.go | 12 +++++++----- tools/evil-spammer/evilwallet/evilwallet.go | 7 +++++-- tools/evil-spammer/models/connector.go | 2 +- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 352bda995..5e679f9fa 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -34,7 +34,9 @@ func (a *AccountWallet) RequestBlockBuiltData(clt *nodeclient.Client, issuerID i return nil, nil, 0, ierrors.Wrap(err, "failed to get block issuance data") } - return congestionResp, issuerResp, clt.CurrentAPI().Version(), nil + version := clt.APIForSlot(congestionResp.Slot).Version() + + return congestionResp, issuerResp, version, nil } func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago.Address, amount iotago.BaseToken) (*models.Output, error) { @@ -94,7 +96,11 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, } func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler.Account, congestionResp *apimodels.CongestionResponse, issuerResp *apimodels.IssuanceBlockHeaderResponse, version iotago.Version) (*iotago.ProtocolBlock, error) { - blockBuilder := builder.NewBasicBlockBuilder(a.api) + issuingTime := time.Now() + issuingSlot := a.client.LatestAPI().TimeProvider().SlotFromTime(issuingTime) + apiForSlot := a.client.APIForSlot(issuingSlot) + + blockBuilder := builder.NewBasicBlockBuilder(apiForSlot) commitmentID, err := issuerResp.Commitment.ID() if err != nil { @@ -215,7 +221,11 @@ func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago. } func (f *faucet) createFaucetTransactionNoManaHandling(receiveAddr iotago.Address, amount iotago.BaseToken, remainderAmount iotago.BaseToken) (*builder.TransactionBuilder, int, error) { - txBuilder := builder.NewTransactionBuilder(f.clt.CurrentAPI()) + currentTime := time.Now() + currentSlot := f.clt.LatestAPI().TimeProvider().SlotFromTime(currentTime) + + apiForSlot := f.clt.APIForSlot(currentSlot) + txBuilder := builder.NewTransactionBuilder(apiForSlot) txBuilder.AddInput(&builder.TxInput{ UnlockTarget: f.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address), @@ -252,7 +262,7 @@ func (f *faucet) createFaucetTransactionNoManaHandling(receiveAddr iotago.Addres }, }) txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("Faucet funds"), Data: []byte("to addr" + receiveAddr.String())}) - txBuilder.SetCreationSlot(f.clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now())) + txBuilder.SetCreationSlot(currentSlot) return txBuilder, remainderIndex, nil } diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index ac010a06e..9f2a21d0b 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -63,7 +63,6 @@ type AccountWallet struct { latestUsedIndex uint64 client *models.WebClient - api iotago.API optsClientBindAddress string optsAccountStatesFile string @@ -80,7 +79,6 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { optsRequestTicker: time.Second * 5, }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) - w.api = w.client.CurrentAPI() w.faucet = newFaucet(w.client, w.optsFaucetParams) w.accountsAliases[FaucetAccountAlias] = &models.AccountData{ Alias: FaucetAccountAlias, @@ -104,7 +102,7 @@ func (a *AccountWallet) toAccountStateFile() error { accounts = append(accounts, models.AccountStateFromAccountData(acc)) } - stateBytes, err := a.api.Encode(&StateData{ + stateBytes, err := a.client.LatestAPI().Encode(&StateData{ Seed: base58.Encode(a.seed[:]), LastUsedIndex: a.latestUsedIndex, AccountsData: accounts, @@ -131,7 +129,7 @@ func (a *AccountWallet) fromAccountStateFile() error { } var data StateData - _, err = a.api.Decode(walletStateBytes, &data) + _, err = a.client.LatestAPI().Decode(walletStateBytes, &data) if err != nil { return ierrors.Wrap(err, "failed to decode from file") } @@ -267,12 +265,16 @@ func (a *AccountWallet) destroyAccount(alias string) error { } hdWallet := mock.NewHDWallet("", a.seed[:], accData.Index) + issuingTime := time.Now() + issuingSlot := a.client.LatestAPI().TimeProvider().SlotFromTime(issuingTime) + apiForSlot := a.client.APIForSlot(issuingSlot) + // get output from node // From TIP42: Indexers and node plugins shall map the account address of the output derived with Account ID to the regular address -> output mapping table, so that given an Account Address, its most recent unspent account output can be retrieved. // TODO: use correct outputID accountOutput := a.client.GetOutput(accData.OutputID) - txBuilder := builder.NewTransactionBuilder(a.api) + txBuilder := builder.NewTransactionBuilder(apiForSlot) txBuilder.AddInput(&builder.TxInput{ UnlockTarget: a.accountsAliases[alias].Account.ID().ToAddress(), InputID: accData.OutputID, diff --git a/tools/evil-spammer/evilwallet/evilwallet.go b/tools/evil-spammer/evilwallet/evilwallet.go index 35b22cddb..007059cce 100644 --- a/tools/evil-spammer/evilwallet/evilwallet.go +++ b/tools/evil-spammer/evilwallet/evilwallet.go @@ -661,8 +661,11 @@ func (e *EvilWallet) updateOutputBalances(buildOptions *Options) (err error) { func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Outputs[iotago.Output], w *Wallet, congestionResponse *apimodels.CongestionResponse, allotmentStrategy models.AllotmentStrategy, issuerAccountID iotago.AccountID) (tx *iotago.SignedTransaction, err error) { clt := e.Connector().GetClient() + currentTime := time.Now() + targetSlot := clt.LatestAPI().TimeProvider().SlotFromTime(currentTime) + targetAPI := clt.APIForSlot(targetSlot) - txBuilder := builder.NewTransactionBuilder(clt.CurrentAPI()) + txBuilder := builder.NewTransactionBuilder(targetAPI) for _, input := range inputs { txBuilder.AddInput(&builder.TxInput{UnlockTarget: input.Address, InputID: input.OutputID, Input: input.OutputStruct}) @@ -688,7 +691,7 @@ func (e *EvilWallet) makeTransaction(inputs []*models.Output, outputs iotago.Out inputPrivateKey, _ := wallet.KeyPair(index) walletKeys[i] = iotago.AddressKeys{Address: addr, Keys: inputPrivateKey} } - targetSlot := clt.CurrentAPI().TimeProvider().SlotFromTime(time.Now()) + txBuilder.SetCreationSlot(targetSlot) // no allotment strategy if congestionResponse == nil { diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index 35ec8207c..2dd4e0ba1 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -237,7 +237,7 @@ func (c *WebClient) PostBlock(block *iotago.ProtocolBlock) (blockID iotago.Block // PostData sends the given data (payload) by creating a block in the backend. func (c *WebClient) PostData(data []byte) (blkID string, err error) { - blockBuilder := builder.NewBasicBlockBuilder(c.client.CurrentAPI()) + blockBuilder := builder.NewBasicBlockBuilder(c.client.LatestAPI()) blockBuilder.IssuingTime(time.Time{}) blockBuilder.Payload(&iotago.TaggedData{ From 5fa3fe818a595b1286ff5a84a0409df396b58cec Mon Sep 17 00:00:00 2001 From: jkrvivian Date: Tue, 17 Oct 2023 20:35:32 +0800 Subject: [PATCH 82/84] Fetch faucet unspent output via indexer --- tools/evil-spammer/accountwallet/config.go | 19 ++----- tools/evil-spammer/accountwallet/faucet.go | 63 +++++++++++----------- tools/evil-spammer/accountwallet/wallet.go | 20 +++---- tools/evil-spammer/main.go | 1 - tools/evil-spammer/models/connector.go | 5 ++ 5 files changed, 53 insertions(+), 55 deletions(-) diff --git a/tools/evil-spammer/accountwallet/config.go b/tools/evil-spammer/accountwallet/config.go index d0824fe92..a363cb8ad 100644 --- a/tools/evil-spammer/accountwallet/config.go +++ b/tools/evil-spammer/accountwallet/config.go @@ -6,7 +6,6 @@ import ( "github.com/iotaledger/hive.go/ds/types" "github.com/iotaledger/iota-core/tools/evil-spammer/models" - iotago "github.com/iotaledger/iota.go/v4" ) // commands @@ -63,17 +62,11 @@ func AvailableCommands(cmd string) bool { } type Configuration struct { - BindAddress string `json:"bindAddress,omitempty"` - AccountStatesFile string `json:"accountStatesFile,omitempty"` - GenesisSeed string `json:"genesisSeed,omitempty"` - GenesisOutputID string `json:"genesisOutputID,omitempty"` - LastFauctUnspentOutputID string `json:"lastFaucetUnspentOutputID,omitempty"` - BlockIssuerPrivateKey string `json:"blockIssuerPrivateKey,omitempty"` - AccountID string `json:"accountID,omitempty"` -} - -func (c *Configuration) Update(latestFaucetOutput iotago.OutputID) { - c.LastFauctUnspentOutputID = latestFaucetOutput.ToHex() + BindAddress string `json:"bindAddress,omitempty"` + AccountStatesFile string `json:"accountStatesFile,omitempty"` + GenesisSeed string `json:"genesisSeed,omitempty"` + BlockIssuerPrivateKey string `json:"blockIssuerPrivateKey,omitempty"` + AccountID string `json:"accountID,omitempty"` } var accountConfigFile = "config.json" @@ -82,9 +75,7 @@ var ( dockerAccountConfigJSON = `{ "bindAddress": "http://localhost:8080", "accountStatesFile": "wallet.dat", - "lastFaucetUnspentOutputID": "0x2ee87e6c33a99118c381310b3a2df78234837fdfd3aac4bcde0c32456eaff349000000000000", "genesisSeed": "7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih", - "genesisOutputID": "0x2ee87e6c33a99118c381310b3a2df78234837fdfd3aac4bcde0c32456eaff349000000000000", "blockIssuerPrivateKey": "db39d2fde6301d313b108dc9db1ee724d0f405f6fde966bd776365bc5f4a5fb31e4b21eb51dcddf65c20db1065e1f1514658b23a3ddbf48d30c0efc926a9a648", "accountID": "0x6aee704f25558e8aa7630fed0121da53074188abc423b3c5810f80be4936eb6e"}` ) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 570d86929..ed3af7089 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -123,11 +123,9 @@ func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler. } type faucetParams struct { - latestUsedOutputID string - faucetPrivateKey string - faucetAccountID string - genesisSeed string - genesisOutputID string + faucetPrivateKey string + faucetAccountID string + genesisSeed string } type faucet struct { @@ -140,33 +138,39 @@ type faucet struct { sync.Mutex } -func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { - //get Faucet output and amount - var faucetAmount iotago.BaseToken +func newFaucet(clt models.Client, faucetParams *faucetParams) (*faucet, error) { + genesisSeed, err := base58.Decode(faucetParams.genesisSeed) + if err != nil { + fmt.Printf("failed to decode base58 seed, using the default one: %v", err) + } + faucetAddr := mock.NewHDWallet("", genesisSeed, 0).Address(iotago.AddressEd25519) + + indexer, err := clt.Indexer() + if err != nil { + panic(ierrors.Wrap(err, "failed to get indexer")) + } - faucetUnspentOutputID, err := iotago.OutputIDFromHexString(faucetParams.latestUsedOutputID) + results, err := indexer.Outputs(context.Background(), &apimodels.BasicOutputsQuery{ + AddressBech32: faucetAddr.Bech32(iotago.PrefixTestnet), + }) if err != nil { - log.Warnf("Cannot parse faucet output id from config: %v", err) + return nil, ierrors.Wrap(err, "failed to prepare faucet unspent outputs indexer request") } - faucetOutput := clt.GetOutput(faucetUnspentOutputID) - if faucetOutput != nil { - faucetAmount = faucetOutput.BaseTokenAmount() - } else { - // use the genesis output ID instead, if we relaunch the docker network - faucetUnspentOutputID, err = iotago.OutputIDFromHexString(faucetParams.genesisOutputID) + var ( + faucetUnspentOutput iotago.Output + faucetUnspentOutputID iotago.OutputID + faucetAmount iotago.BaseToken + ) + for results.Next() { + unspents, err := results.Outputs(context.TODO()) if err != nil { - panic("cannot parse genesis output id, please update config file with genesis OutputID created in the snapshot") - } - faucetOutput = clt.GetOutput(faucetUnspentOutputID) - if faucetOutput == nil { - panic("cannot find faucet output") + return nil, ierrors.Wrap(err, "failed to get faucet unspent outputs") } - faucetAmount = faucetOutput.BaseTokenAmount() - } - genesisSeed, err := base58.Decode(faucetParams.genesisSeed) - if err != nil { - fmt.Printf("failed to decode base58 seed, using the default one: %v", err) + + faucetUnspentOutput = unspents[0] + faucetAmount = faucetUnspentOutput.BaseTokenAmount() + faucetUnspentOutputID = lo.Return1(results.Response.Items.OutputIDs())[0] } f := &faucet{ @@ -175,16 +179,15 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) *faucet { genesisHdWallet: mock.NewHDWallet("", genesisSeed, 0), } - f.genesisHdWallet.Address() f.unspentOutput = &models.Output{ - Address: f.genesisHdWallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address), + Address: faucetAddr.(*iotago.Ed25519Address), Index: 0, OutputID: faucetUnspentOutputID, Balance: faucetAmount, - OutputStruct: faucetOutput, + OutputStruct: faucetUnspentOutput, } - return f + return f, nil } func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken, rmc iotago.Mana) (*iotago.SignedTransaction, error) { diff --git a/tools/evil-spammer/accountwallet/wallet.go b/tools/evil-spammer/accountwallet/wallet.go index ac010a06e..3b255beb5 100644 --- a/tools/evil-spammer/accountwallet/wallet.go +++ b/tools/evil-spammer/accountwallet/wallet.go @@ -31,11 +31,9 @@ func Run(config *Configuration) (*AccountWallet, error) { } opts = append(opts, WithFaucetAccountParams(&faucetParams{ - latestUsedOutputID: config.LastFauctUnspentOutputID, - genesisSeed: config.GenesisSeed, - faucetPrivateKey: config.BlockIssuerPrivateKey, - faucetAccountID: config.AccountID, - genesisOutputID: config.GenesisOutputID, + genesisSeed: config.GenesisSeed, + faucetPrivateKey: config.BlockIssuerPrivateKey, + faucetAccountID: config.AccountID, })) wallet := NewAccountWallet(opts...) @@ -81,7 +79,13 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { }, opts, func(w *AccountWallet) { w.client = models.NewWebClient(w.optsClientBindAddress) w.api = w.client.CurrentAPI() - w.faucet = newFaucet(w.client, w.optsFaucetParams) + + faucet, err := newFaucet(w.client, w.optsFaucetParams) + if err != nil { + panic(ierrors.Wrap(err, "failed to create faucet")) + } + + w.faucet = faucet w.accountsAliases[FaucetAccountAlias] = &models.AccountData{ Alias: FaucetAccountAlias, Status: models.AccountReady, @@ -92,10 +96,6 @@ func NewAccountWallet(opts ...options.Option[AccountWallet]) *AccountWallet { }) } -func (a *AccountWallet) LastFaucetUnspentOutputID() iotago.OutputID { - return a.faucet.unspentOutput.OutputID -} - // toAccountStateFile write account states to file. func (a *AccountWallet) toAccountStateFile() error { accounts := make([]*models.AccountState, 0) diff --git a/tools/evil-spammer/main.go b/tools/evil-spammer/main.go index 660a2f62a..3306fe387 100644 --- a/tools/evil-spammer/main.go +++ b/tools/evil-spammer/main.go @@ -45,7 +45,6 @@ func main() { if err != nil { log.Errorf("Error while saving wallet state: %v", err) } - config.Update(accWallet.LastFaucetUnspentOutputID()) accountwallet.SaveConfiguration(config) }() diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index 35ec8207c..f5f108599 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -160,6 +160,7 @@ func (c *WebClients) RemoveClient(url string) { type Client interface { Client() *nodeclient.Client + Indexer() (nodeclient.IndexerClient, error) // URL returns a client API url. URL() (cltID string) // PostBlock sends a block to the Tangle via a given client. @@ -192,6 +193,10 @@ func (c *WebClient) Client() *nodeclient.Client { return c.client } +func (c *WebClient) Indexer() (nodeclient.IndexerClient, error) { + return c.client.Indexer(context.Background()) +} + func (c *WebClient) APIForVersion(version iotago.Version) (iotago.API, error) { return c.client.APIForVersion(version) } From 262a131f802ec94c1d63a4cd579b128040b8242a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 17 Oct 2023 14:59:16 +0200 Subject: [PATCH 83/84] Refactor, wrap getting faucet output --- tools/evil-spammer/accountwallet/faucet.go | 43 +++++++++++++--------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/tools/evil-spammer/accountwallet/faucet.go b/tools/evil-spammer/accountwallet/faucet.go index 35c0ccbe1..3a6948142 100644 --- a/tools/evil-spammer/accountwallet/faucet.go +++ b/tools/evil-spammer/accountwallet/faucet.go @@ -150,6 +150,29 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) (*faucet, error) { } faucetAddr := mock.NewHDWallet("", genesisSeed, 0).Address(iotago.AddressEd25519) + f := &faucet{ + clt: clt, + account: blockhandler.AccountFromParams(faucetParams.faucetAccountID, faucetParams.faucetPrivateKey), + genesisHdWallet: mock.NewHDWallet("", genesisSeed, 0), + } + + faucetUnspentOutput, faucetUnspentOutputID, faucetAmount, err := f.getGenesisOutputFromIndexer(clt, faucetAddr) + if err != nil { + return nil, ierrors.Wrap(err, "failed to get faucet output from indexer") + } + + f.unspentOutput = &models.Output{ + Address: faucetAddr.(*iotago.Ed25519Address), + Index: 0, + OutputID: faucetUnspentOutputID, + Balance: faucetAmount, + OutputStruct: faucetUnspentOutput, + } + + return f, nil +} + +func (f *faucet) getGenesisOutputFromIndexer(clt models.Client, faucetAddr iotago.DirectUnlockableAddress) (iotago.Output, iotago.OutputID, iotago.BaseToken, error) { indexer, err := clt.Indexer() if err != nil { panic(ierrors.Wrap(err, "failed to get indexer")) @@ -159,7 +182,7 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) (*faucet, error) { AddressBech32: faucetAddr.Bech32(iotago.PrefixTestnet), }) if err != nil { - return nil, ierrors.Wrap(err, "failed to prepare faucet unspent outputs indexer request") + return nil, iotago.EmptyOutputID, 0, ierrors.Wrap(err, "failed to prepare faucet unspent outputs indexer request") } var ( @@ -170,7 +193,7 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) (*faucet, error) { for results.Next() { unspents, err := results.Outputs(context.TODO()) if err != nil { - return nil, ierrors.Wrap(err, "failed to get faucet unspent outputs") + return nil, iotago.EmptyOutputID, 0, ierrors.Wrap(err, "failed to get faucet unspent outputs") } faucetUnspentOutput = unspents[0] @@ -178,21 +201,7 @@ func newFaucet(clt models.Client, faucetParams *faucetParams) (*faucet, error) { faucetUnspentOutputID = lo.Return1(results.Response.Items.OutputIDs())[0] } - f := &faucet{ - clt: clt, - account: blockhandler.AccountFromParams(faucetParams.faucetAccountID, faucetParams.faucetPrivateKey), - genesisHdWallet: mock.NewHDWallet("", genesisSeed, 0), - } - - f.unspentOutput = &models.Output{ - Address: faucetAddr.(*iotago.Ed25519Address), - Index: 0, - OutputID: faucetUnspentOutputID, - Balance: faucetAmount, - OutputStruct: faucetUnspentOutput, - } - - return f, nil + return faucetUnspentOutput, faucetUnspentOutputID, faucetAmount, nil } func (f *faucet) prepareFaucetRequest(receiveAddr iotago.Address, amount iotago.BaseToken, rmc iotago.Mana) (*iotago.SignedTransaction, error) { From 006dfb8a778601cf38155dcd3717aa12341e5fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daria=20Dziuba=C5=82towska?= Date: Tue, 17 Oct 2023 16:30:29 +0200 Subject: [PATCH 84/84] Simplify return --- tools/evil-spammer/models/connector.go | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tools/evil-spammer/models/connector.go b/tools/evil-spammer/models/connector.go index fb3e2a3b0..c15462ca0 100644 --- a/tools/evil-spammer/models/connector.go +++ b/tools/evil-spammer/models/connector.go @@ -232,12 +232,7 @@ func NewWebClient(url string, opts ...options.Option[WebClient]) *WebClient { } func (c *WebClient) PostBlock(block *iotago.ProtocolBlock) (blockID iotago.BlockID, err error) { - id, err := c.client.SubmitBlock(context.Background(), block) - if err != nil { - return - } - - return id, nil + return c.client.SubmitBlock(context.Background(), block) } // PostData sends the given data (payload) by creating a block in the backend. @@ -316,10 +311,5 @@ func (c *WebClient) GetBlockIssuance() (resp *apimodels.IssuanceBlockHeaderRespo } func (c *WebClient) GetCongestion(accountID iotago.AccountID) (resp *apimodels.CongestionResponse, err error) { - resp, err = c.client.Congestion(context.Background(), accountID) - if err != nil { - return - } - - return + return c.client.Congestion(context.Background(), accountID) }