Skip to content

Commit

Permalink
Merge pull request #21 from gohornet/add-spammer
Browse files Browse the repository at this point in the history
Add spammer plugin
  • Loading branch information
muXxer authored Dec 15, 2019
2 parents 156f7de + 7263afc commit c1384c5
Show file tree
Hide file tree
Showing 11 changed files with 447 additions and 4 deletions.
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,42 @@

All notable changes to this project will be documented in this file.

## [0.2.2] - 15.12.2019

### Added

- TangleMonitor Plugin
- Spammer Plugin
- More detailed log messages at shutdown

### Fixed

- Do not expose passwords from config file at startup
- Duplicated neighbors

### Config file changes

New settings:
```json
"monitor": {
"tanglemonitorpath": "tanglemonitor/frontend",
"domain": "",
"host": "127.0.0.1"
},
"spammer": {
"address": "HORNET99INTEGRATED99SPAMMER999999999999999999999999999999999999999999999999999999",
"depth": 3,
"message": "Spamming with HORNET tipselect",
"tag": "HORNET99INTEGRATED99SPAMMER",
"tpsratelimit": 0.1,
"workers": 1
},
"zmq": {
"host": "127.0.0.1",
}
```


## [0.2.1] - 13.12.2019

### Added
Expand Down
52 changes: 51 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,56 @@ This way, HORNET is easier to install and runs on low-end devices.
- Download the latest HORNET snapshot from [dbfiles.iota.org](https://dbfiles.iota.org/mainnet/hornet/latest-export.gz.bin)
- Run HORNET: `./hornet -c config`

---

### Available plugins

#### TangleMonitor

- Download the latest TangleMonitor source code
```bash
git clone https://github.com/unioproject/tanglemonitor.git
```
- Modify the `config.json` to fit your needs
- `"tanglemonitorpath"` has to point to the frontend folder of the TangleMonitor source code
- Add `"Monitor"` to `"enableplugins"`
- Change `"host"` to `"0.0.0.0"` if you want to access TangleMonitor from anywhere
```json
"monitor": {
"tanglemonitorpath": "tanglemonitor/frontend",
"domain": "",
"host": "127.0.0.1"
},
"node": {
"disableplugins": [],
"enableplugins": ["Monitor"],
"loglevel": 3
},
```

#### Spammer

- Modify the `config.json` to fit your needs
- Change `"address"`, `"message"`, `"tag"` and `"tpsratelimit"`
- Add `"Spammer"` to `"enableplugins"`
```json
"spammer": {
"address": "HORNET99INTEGRATED99SPAMMER999999999999999999999999999999999999999999999999999999",
"depth": 3,
"message": "Spamming with HORNET tipselect",
"tag": "HORNET99INTEGRATED99SPAMMER",
"tpsratelimit": 0.1,
"workers": 1
},
"node": {
"disableplugins": [],
"enableplugins": ["Spammer"],
"loglevel": 3
},
```

---

### Docker

See [Docker](DOCKER.md)
- See [Docker](DOCKER.md)
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@
"protocol": {
"mwm": 14
},
"spammer": {
"address": "HORNET99INTEGRATED99SPAMMER999999999999999999999999999999999999999999999999999999",
"depth": 3,
"message": "Spamming with HORNET tipselect",
"tag": "HORNET99INTEGRATED99SPAMMER",
"tpsratelimit": 0.1,
"workers": 1
},
"tipsel": {
"belowmaxdepthtransactionlimit": 20000,
"maxdepth": 15
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
github.com/gorilla/websocket v1.4.1
github.com/iotaledger/goshimmer v0.0.0-20191125182838-26e99d88bddb
github.com/iotaledger/hive.go v0.0.0-20191206213336-9f6cd83f0501
github.com/iotaledger/hive.go v0.0.0-20191215095341-f16d8a5ea757
github.com/iotaledger/iota.go v1.0.0-beta.12
github.com/labstack/echo v3.3.10+incompatible
github.com/mitchellh/mapstructure v1.1.2
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ github.com/iotaledger/goshimmer v0.0.0-20191125182838-26e99d88bddb/go.mod h1:Mpv
github.com/iotaledger/hive.go v0.0.0-20191113184748-b545de9170d9/go.mod h1:Ks2y/bEyfvb7nUA7l69a+8Epsv16UlGev0BvxggHius=
github.com/iotaledger/hive.go v0.0.0-20191206213336-9f6cd83f0501 h1:m9bX1o4r269lC8PiLnvwnJVLM9SQIBaSYZCdwJgo0tU=
github.com/iotaledger/hive.go v0.0.0-20191206213336-9f6cd83f0501/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20=
github.com/iotaledger/hive.go v0.0.0-20191208004610-567900b261bd h1:hh8iusLOBylWNHeJNiZv6atCbO7vzjCLlg53pNAMkFk=
github.com/iotaledger/hive.go v0.0.0-20191215095341-f16d8a5ea757 h1:D9zQRp4dqPErNbJHa4uX5UREFlDs9WOq8j5yJo+/Szw=
github.com/iotaledger/hive.go v0.0.0-20191215095341-f16d8a5ea757/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20=
github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
github.com/iotaledger/iota.go v1.0.0-beta.12 h1:p6Pk3N8tmb6Kaj8F45O5XVJQfH5qQYqpvUnXiSMrtiE=
github.com/iotaledger/iota.go v1.0.0-beta.12/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/gohornet/hornet/plugins/monitor"
"github.com/gohornet/hornet/plugins/snapshot"
"github.com/gohornet/hornet/plugins/spa"
"github.com/gohornet/hornet/plugins/spammer"
"github.com/gohornet/hornet/plugins/tangle"
"github.com/gohornet/hornet/plugins/tipselection"
"github.com/gohornet/hornet/plugins/webapi"
Expand All @@ -37,5 +38,6 @@ func main() {
spa.PLUGIN,
zeromq.PLUGIN,
monitor.PLUGIN,
spammer.PLUGIN,
)
}
7 changes: 5 additions & 2 deletions plugins/cli/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

var (
// AppVersion version number
AppVersion = "0.2.1"
AppVersion = "0.2.2"

// AppName app code name
AppName = "HORNET"
Expand Down Expand Up @@ -58,7 +58,10 @@ func configure(ctx *node.Plugin) {
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝
` + "\n\n")

parameter.FetchConfig(true)
ignoreSettingsAtPrint := []string{}
ignoreSettingsAtPrint = append(ignoreSettingsAtPrint, "api.auth.password")
ignoreSettingsAtPrint = append(ignoreSettingsAtPrint, "dashboard.basic_auth.password")
parameter.FetchConfig(true, ignoreSettingsAtPrint)
parseParameters()
ctx.Node.Logger.Infof("Using profile '%s'", profile.GetProfile().Name)
ctx.Node.Logger.Info("Loading plugins ...")
Expand Down
112 changes: 112 additions & 0 deletions plugins/spammer/bundle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package spammer

import (
"fmt"
"time"

"github.com/iotaledger/iota.go/bundle"
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/converter"
"github.com/iotaledger/iota.go/kerl"
"github.com/iotaledger/iota.go/trinary"
)

func integerToAscii(number int) string {
alphabet := "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"

result := ""
for index := 0; index < 7; index++ {
pos := number % 27
number /= 27
result = string(alphabet[pos]) + result
}
return result
}

// We don't need to care about the M-Bug in the spammer => much faster without
func finalizeInsecure(bundle bundle.Bundle) (bundle.Bundle, error) {
var valueTrits = make([]trinary.Trits, len(bundle))
var timestampTrits = make([]trinary.Trits, len(bundle))
var currentIndexTrits = make([]trinary.Trits, len(bundle))
var obsoleteTagTrits = make([]trinary.Trits, len(bundle))
var lastIndexTrits = trinary.PadTrits(trinary.IntToTrits(int64(bundle[0].LastIndex)), 27)

for i := range bundle {
valueTrits[i] = trinary.PadTrits(trinary.IntToTrits(bundle[i].Value), 81)
timestampTrits[i] = trinary.PadTrits(trinary.IntToTrits(int64(bundle[i].Timestamp)), 27)
currentIndexTrits[i] = trinary.PadTrits(trinary.IntToTrits(int64(bundle[i].CurrentIndex)), 27)
obsoleteTagTrits[i] = trinary.PadTrits(trinary.MustTrytesToTrits(bundle[i].ObsoleteTag), 81)
}

var bundleHash trinary.Hash

k := kerl.NewKerl()

for i := 0; i < len(bundle); i++ {
relevantTritsForBundleHash := trinary.MustTrytesToTrits(
bundle[i].Address +
trinary.MustTritsToTrytes(valueTrits[i]) +
trinary.MustTritsToTrytes(obsoleteTagTrits[i]) +
trinary.MustTritsToTrytes(timestampTrits[i]) +
trinary.MustTritsToTrytes(currentIndexTrits[i]) +
trinary.MustTritsToTrytes(lastIndexTrits),
)
k.Absorb(relevantTritsForBundleHash)
}

bundleHashTrits, err := k.Squeeze(consts.HashTrinarySize)
if err != nil {
return nil, err
}
bundleHash = trinary.MustTritsToTrytes(bundleHashTrits)

// set the computed bundle hash on each tx in the bundle
for i := range bundle {
tx := &bundle[i]
tx.Bundle = bundleHash
}

return bundle, nil
}

func createBundle(address string, msg string, tagSubstring string, txCount int, additionalMesssage ...string) (bundle.Bundle, error) {

tag, err := trinary.NewTrytes(tagSubstring + integerToAscii(txCount))
if err != nil {
return nil, fmt.Errorf("NewTrytes: %v", err.Error())
}
now := time.Now()

messageString := msg + fmt.Sprintf("\nCount: %06d", txCount)
messageString += fmt.Sprintf("\nTimestamp: %s", now.Format(time.RFC3339))
if len(additionalMesssage) > 0 {
messageString = fmt.Sprintf("%v\n%v", messageString, additionalMesssage[0])
}

message, err := converter.ASCIIToTrytes(messageString)
if err != nil {
return nil, fmt.Errorf("ASCIIToTrytes: %v", err.Error())
}

timestamp := uint64(now.UnixNano() / int64(time.Millisecond))

var b bundle.Bundle

outEntry := bundle.BundleEntry{
Address: address,
Value: 0,
Tag: tag,
Timestamp: timestamp,
Length: uint64(1),
SignatureMessageFragments: []trinary.Trytes{trinary.Pad(message, consts.SignatureMessageFragmentSizeInTrytes)},
}
b = bundle.AddEntry(b, outEntry)

// finalize bundle by adding the bundle hash
b, err = finalizeInsecure(b)
if err != nil {
return nil, fmt.Errorf("Bundle.Finalize: %v", err.Error())
}

return b, nil
}
12 changes: 12 additions & 0 deletions plugins/spammer/parameters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package spammer

import flag "github.com/spf13/pflag"

func init() {
flag.String("spammer.address", "HORNET99INTEGRATED99SPAMMER999999999999999999999999999999999999999999999999999999", "Tx Address")
flag.String("spammer.message", "Spamming with HORNET tipselect", "Message of the Tx")
flag.String("spammer.tag", "HORNET99INTEGRATED99SPAMMER", "Tag of the Tx")
flag.Uint("spammer.depth", 3, "Depth of the random walker")
flag.Float64("spammer.tpsRateLimit", 0.10, "Rate limit for the spam (0 = no limit)")
flag.Uint("spammer.workers", 1, "How many spammers should run in parallel")
}
92 changes: 92 additions & 0 deletions plugins/spammer/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package spammer

import (
"runtime"
"time"

"github.com/gohornet/hornet/packages/logger"
"github.com/gohornet/hornet/packages/model/tangle"
"github.com/gohornet/hornet/packages/node"
"github.com/gohornet/hornet/packages/shutdown"
"github.com/gohornet/hornet/packages/timeutil"
daemon "github.com/iotaledger/hive.go/daemon/ordered"
"github.com/iotaledger/hive.go/parameter"
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/trinary"
)

var (
PLUGIN = node.NewPlugin("Spammer", node.Disabled, configure, run)
log = logger.NewLogger("Spammer")

address string
message string
tagSubstring string
depth uint
rateLimit float64
mwm int
spammerWorkerCount int
)

func configure(plugin *node.Plugin) {

address = trinary.Pad(parameter.NodeConfig.GetString("spammer.address"), consts.AddressTrinarySize/3)[:consts.AddressTrinarySize/3]
message = parameter.NodeConfig.GetString("spammer.message")
tagSubstring = trinary.Pad(parameter.NodeConfig.GetString("spammer.tag"), consts.TagTrinarySize/3)[:consts.TagTrinarySize/3]
depth = parameter.NodeConfig.GetUint("spammer.depth")
rateLimit = parameter.NodeConfig.GetFloat64("spammer.tpsRateLimit")
mwm = parameter.NodeConfig.GetInt("protocol.mwm")
spammerWorkerCount = int(parameter.NodeConfig.GetUint("spammer.workers"))

if spammerWorkerCount >= runtime.NumCPU() {
spammerWorkerCount = runtime.NumCPU() - 1
}
if spammerWorkerCount < 1 {
spammerWorkerCount = 1
}

if int64(rateLimit) != 0 {
rateLimitChannelSize := int64(rateLimit) * 2
if rateLimitChannelSize < 2 {
rateLimitChannelSize = 2
}
rateLimitChannel = make(chan struct{}, rateLimitChannelSize)

// create a background worker that fills rateLimitChannel every second
daemon.BackgroundWorker("Spammer rate limit channel", func(shutdownSignal <-chan struct{}) {
timeutil.Ticker(func() {
select {
case rateLimitChannel <- struct{}{}:
default:
// Channel full
}
}, time.Duration(int64(float64(time.Second)/rateLimit)), shutdownSignal)
}, shutdown.ShutdownPrioritySpammer)
}

if len(tagSubstring) > 20 {
tagSubstring = string([]rune(tagSubstring)[:20])
}
}

func run(plugin *node.Plugin) {

for i := 0; i < spammerWorkerCount; i++ {
daemon.BackgroundWorker("Spammer", func(shutdownSignal <-chan struct{}) {
log.Infof("Starting Spammer %d... done", i)

for {
select {
case <-shutdownSignal:
log.Infof("Stopping Spammer %d...", i)
log.Infof("Stopping Spammer %d... done", i)
return
default:
if tangle.IsNodeSynced() {
doSpam(shutdownSignal)
}
}
}
}, shutdown.ShutdownPrioritySpammer)
}
}
Loading

0 comments on commit c1384c5

Please sign in to comment.