diff --git a/main.go b/main.go index 7e8099a447f7a779398c03b0049175744d8920b0..9b0fc7beca86ba050a95a239f365f11630b5cba6 100644 --- a/main.go +++ b/main.go @@ -7,12 +7,13 @@ import ( "github.com/iotaledger/goshimmer/plugins/cli" "github.com/iotaledger/goshimmer/plugins/gossip" "github.com/iotaledger/goshimmer/plugins/gracefulshutdown" - "github.com/iotaledger/goshimmer/plugins/spammer" "github.com/iotaledger/goshimmer/plugins/statusscreen" + statusscreen_tps "github.com/iotaledger/goshimmer/plugins/statusscreen-tps" "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/goshimmer/plugins/tipselection" "github.com/iotaledger/goshimmer/plugins/webapi" webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi-gtta" + webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi-spammer" ) func main() { @@ -22,12 +23,14 @@ func main() { gossip.PLUGIN, tangle.PLUGIN, analysis.PLUGIN, - statusscreen.PLUGIN, gracefulshutdown.PLUGIN, tipselection.PLUGIN, - spammer.PLUGIN, + + statusscreen.PLUGIN, + statusscreen_tps.PLUGIN, webapi.PLUGIN, webapi_gtta.PLUGIN, + webapi_spammer.PLUGIN, ) } diff --git a/packages/transactionspammer/transactionspammer.go b/packages/transactionspammer/transactionspammer.go new file mode 100644 index 0000000000000000000000000000000000000000..503a0f5af72c6f3120b0749ebb30bf5778ba3cd5 --- /dev/null +++ b/packages/transactionspammer/transactionspammer.go @@ -0,0 +1,83 @@ +package transactionspammer + +import ( + "sync" + "time" + + "github.com/iotaledger/goshimmer/packages/daemon" + "github.com/iotaledger/goshimmer/packages/model/value_transaction" + "github.com/iotaledger/goshimmer/plugins/gossip" + "github.com/iotaledger/goshimmer/plugins/tipselection" +) + +var spamming = false + +var startMutex sync.Mutex + +var shutdownSignal chan int + +func Start(tps int64) { + startMutex.Lock() + + if !spamming { + shutdownSignal = make(chan int, 1) + + func(shutdownSignal chan int) { + daemon.BackgroundWorker(func() { + for { + start := time.Now() + sentCounter := int64(0) + totalSentCounter := int64(0) + + for { + select { + case <-daemon.ShutdownSignal: + return + + case <-shutdownSignal: + return + + default: + sentCounter++ + totalSentCounter++ + + tx := value_transaction.New() + tx.SetValue(totalSentCounter) + tx.SetBranchTransactionHash(tipselection.GetRandomTip()) + tx.SetTrunkTransactionHash(tipselection.GetRandomTip()) + + gossip.Events.ReceiveTransaction.Trigger(tx.MetaTransaction) + + if sentCounter >= tps { + duration := time.Since(start) + if duration < time.Second { + time.Sleep(time.Second - duration) + + start = time.Now() + } + + sentCounter = 0 + } + } + } + } + }) + }(shutdownSignal) + + spamming = true + } + + startMutex.Unlock() +} + +func Stop() { + startMutex.Lock() + + if spamming { + close(shutdownSignal) + + spamming = false + } + + startMutex.Unlock() +} diff --git a/plugins/spammer/spammer.go b/plugins/spammer/spammer.go deleted file mode 100644 index 44985dea31b0032028a941c71b4d621ad8db4b51..0000000000000000000000000000000000000000 --- a/plugins/spammer/spammer.go +++ /dev/null @@ -1,86 +0,0 @@ -package spammer - -import ( - "fmt" - "runtime" - "strconv" - "sync/atomic" - "time" - - "github.com/iotaledger/goshimmer/packages/daemon" - "github.com/iotaledger/goshimmer/packages/events" - "github.com/iotaledger/goshimmer/packages/model/meta_transaction" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/packages/node" - "github.com/iotaledger/goshimmer/plugins/gossip" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/goshimmer/plugins/tipselection" -) - -var PLUGIN = node.NewPlugin("Spammer", configure, run) - -func bToMb(b uint64) uint64 { - return b / 1024 / 1024 -} - -func configure(plugin *node.Plugin) { - tpsCounter := 0 - solidCounter := 0 - var receivedCounter uint64 - - gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(transaction *meta_transaction.MetaTransaction) { - atomic.AddUint64(&receivedCounter, 1) - })) - - go func() { - for { - select { - case <-daemon.ShutdownSignal: - return - - case <-time.After(1 * time.Second): - fmt.Println("RECEIVED", receivedCounter, " / TPS "+strconv.Itoa(tpsCounter)+" / SOLID "+strconv.Itoa(solidCounter), " / TIPS ", tipselection.GetTipsCount()) - fmt.Println(runtime.NumGoroutine()) - - var m runtime.MemStats - runtime.ReadMemStats(&m) - // For info on each, see: https://golang.org/pkg/runtime/#MemStats - fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc)) - fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc)) - fmt.Printf("\tSys = %v MiB", bToMb(m.Sys)) - fmt.Printf("\tNumGC = %v\n", m.NumGC) - - tpsCounter = 0 - } - } - }() - - tangle.Events.TransactionSolid.Attach(events.NewClosure(func(transaction *value_transaction.ValueTransaction) { - solidCounter++ - tpsCounter++ - })) -} - -func run(plugin *node.Plugin) { - daemon.BackgroundWorker(func() { - for { - transactionCount := 100000 - - for i := 0; i < transactionCount; i++ { - select { - case <-daemon.ShutdownSignal: - return - default: - tx := value_transaction.New() - tx.SetValue(int64(i + 1)) - tx.SetBranchTransactionHash(tipselection.GetRandomTip()) - tx.SetTrunkTransactionHash(tipselection.GetRandomTip()) - - gossip.Events.ReceiveTransaction.Trigger(tx.MetaTransaction) - } - } - - //time.Sleep(5 * time.Second) - } - }) -} diff --git a/plugins/statusscreen-tps/plugin.go b/plugins/statusscreen-tps/plugin.go new file mode 100644 index 0000000000000000000000000000000000000000..eabb868f15e786ecea795ceac8173f2984d4a31c --- /dev/null +++ b/plugins/statusscreen-tps/plugin.go @@ -0,0 +1,56 @@ +package statusscreen_tps + +import ( + "strconv" + "sync/atomic" + "time" + + "github.com/iotaledger/goshimmer/packages/daemon" + "github.com/iotaledger/goshimmer/packages/events" + "github.com/iotaledger/goshimmer/packages/model/meta_transaction" + "github.com/iotaledger/goshimmer/packages/model/value_transaction" + "github.com/iotaledger/goshimmer/packages/node" + "github.com/iotaledger/goshimmer/plugins/gossip" + "github.com/iotaledger/goshimmer/plugins/statusscreen" + "github.com/iotaledger/goshimmer/plugins/tangle" +) + +var receivedTpsCounter uint64 + +var solidTpsCounter uint64 + +var receivedTps uint64 + +var solidTps uint64 + +var PLUGIN = node.NewPlugin("Statusscreen TPS", func(plugin *node.Plugin) { + gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(_ *meta_transaction.MetaTransaction) { + atomic.AddUint64(&receivedTpsCounter, 1) + })) + + tangle.Events.TransactionSolid.Attach(events.NewClosure(func(_ *value_transaction.ValueTransaction) { + atomic.AddUint64(&solidTpsCounter, 1) + })) + + statusscreen.AddHeaderInfo(func() (s string, s2 string) { + return "TPS", strconv.FormatUint(atomic.LoadUint64(&receivedTps), 10) + " received / " + strconv.FormatUint(atomic.LoadUint64(&solidTps), 10) + " new" + }) +}, func(plugin *node.Plugin) { + daemon.BackgroundWorker(func() { + ticker := time.NewTicker(time.Second) + + for { + select { + case <-daemon.ShutdownSignal: + return + + case <-ticker.C: + atomic.StoreUint64(&receivedTps, atomic.LoadUint64(&receivedTpsCounter)) + atomic.StoreUint64(&solidTps, atomic.LoadUint64(&solidTpsCounter)) + + atomic.StoreUint64(&receivedTpsCounter, 0) + atomic.StoreUint64(&solidTpsCounter, 0) + } + } + }) +}) diff --git a/plugins/statusscreen/ui_header_bar.go b/plugins/statusscreen/ui_header_bar.go index 4089d415078ee8f7b02b3a5bd289dbb9f1411ca3..5d7a3993586341c8d2dbb8c481621bab94029aaa 100644 --- a/plugins/statusscreen/ui_header_bar.go +++ b/plugins/statusscreen/ui_header_bar.go @@ -17,6 +17,12 @@ import ( var start = time.Now() +var headerInfos = make([]func() (string, string), 0) + +func AddHeaderInfo(generator func() (string, string)) { + headerInfos = append(headerInfos, generator) +} + type UIHeaderBar struct { Primitive *tview.Grid LogoContainer *tview.TextView @@ -62,9 +68,16 @@ func (headerBar *UIHeaderBar) Update() { fmt.Fprintln(headerBar.InfoContainer) fmt.Fprintln(headerBar.InfoContainer, "[::d]COO-LESS IOTA PROTOTYPE - [::b]Status: [green::b]SYNCED ") - fmt.Fprintln(headerBar.InfoContainer) - fmt.Fprintln(headerBar.InfoContainer) - fmt.Fprintln(headerBar.InfoContainer) + for i := 0; i < 3-len(headerInfos); i++ { + fmt.Fprintln(headerBar.InfoContainer) + } + + for _, infoGenerator := range headerInfos { + fieldName, fieldValue := infoGenerator() + fmt.Fprintf(headerBar.InfoContainer, "[::b]%v: [::d]%40v ", fieldName, fieldValue) + fmt.Fprintln(headerBar.InfoContainer) + } + fmt.Fprintf(headerBar.InfoContainer, "[::b]Node ID: [::d]%40v ", accountability.OwnId().StringIdentifier) fmt.Fprintln(headerBar.InfoContainer) fmt.Fprintf(headerBar.InfoContainer, "[::b]Neighbors: [::d]%40v ", strconv.Itoa(len(chosenneighbors.INSTANCE.Peers))+" chosen / "+strconv.Itoa(len(acceptedneighbors.INSTANCE.Peers))+" accepted") diff --git a/plugins/webapi-gtta/plugin.go b/plugins/webapi-gtta/plugin.go index b174e7ec57650af8a2d4b89cc3da7cd164c7c6fa..3a97085736a984f78ea8df9528ba8d53b68d9721 100644 --- a/plugins/webapi-gtta/plugin.go +++ b/plugins/webapi-gtta/plugin.go @@ -21,14 +21,14 @@ func Handler(c echo.Context) error { branchTransactionHash := tipselection.GetRandomTip() trunkTransactionHash := tipselection.GetRandomTip() - return c.JSON(http.StatusOK, response{ + return c.JSON(http.StatusOK, webResponse{ Duration: time.Since(start).Nanoseconds() / 1e6, BranchTransaction: branchTransactionHash, TrunkTransaction: trunkTransactionHash, }) } -type response struct { +type webResponse struct { Duration int64 `json:"duration"` BranchTransaction ternary.Trinary `json:"branchTransaction"` TrunkTransaction ternary.Trinary `json:"trunkTransaction"` diff --git a/plugins/webapi-spammer/plugin.go b/plugins/webapi-spammer/plugin.go new file mode 100644 index 0000000000000000000000000000000000000000..b216aca5e0f9d3e905eb30b898b6066f4dd42c72 --- /dev/null +++ b/plugins/webapi-spammer/plugin.go @@ -0,0 +1,73 @@ +package webapi_spammer + +import ( + "net/http" + "time" + + "github.com/iotaledger/goshimmer/packages/node" + "github.com/iotaledger/goshimmer/packages/transactionspammer" + "github.com/iotaledger/goshimmer/plugins/webapi" + "github.com/labstack/echo" +) + +var PLUGIN = node.NewPlugin("Spammer", configure) + +func configure(plugin *node.Plugin) { + webapi.AddEndpoint("spammer", WebApiHandler) +} + +func WebApiHandler(c echo.Context) error { + c.Set("requestStartTime", time.Now()) + + var request webRequest + if err := c.Bind(&request); err != nil { + return requestFailed(c, err.Error()) + } + + switch request.Cmd { + case "start": + if request.Tps == 0 { + request.Tps = 1000 + } + + transactionspammer.Stop() + transactionspammer.Start(request.Tps) + + return requestSuccessful(c, "started spamming transactions") + + case "stop": + transactionspammer.Stop() + + return requestSuccessful(c, "stopped spamming transactions") + + default: + return requestFailed(c, "invalid cmd in request") + } +} + +func requestSuccessful(c echo.Context, message string) error { + return c.JSON(http.StatusOK, webResponse{ + Duration: time.Since(c.Get("requestStartTime").(time.Time)).Nanoseconds() / 1e6, + Status: "success", + Message: message, + }) +} + +func requestFailed(c echo.Context, message string) error { + return c.JSON(http.StatusOK, webResponse{ + Duration: time.Since(c.Get("requestStartTime").(time.Time)).Nanoseconds() / 1e6, + Status: "failed", + Message: message, + }) +} + +type webResponse struct { + Duration int64 `json:"duration"` + Status string `json:"status"` + Message string `json:"message"` +} + +type webRequest struct { + Cmd string `json:"cmd"` + Tps int64 `json:"tps"` +}