Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Blowball spam and fix nil CongestionResponse #2

Merged
merged 2 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions accountwallet/faucet.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func (a *AccountWallet) RequestFaucetFunds(clt models.Client, receiveAddr iotago
}, nil
}

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)
func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload, issuer blockhandler.Account, congestionResp *apimodels.CongestionResponse, issuerResp *apimodels.IssuanceBlockHeaderResponse, version iotago.Version, strongParents ...iotago.BlockID) (iotago.BlockID, error) {
signedBlock, err := a.CreateBlock(payload, issuer, congestionResp, issuerResp, version, strongParents...)
if err != nil {
log.Errorf("failed to create block: %s", err)

Expand All @@ -86,10 +86,17 @@ func (a *AccountWallet) PostWithBlock(clt models.Client, payload iotago.Payload,
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) {
func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler.Account, congestionResp *apimodels.CongestionResponse, issuerResp *apimodels.IssuanceBlockHeaderResponse, version iotago.Version, strongParents ...iotago.BlockID) (*iotago.ProtocolBlock, error) {
issuingTime := time.Now()
issuingSlot := a.client.LatestAPI().TimeProvider().SlotFromTime(issuingTime)
apiForSlot := a.client.APIForSlot(issuingSlot)
if congestionResp == nil {
var err error
congestionResp, err = a.client.GetCongestion(issuer.ID())
if err != nil {
return nil, ierrors.Wrap(err, "failed to get congestion data")
}
}

blockBuilder := builder.NewBasicBlockBuilder(apiForSlot)

Expand All @@ -102,7 +109,7 @@ func (a *AccountWallet) CreateBlock(payload iotago.Payload, issuer blockhandler.
blockBuilder.SlotCommitmentID(commitmentID)
blockBuilder.LatestFinalizedSlot(issuerResp.LatestFinalizedSlot)
blockBuilder.IssuingTime(time.Now())
blockBuilder.StrongParents(issuerResp.StrongParents)
blockBuilder.StrongParents(append(issuerResp.StrongParents, strongParents...))
blockBuilder.WeakParents(issuerResp.WeakParents)
blockBuilder.ShallowLikeParents(issuerResp.ShallowLikeParents)

Expand Down
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var (
DeepSpam: false,
EnableRateSetter: false,
AccountAlias: accountwallet.FaucetAccountAlias,
BlowballSize: 30,
}

accountsSubcommandsFlags []accountwallet.AccountSubcommands
Expand Down
31 changes: 29 additions & 2 deletions evilwallet/evilwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,40 @@ func (e *EvilWallet) GetAccount(alias string) (blockhandler.Account, error) {
return account.Account, nil
}

func (e *EvilWallet) CreateBlock(clt models.Client, payload iotago.Payload, congestionResp *apimodels.CongestionResponse, issuer blockhandler.Account, strongParents ...iotago.BlockID) (*iotago.ProtocolBlock, error) {
var congestionSlot iotago.SlotIndex
version := clt.CommittedAPI().Version()
if congestionResp != nil {
congestionSlot = congestionResp.Slot
version = clt.APIForSlot(congestionSlot).Version()
}

issuerResp, err := clt.GetBlockIssuance(congestionSlot)
if err != nil {
return nil, ierrors.Wrap(err, "failed to get block issuance data")
}

block, err := e.accWallet.CreateBlock(payload, issuer, congestionResp, issuerResp, version, strongParents...)
if err != nil {
return nil, err
}

return block, nil
}

func (e *EvilWallet) PrepareAndPostBlock(clt models.Client, payload iotago.Payload, congestionResp *apimodels.CongestionResponse, issuer blockhandler.Account) (iotago.BlockID, error) {
issuerResp, err := clt.GetBlockIssuance(congestionResp.Slot)
var congestionSlot iotago.SlotIndex
version := clt.CommittedAPI().Version()
if congestionResp != nil {
congestionSlot = congestionResp.Slot
version = clt.APIForSlot(congestionSlot).Version()
}

issuerResp, err := clt.GetBlockIssuance(congestionSlot)
if err != nil {
return iotago.EmptyBlockID, ierrors.Wrap(err, "failed to get block issuance data")
}

version := clt.APIForSlot(congestionResp.Slot).Version()
blockID, err := e.accWallet.PostWithBlock(clt, payload, issuer, congestionResp, issuerResp, version)
if err != nil {
return iotago.EmptyBlockID, err
Expand Down
2 changes: 1 addition & 1 deletion interactive/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const (
)

var (
scenarios = []string{spammer.TypeBlock, spammer.TypeTx, spammer.TypeDs, "conflict-circle", "guava", "orange", "mango", "pear", "lemon", "banana", "kiwi", "peace"}
scenarios = []string{spammer.TypeBlock, spammer.TypeTx, spammer.TypeDs, spammer.TypeBlowball, "conflict-circle", "guava", "orange", "mango", "pear", "lemon", "banana", "kiwi", "peace"}
confirms = []string{AnswerEnable, AnswerDisable}
outputNumbers = []string{"100", "1000", "5000", "cancel"}
timeUnits = []string{mpm, mps}
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func main() {
case ScriptAccounts:
accountsSubcommands(accWallet, accountsSubcommandsFlags)
default:
log.Warnf("Unknown parameter for script, possible values: interactive, basic, accounts, quick")
log.Warnf("Unknown parameter for script, possible values: interactive, spammer, accounts")
}
}

Expand Down
12 changes: 12 additions & 0 deletions models/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ type Client interface {
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)
// GetBlockConfirmationState returns the AcceptanceState of a given block ID.
GetBlockConfirmationState(blkID iotago.BlockID) string
// GetBlockState returns the AcceptanceState of a given transaction ID.
GetBlockState(txID iotago.TransactionID) (resp *apimodels.BlockMetadataResponse, err error)
// GetOutput gets the output of a given outputID.
Expand Down Expand Up @@ -296,6 +298,16 @@ func (c *WebClient) GetOutput(outputID iotago.OutputID) iotago.Output {
return res
}

// GetBlockConfirmationState returns the AcceptanceState of a given block ID.
func (c *WebClient) GetBlockConfirmationState(blkID iotago.BlockID) string {
resp, err := c.client.BlockMetadataByBlockID(context.Background(), blkID)
if err != nil {
return ""
}

return resp.BlockState
}

// GetBlockState returns the AcceptanceState of a given transaction ID.
func (c *WebClient) GetBlockState(txID iotago.TransactionID) (*apimodels.BlockMetadataResponse, error) {
return c.client.TransactionIncludedBlockMetadata(context.Background(), txID)
Expand Down
2 changes: 1 addition & 1 deletion parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func parseOptionFlagSet(flagSet *flag.FlagSet, args ...[]string) {
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")
" 'tx' - transaction, 'ds' - double spends spammers, 'nds' - n-spends spammer, 'custom' - spams with provided scenario, 'bb' - blowball")
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.")
Expand Down
1 change: 1 addition & 0 deletions programs/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ type CustomSpamParams struct {
DeepSpam bool
EnableRateSetter bool
AccountAlias string
BlowballSize int
}
54 changes: 45 additions & 9 deletions programs/spammers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ func CustomSpam(params *CustomSpamParams, accWallet *accountwallet.AccountWallet
for i, sType := range params.SpamTypes {
log.Infof("Start spamming with rate: %d, time unit: %s, and spamming type: %s.", params.Rates[i], params.TimeUnit.String(), sType)

numOfBigWallets := spammer.BigWalletsNeeded(params.Rates[i], params.TimeUnit, params.Durations[i])
fmt.Println("numOfBigWallets: ", numOfBigWallets)
success := w.RequestFreshBigFaucetWallets(numOfBigWallets)
if !success {
log.Errorf("Failed to request faucet wallet")
if sType != spammer.TypeBlock && sType != spammer.TypeBlowball {
numOfBigWallets := spammer.BigWalletsNeeded(params.Rates[i], params.TimeUnit, params.Durations[i])
fmt.Println("numOfBigWallets: ", numOfBigWallets)
success := w.RequestFreshBigFaucetWallets(numOfBigWallets)
if !success {
log.Errorf("Failed to request faucet wallet")

return
}
return
}

unspentOutputsLeft := w.UnspentOutputsLeft(evilwallet.Fresh)
log.Debugf("Prepared %d unspent outputs for spamming.", unspentOutputsLeft)
unspentOutputsLeft := w.UnspentOutputsLeft(evilwallet.Fresh)
log.Debugf("Prepared %d unspent outputs for spamming.", unspentOutputsLeft)
}

switch sType {
case spammer.TypeBlock:
Expand All @@ -43,6 +45,17 @@ func CustomSpam(params *CustomSpamParams, accWallet *accountwallet.AccountWallet
}
s.Spam()
}(i)
case spammer.TypeBlowball:
wg.Add(1)
go func(i int) {
defer wg.Done()

s := SpamBlowball(w, params.Rates[i], params.TimeUnit, params.Durations[i], params.BlowballSize, params.EnableRateSetter, params.AccountAlias)
if s == nil {
return
}
s.Spam()
}(i)
case spammer.TypeTx:
wg.Add(1)
go func(i int) {
Expand Down Expand Up @@ -222,3 +235,26 @@ func SpamAccounts(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Du

return spammer.NewSpammer(options...)
}

func SpamBlowball(w *evilwallet.EvilWallet, rate int, timeUnit, duration time.Duration, blowballSize int, enableRateSetter bool, accountAlias string) *spammer.Spammer {
if w.NumOfClient() < 1 {
log.Infof("Warning: At least one client is needed to spam.")
}

// blowball spammer needs at least 40 seconds to finish
if duration < 40*time.Second {
duration = 40 * time.Second
}

options := []spammer.Options{
spammer.WithSpamRate(rate, timeUnit),
spammer.WithSpamDuration(duration),
spammer.WithBlowballSize(blowballSize),
spammer.WithRateSetter(enableRateSetter),
spammer.WithEvilWallet(w),
spammer.WithSpammingFunc(spammer.BlowballSpammingFunction),
spammer.WithAccountAlias(accountAlias),
}

return spammer.NewSpammer(options...)
}
14 changes: 14 additions & 0 deletions spammer/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,25 @@ func WithTimeDelayForDoubleSpend(timeDelay time.Duration) Options {
}
}

// WithBlowballSize provides spammer with options regarding blowball size.
func WithBlowballSize(size int) Options {
return func(s *Spammer) {
if s.SpamDetails == nil {
s.SpamDetails = &SpamDetails{
BlowballSize: size,
}
} else {
s.SpamDetails.BlowballSize = size
}
}
}

// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

type SpamDetails struct {
Rate int
TimeUnit time.Duration
MaxDuration time.Duration
MaxBatchesSent int
BlowballSize int
}
40 changes: 34 additions & 6 deletions spammer/spammer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
TypeDs = "ds"
TypeCustom = "custom"
TypeAccounts = "accounts"
TypeBlowball = "bb"
)

// region Spammer //////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -226,30 +227,55 @@ func (s *Spammer) StopSpamming() {
s.shutdown <- types.Void
}

func (s *Spammer) PrepareAndPostBlock(txData *models.PayloadIssuanceData, issuerAlias string, clt models.Client) {
func (s *Spammer) PrepareBlock(txData *models.PayloadIssuanceData, issuerAlias string, clt models.Client, strongParents ...iotago.BlockID) *iotago.ProtocolBlock {
if txData.Payload == nil {
s.log.Debug(ErrPayloadIsNil)
s.ErrCounter.CountError(ErrPayloadIsNil)

return
return nil
}
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
return nil
}
block, err := s.EvilWallet.CreateBlock(clt, txData.Payload, txData.CongestionResponse, issuerAccount, strongParents...)
if err != nil {
s.log.Debug(ierrors.Wrapf(ErrFailPostBlock, err.Error()))
s.ErrCounter.CountError(ierrors.Wrapf(ErrFailPostBlock, err.Error()))

return nil
}

return block
}

func (s *Spammer) PrepareAndPostBlock(txData *models.PayloadIssuanceData, issuerAlias string, clt models.Client) iotago.BlockID {
if txData.Payload == nil {
s.log.Debug(ErrPayloadIsNil)
s.ErrCounter.CountError(ErrPayloadIsNil)

return iotago.EmptyBlockID
}
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 iotago.EmptyBlockID
}
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()))

return
return iotago.EmptyBlockID
}

if txData.Payload.PayloadType() != iotago.PayloadSignedTransaction {
return
return blockID
}

//nolint:all,forcetypassert
Expand All @@ -260,7 +286,7 @@ func (s *Spammer) PrepareAndPostBlock(txData *models.PayloadIssuanceData, issuer
s.log.Debug(ierrors.Wrapf(ErrTransactionInvalid, err.Error()))
s.ErrCounter.CountError(ierrors.Wrapf(ErrTransactionInvalid, err.Error()))

return
return blockID
}

// reuse outputs
Expand All @@ -275,6 +301,8 @@ func (s *Spammer) PrepareAndPostBlock(txData *models.PayloadIssuanceData, issuer
}
count := s.State.txSent.Add(1)
s.log.Debugf("Last block sent, ID: %s, txCount: %d", blockID.ToHex(), count)

return blockID
}

// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading
Loading