mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-21 07:24:36 +00:00
crypto: Refactor to move files out of the top level directory
Currently the top level directory contains basically all of the code for the crypto package. This PR moves the crypto code into submodules in a similar manner to what `golang/x/crypto` does. This improves code organization. Ref discussion: https://github.com/tendermint/tendermint/pull/1966 Closes #1956
This commit is contained in:
Generated
-335
@@ -1,335 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/ebuchman/fail-test"
|
||||
packages = ["."]
|
||||
revision = "95f809107225be108efcf10a3509e4ea6ceef3c4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-kit/kit"
|
||||
packages = [
|
||||
"log",
|
||||
"log/level",
|
||||
"log/term",
|
||||
"metrics",
|
||||
"metrics/discard",
|
||||
"metrics/internal/lv",
|
||||
"metrics/prometheus"
|
||||
]
|
||||
revision = "4dc7be5d2d12881735283bcab7352178e190fc71"
|
||||
version = "v0.6.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-logfmt/logfmt"
|
||||
packages = ["."]
|
||||
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-stack/stack"
|
||||
packages = ["."]
|
||||
revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = [
|
||||
"gogoproto",
|
||||
"jsonpb",
|
||||
"proto",
|
||||
"protoc-gen-gogo/descriptor",
|
||||
"sortkeys",
|
||||
"types"
|
||||
]
|
||||
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp"
|
||||
]
|
||||
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/snappy"
|
||||
packages = ["."]
|
||||
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jmhodges/levigo"
|
||||
packages = ["."]
|
||||
revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kr/logfmt"
|
||||
packages = ["."]
|
||||
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = [
|
||||
"prometheus",
|
||||
"prometheus/promhttp"
|
||||
]
|
||||
revision = "ae27198cdd90bf12cd134ad79d1366a6cf49f632"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
"internal/bitbucket.org/ww/goautoneg",
|
||||
"model"
|
||||
]
|
||||
revision = "7600349dcfe1abd18d72d3a1770870d9800a7801"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
"internal/util",
|
||||
"nfs",
|
||||
"xfs"
|
||||
]
|
||||
revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/rcrowley/go-metrics"
|
||||
packages = ["."]
|
||||
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/syndtr/goleveldb"
|
||||
packages = [
|
||||
"leveldb",
|
||||
"leveldb/cache",
|
||||
"leveldb/comparer",
|
||||
"leveldb/errors",
|
||||
"leveldb/filter",
|
||||
"leveldb/iterator",
|
||||
"leveldb/journal",
|
||||
"leveldb/memdb",
|
||||
"leveldb/opt",
|
||||
"leveldb/storage",
|
||||
"leveldb/table",
|
||||
"leveldb/util"
|
||||
]
|
||||
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/tendermint/ed25519"
|
||||
packages = [
|
||||
".",
|
||||
"edwards25519",
|
||||
"extra25519"
|
||||
]
|
||||
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/go-amino"
|
||||
packages = ["."]
|
||||
revision = "2106ca61d91029c931fd54968c2bb02dc96b1412"
|
||||
version = "0.10.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "develop"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/client",
|
||||
"abci/example/code",
|
||||
"abci/example/kvstore",
|
||||
"abci/types",
|
||||
"blockchain",
|
||||
"config",
|
||||
"consensus",
|
||||
"consensus/types",
|
||||
"crypto",
|
||||
"crypto/merkle",
|
||||
"crypto/tmhash",
|
||||
"evidence",
|
||||
"libs/autofile",
|
||||
"libs/clist",
|
||||
"libs/common",
|
||||
"libs/db",
|
||||
"libs/events",
|
||||
"libs/flowrate",
|
||||
"libs/log",
|
||||
"libs/pubsub",
|
||||
"libs/pubsub/query",
|
||||
"mempool",
|
||||
"node",
|
||||
"p2p",
|
||||
"p2p/conn",
|
||||
"p2p/pex",
|
||||
"p2p/upnp",
|
||||
"privval",
|
||||
"proxy",
|
||||
"rpc/client",
|
||||
"rpc/core",
|
||||
"rpc/core/types",
|
||||
"rpc/grpc",
|
||||
"rpc/lib",
|
||||
"rpc/lib/client",
|
||||
"rpc/lib/server",
|
||||
"rpc/lib/types",
|
||||
"state",
|
||||
"state/txindex",
|
||||
"state/txindex/kv",
|
||||
"state/txindex/null",
|
||||
"types",
|
||||
"version"
|
||||
]
|
||||
revision = "9d81a74429e093f3167875e0145ad957874c77d1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"curve25519",
|
||||
"internal/subtle",
|
||||
"nacl/box",
|
||||
"nacl/secretbox",
|
||||
"openpgp/armor",
|
||||
"openpgp/errors",
|
||||
"poly1305",
|
||||
"ripemd160",
|
||||
"salsa20/salsa"
|
||||
]
|
||||
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"netutil",
|
||||
"trace"
|
||||
]
|
||||
revision = "292b43bbf7cb8d35ddf40f8d5100ef3837cced3f"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable"
|
||||
]
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
revision = "e92b116572682a5b432ddd840aeaba2a559eeff1"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclb/grpc_lb_v1/messages",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
"transport"
|
||||
]
|
||||
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
|
||||
version = "v1.11.3"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "bc54a74ffdfc09872726fcf5c72b5df882269dc1cd949ac3fbeac9a554fc25c6"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
@@ -1,50 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-kit/kit"
|
||||
version = "^0.6.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
version = "^1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/pkg/errors"
|
||||
version = "^0.8.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/rcrowley/go-metrics"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
branch = "develop"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
+1
-67
@@ -1,35 +1,7 @@
|
||||
DIST_DIRS := find * -type d -exec
|
||||
VERSION := $(shell perl -ne '/^var version.*"([^"]+)".*$$/ && print "v$$1\n"' main.go)
|
||||
GOTOOLS = \
|
||||
github.com/mitchellh/gox \
|
||||
github.com/golang/dep/cmd/dep \
|
||||
gopkg.in/alecthomas/gometalinter.v2
|
||||
|
||||
all: check get_vendor_deps build test install metalinter
|
||||
|
||||
check: check_tools
|
||||
|
||||
########################################
|
||||
### Tools & dependencies
|
||||
|
||||
check_tools:
|
||||
@# https://stackoverflow.com/a/25668869
|
||||
@echo "Found tools: $(foreach tool,$(GOTOOLS_CHECK),\
|
||||
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
|
||||
|
||||
get_tools:
|
||||
@echo "--> Installing tools"
|
||||
go get -u -v $(GOTOOLS)
|
||||
@gometalinter.v2 --install
|
||||
|
||||
update_tools:
|
||||
@echo "--> Updating tools"
|
||||
@go get -u $(GOTOOLS)
|
||||
|
||||
get_vendor_deps:
|
||||
@rm -rf vendor/
|
||||
@echo "--> Running dep ensure"
|
||||
@dep ensure
|
||||
all: build test install
|
||||
|
||||
########################################
|
||||
### Build
|
||||
@@ -72,44 +44,6 @@ clean:
|
||||
rm -f ./tm-bench
|
||||
rm -rf ./dist
|
||||
|
||||
########################################
|
||||
### Formatting, linting, and vetting
|
||||
|
||||
fmt:
|
||||
@go fmt ./...
|
||||
|
||||
metalinter:
|
||||
@echo "==> Running linter"
|
||||
gometalinter.v2 --vendor --deadline=600s --disable-all \
|
||||
--enable=maligned \
|
||||
--enable=deadcode \
|
||||
--enable=goconst \
|
||||
--enable=goimports \
|
||||
--enable=gosimple \
|
||||
--enable=ineffassign \
|
||||
--enable=megacheck \
|
||||
--enable=misspell \
|
||||
--enable=staticcheck \
|
||||
--enable=safesql \
|
||||
--enable=structcheck \
|
||||
--enable=unconvert \
|
||||
--enable=unused \
|
||||
--enable=varcheck \
|
||||
--enable=vetshadow \
|
||||
./...
|
||||
#--enable=gas \
|
||||
#--enable=dupl \
|
||||
#--enable=errcheck \
|
||||
#--enable=gocyclo \
|
||||
#--enable=golint \ <== comments on anything exported
|
||||
#--enable=gotype \
|
||||
#--enable=interfacer \
|
||||
#--enable=unparam \
|
||||
#--enable=vet \
|
||||
|
||||
metalinter_all:
|
||||
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
|
||||
|
||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||
# unless there is a reason not to.
|
||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||
|
||||
@@ -51,15 +51,26 @@ with the last command being in a seperate window.
|
||||
## How stats are collected
|
||||
|
||||
These stats are derived by having each connection send transactions at the
|
||||
specified rate (or as close as it can get) for the specified time. After the
|
||||
specified time, it iterates over all of the blocks that were created in that
|
||||
time. The average and stddev per second are computed based off of that, by
|
||||
specified rate (or as close as it can get) for the specified time.
|
||||
After the specified time, it iterates over all of the blocks that were created
|
||||
in that time.
|
||||
The average and stddev per second are computed based off of that, by
|
||||
grouping the data by second.
|
||||
|
||||
To send transactions at the specified rate in each connection, we loop
|
||||
through the number of transactions. If its too slow, the loop stops at one second.
|
||||
If its too fast, we wait until the one second mark ends. The transactions per
|
||||
second stat is computed based off of what ends up in the block.
|
||||
through the number of transactions.
|
||||
If its too slow, the loop stops at one second.
|
||||
If its too fast, we wait until the one second mark ends.
|
||||
The transactions per second stat is computed based off of what ends up in the
|
||||
block.
|
||||
|
||||
Note that there will be edge effects on the number of transactions in the first
|
||||
and last blocks.
|
||||
This is because transactions may start sending midway through when tendermint
|
||||
starts building the next block, so it only has half as much time to gather txs
|
||||
that tm-bench sends.
|
||||
Similarly the end of the duration will likely end mid-way through tendermint
|
||||
trying to build the next block.
|
||||
|
||||
Each of the connections is handled via two separate goroutines.
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkTimingPerTx(b *testing.B) {
|
||||
startTime := time.Now()
|
||||
endTime := startTime.Add(time.Second)
|
||||
for i := 0; i < b.N; i++ {
|
||||
if i%20 == 0 {
|
||||
if time.Now().After(endTime) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-149
@@ -1,17 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/log/term"
|
||||
metrics "github.com/rcrowley/go-metrics"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmrpc "github.com/tendermint/tendermint/rpc/client"
|
||||
@@ -19,19 +16,14 @@ import (
|
||||
|
||||
var logger = log.NewNopLogger()
|
||||
|
||||
type statistics struct {
|
||||
TxsThroughput metrics.Histogram `json:"txs_per_sec"`
|
||||
BlocksThroughput metrics.Histogram `json:"blocks_per_sec"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
var duration, txsRate, connections, txSize int
|
||||
var durationInt, txsRate, connections, txSize int
|
||||
var verbose bool
|
||||
var outputFormat, broadcastTxMethod string
|
||||
|
||||
flagSet := flag.NewFlagSet("tm-bench", flag.ExitOnError)
|
||||
flagSet.IntVar(&connections, "c", 1, "Connections to keep open per endpoint")
|
||||
flagSet.IntVar(&duration, "T", 10, "Exit after the specified amount of time in seconds")
|
||||
flagSet.IntVar(&durationInt, "T", 10, "Exit after the specified amount of time in seconds")
|
||||
flagSet.IntVar(&txsRate, "r", 1000, "Txs per second to send in a connection")
|
||||
flagSet.IntVar(&txSize, "s", 250, "The size of a transaction in bytes.")
|
||||
flagSet.StringVar(&outputFormat, "output-format", "plain", "Output format: plain or json")
|
||||
@@ -42,7 +34,7 @@ func main() {
|
||||
fmt.Println(`Tendermint blockchain benchmarking tool.
|
||||
|
||||
Usage:
|
||||
tm-bench [-c 1] [-T 10] [-r 1000] [endpoints] [-output-format <plain|json> [-broadcast-tx-method <async|sync|commit>]]
|
||||
tm-bench [-c 1] [-T 10] [-r 1000] [-s 250] [endpoints] [-output-format <plain|json> [-broadcast-tx-method <async|sync|commit>]]
|
||||
|
||||
Examples:
|
||||
tm-bench localhost:26657`)
|
||||
@@ -73,7 +65,7 @@ Examples:
|
||||
}
|
||||
logger = log.NewTMLoggerWithColorFn(log.NewSyncWriter(os.Stdout), colorFn)
|
||||
|
||||
fmt.Printf("Running %ds test @ %s\n", duration, flagSet.Arg(0))
|
||||
fmt.Printf("Running %ds test @ %s\n", durationInt, flagSet.Arg(0))
|
||||
}
|
||||
|
||||
if broadcastTxMethod != "async" &&
|
||||
@@ -93,10 +85,6 @@ Examples:
|
||||
)
|
||||
logger.Info("Latest block height", "h", initialHeight)
|
||||
|
||||
// record time start
|
||||
timeStart := time.Now()
|
||||
logger.Info("Time started", "t", timeStart)
|
||||
|
||||
transacters := startTransacters(
|
||||
endpoints,
|
||||
connections,
|
||||
@@ -104,9 +92,17 @@ Examples:
|
||||
txSize,
|
||||
"broadcast_tx_"+broadcastTxMethod,
|
||||
)
|
||||
endTime := time.Duration(duration) * time.Second
|
||||
|
||||
<-time.After(endTime)
|
||||
// Wait until transacters have begun until we get the start time
|
||||
timeStart := time.Now()
|
||||
logger.Info("Time last transacter started", "t", timeStart)
|
||||
|
||||
duration := time.Duration(durationInt) * time.Second
|
||||
|
||||
timeEnd := timeStart.Add(duration)
|
||||
logger.Info("End time for calculation", "t", timeEnd)
|
||||
|
||||
<-time.After(duration)
|
||||
for i, t := range transacters {
|
||||
t.Stop()
|
||||
numCrashes := countCrashes(t.connsBroken)
|
||||
@@ -115,15 +111,13 @@ Examples:
|
||||
}
|
||||
}
|
||||
|
||||
timeStop := time.Now()
|
||||
logger.Info("Time stopped", "t", timeStop)
|
||||
logger.Debug("Time all transacters stopped", "t", time.Now())
|
||||
|
||||
stats, err := calculateStatistics(
|
||||
client,
|
||||
initialHeight,
|
||||
timeStart,
|
||||
timeStop,
|
||||
duration,
|
||||
durationInt,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
@@ -152,90 +146,6 @@ func countCrashes(crashes []bool) int {
|
||||
return count
|
||||
}
|
||||
|
||||
// calculateStatistics calculates the tx / second, and blocks / second based
|
||||
// off of the number the transactions and number of blocks that occurred from
|
||||
// the start block, and the end time.
|
||||
func calculateStatistics(
|
||||
client tmrpc.Client,
|
||||
minHeight int64,
|
||||
timeStart, timeStop time.Time,
|
||||
duration int,
|
||||
) (*statistics, error) {
|
||||
stats := &statistics{
|
||||
BlocksThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)),
|
||||
TxsThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)),
|
||||
}
|
||||
|
||||
// get blocks between minHeight and last height
|
||||
// This returns max(minHeight,(last_height - 20)) to last_height
|
||||
info, err := client.BlockchainInfo(minHeight, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
blockMetas = info.BlockMetas
|
||||
lastHeight = info.LastHeight
|
||||
diff = lastHeight - minHeight
|
||||
offset = len(blockMetas)
|
||||
)
|
||||
|
||||
for offset < int(diff) {
|
||||
// get blocks between minHeight and last height
|
||||
info, err := client.BlockchainInfo(minHeight, lastHeight-int64(offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockMetas = append(blockMetas, info.BlockMetas...)
|
||||
offset = len(blockMetas)
|
||||
}
|
||||
|
||||
var (
|
||||
numBlocksPerSec = make(map[int64]int64)
|
||||
numTxsPerSec = make(map[int64]int64)
|
||||
)
|
||||
|
||||
// because during some seconds blocks won't be created...
|
||||
for i := int64(0); i < int64(duration); i++ {
|
||||
numBlocksPerSec[i] = 0
|
||||
numTxsPerSec[i] = 0
|
||||
}
|
||||
|
||||
// iterates from max height to min height
|
||||
for _, blockMeta := range blockMetas {
|
||||
// check if block was created after timeStart
|
||||
if blockMeta.Header.Time.Before(timeStart) {
|
||||
break
|
||||
}
|
||||
|
||||
// check if block was created before timeStop
|
||||
if blockMeta.Header.Time.After(timeStop) {
|
||||
continue
|
||||
}
|
||||
sec := secondsSinceTimeStart(timeStart, blockMeta.Header.Time)
|
||||
|
||||
// increase number of blocks for that second
|
||||
numBlocksPerSec[sec]++
|
||||
|
||||
// increase number of txs for that second
|
||||
numTxsPerSec[sec] += blockMeta.Header.NumTxs
|
||||
}
|
||||
|
||||
for _, n := range numBlocksPerSec {
|
||||
stats.BlocksThroughput.Update(n)
|
||||
}
|
||||
|
||||
for _, n := range numTxsPerSec {
|
||||
stats.TxsThroughput.Update(n)
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func secondsSinceTimeStart(timeStart, timePassed time.Time) int64 {
|
||||
return int64(math.Round(timePassed.Sub(timeStart).Seconds()))
|
||||
}
|
||||
|
||||
func startTransacters(
|
||||
endpoints []string,
|
||||
connections,
|
||||
@@ -245,52 +155,21 @@ func startTransacters(
|
||||
) []*transacter {
|
||||
transacters := make([]*transacter, len(endpoints))
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(endpoints))
|
||||
for i, e := range endpoints {
|
||||
t := newTransacter(e, connections, txsRate, txSize, broadcastTxMethod)
|
||||
t.SetLogger(logger)
|
||||
if err := t.Start(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
transacters[i] = t
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
if err := t.Start(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
transacters[i] = t
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return transacters
|
||||
}
|
||||
|
||||
func printStatistics(stats *statistics, outputFormat string) {
|
||||
if outputFormat == "json" {
|
||||
result, err := json.Marshal(struct {
|
||||
TxsThroughput float64 `json:"txs_per_sec_avg"`
|
||||
BlocksThroughput float64 `json:"blocks_per_sec_avg"`
|
||||
}{stats.TxsThroughput.Mean(), stats.BlocksThroughput.Mean()})
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(string(result))
|
||||
} else {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0)
|
||||
fmt.Fprintln(w, "Stats\tAvg\tStdDev\tMax\tTotal\t")
|
||||
fmt.Fprintln(
|
||||
w,
|
||||
fmt.Sprintf(
|
||||
"Txs/sec\t%.0f\t%.0f\t%d\t%d\t",
|
||||
stats.TxsThroughput.Mean(),
|
||||
stats.TxsThroughput.StdDev(),
|
||||
stats.TxsThroughput.Max(),
|
||||
stats.TxsThroughput.Sum(),
|
||||
),
|
||||
)
|
||||
fmt.Fprintln(
|
||||
w,
|
||||
fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t%d\t",
|
||||
stats.BlocksThroughput.Mean(),
|
||||
stats.BlocksThroughput.StdDev(),
|
||||
stats.BlocksThroughput.Max(),
|
||||
stats.BlocksThroughput.Sum(),
|
||||
),
|
||||
)
|
||||
w.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
metrics "github.com/rcrowley/go-metrics"
|
||||
tmrpc "github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
type statistics struct {
|
||||
TxsThroughput metrics.Histogram `json:"txs_per_sec"`
|
||||
BlocksThroughput metrics.Histogram `json:"blocks_per_sec"`
|
||||
}
|
||||
|
||||
// calculateStatistics calculates the tx / second, and blocks / second based
|
||||
// off of the number the transactions and number of blocks that occurred from
|
||||
// the start block, and the end time.
|
||||
func calculateStatistics(
|
||||
client tmrpc.Client,
|
||||
minHeight int64,
|
||||
timeStart time.Time,
|
||||
duration int,
|
||||
) (*statistics, error) {
|
||||
timeEnd := timeStart.Add(time.Duration(duration) * time.Second)
|
||||
|
||||
stats := &statistics{
|
||||
BlocksThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)),
|
||||
TxsThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)),
|
||||
}
|
||||
|
||||
var (
|
||||
numBlocksPerSec = make(map[int64]int64)
|
||||
numTxsPerSec = make(map[int64]int64)
|
||||
)
|
||||
|
||||
// because during some seconds blocks won't be created...
|
||||
for i := int64(0); i < int64(duration); i++ {
|
||||
numBlocksPerSec[i] = 0
|
||||
numTxsPerSec[i] = 0
|
||||
}
|
||||
|
||||
blockMetas, err := getBlockMetas(client, minHeight, timeStart, timeEnd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// iterates from max height to min height
|
||||
for _, blockMeta := range blockMetas {
|
||||
// check if block was created after timeStart
|
||||
if blockMeta.Header.Time.Before(timeStart) {
|
||||
break
|
||||
}
|
||||
|
||||
// check if block was created before timeEnd
|
||||
if blockMeta.Header.Time.After(timeEnd) {
|
||||
continue
|
||||
}
|
||||
sec := secondsSinceTimeStart(timeStart, blockMeta.Header.Time)
|
||||
|
||||
// increase number of blocks for that second
|
||||
numBlocksPerSec[sec]++
|
||||
|
||||
// increase number of txs for that second
|
||||
numTxsPerSec[sec] += blockMeta.Header.NumTxs
|
||||
logger.Debug(fmt.Sprintf("%d txs at block height %d", blockMeta.Header.NumTxs, blockMeta.Header.Height))
|
||||
}
|
||||
|
||||
for i := int64(0); i < int64(duration); i++ {
|
||||
stats.BlocksThroughput.Update(numBlocksPerSec[i])
|
||||
stats.TxsThroughput.Update(numTxsPerSec[i])
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func getBlockMetas(client tmrpc.Client, minHeight int64, timeStart, timeEnd time.Time) ([]*types.BlockMeta, error) {
|
||||
// get blocks between minHeight and last height
|
||||
// This returns max(minHeight,(last_height - 20)) to last_height
|
||||
info, err := client.BlockchainInfo(minHeight, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
blockMetas = info.BlockMetas
|
||||
lastHeight = info.LastHeight
|
||||
diff = lastHeight - minHeight
|
||||
offset = len(blockMetas)
|
||||
)
|
||||
|
||||
for offset < int(diff) {
|
||||
// get blocks between minHeight and last height
|
||||
info, err := client.BlockchainInfo(minHeight, lastHeight-int64(offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockMetas = append(blockMetas, info.BlockMetas...)
|
||||
offset = len(blockMetas)
|
||||
}
|
||||
|
||||
return blockMetas, nil
|
||||
}
|
||||
|
||||
func secondsSinceTimeStart(timeStart, timePassed time.Time) int64 {
|
||||
return int64(math.Round(timePassed.Sub(timeStart).Seconds()))
|
||||
}
|
||||
|
||||
func printStatistics(stats *statistics, outputFormat string) {
|
||||
if outputFormat == "json" {
|
||||
result, err := json.Marshal(struct {
|
||||
TxsThroughput float64 `json:"txs_per_sec_avg"`
|
||||
BlocksThroughput float64 `json:"blocks_per_sec_avg"`
|
||||
}{stats.TxsThroughput.Mean(), stats.BlocksThroughput.Mean()})
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(string(result))
|
||||
} else {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0)
|
||||
fmt.Fprintln(w, "Stats\tAvg\tStdDev\tMax\tTotal\t")
|
||||
fmt.Fprintln(
|
||||
w,
|
||||
fmt.Sprintf(
|
||||
"Txs/sec\t%.0f\t%.0f\t%d\t%d\t",
|
||||
stats.TxsThroughput.Mean(),
|
||||
stats.TxsThroughput.StdDev(),
|
||||
stats.TxsThroughput.Max(),
|
||||
stats.TxsThroughput.Sum(),
|
||||
),
|
||||
)
|
||||
fmt.Fprintln(
|
||||
w,
|
||||
fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t%d\t",
|
||||
stats.BlocksThroughput.Mean(),
|
||||
stats.BlocksThroughput.StdDev(),
|
||||
stats.BlocksThroughput.Max(),
|
||||
stats.BlocksThroughput.Sum(),
|
||||
),
|
||||
)
|
||||
w.Flush()
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,8 @@ type transacter struct {
|
||||
|
||||
conns []*websocket.Conn
|
||||
connsBroken []bool
|
||||
wg sync.WaitGroup
|
||||
startingWg sync.WaitGroup
|
||||
endingWg sync.WaitGroup
|
||||
stopped bool
|
||||
|
||||
logger log.Logger
|
||||
@@ -75,19 +76,22 @@ func (t *transacter) Start() error {
|
||||
t.conns[i] = c
|
||||
}
|
||||
|
||||
t.wg.Add(2 * t.Connections)
|
||||
t.startingWg.Add(t.Connections)
|
||||
t.endingWg.Add(2 * t.Connections)
|
||||
for i := 0; i < t.Connections; i++ {
|
||||
go t.sendLoop(i)
|
||||
go t.receiveLoop(i)
|
||||
}
|
||||
|
||||
t.startingWg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop closes the connections.
|
||||
func (t *transacter) Stop() {
|
||||
t.stopped = true
|
||||
t.wg.Wait()
|
||||
t.endingWg.Wait()
|
||||
for _, c := range t.conns {
|
||||
c.Close()
|
||||
}
|
||||
@@ -97,7 +101,7 @@ func (t *transacter) Stop() {
|
||||
// `broadcast_tx_async`).
|
||||
func (t *transacter) receiveLoop(connIndex int) {
|
||||
c := t.conns[connIndex]
|
||||
defer t.wg.Done()
|
||||
defer t.endingWg.Done()
|
||||
for {
|
||||
_, _, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
@@ -118,6 +122,13 @@ func (t *transacter) receiveLoop(connIndex int) {
|
||||
|
||||
// sendLoop generates transactions at a given rate.
|
||||
func (t *transacter) sendLoop(connIndex int) {
|
||||
started := false
|
||||
// Close the starting waitgroup, in the event that this fails to start
|
||||
defer func() {
|
||||
if !started {
|
||||
t.startingWg.Done()
|
||||
}
|
||||
}()
|
||||
c := t.conns[connIndex]
|
||||
|
||||
c.SetPingHandler(func(message string) error {
|
||||
@@ -139,7 +150,7 @@ func (t *transacter) sendLoop(connIndex int) {
|
||||
defer func() {
|
||||
pingsTicker.Stop()
|
||||
txsTicker.Stop()
|
||||
t.wg.Done()
|
||||
t.endingWg.Done()
|
||||
}()
|
||||
|
||||
// hash of the host name is a part of each tx
|
||||
@@ -149,6 +160,11 @@ func (t *transacter) sendLoop(connIndex int) {
|
||||
hostname = "127.0.0.1"
|
||||
}
|
||||
hostnameHash = md5.Sum([]byte(hostname))
|
||||
// each transaction embeds connection index, tx number and hash of the hostname
|
||||
// we update the tx number between successive txs
|
||||
tx := generateTx(connIndex, txNumber, t.Size, hostnameHash)
|
||||
txHex := make([]byte, len(tx)*2)
|
||||
hex.Encode(txHex, tx)
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -156,18 +172,23 @@ func (t *transacter) sendLoop(connIndex int) {
|
||||
startTime := time.Now()
|
||||
endTime := startTime.Add(time.Second)
|
||||
numTxSent := t.Rate
|
||||
if !started {
|
||||
t.startingWg.Done()
|
||||
started = true
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
for i := 0; i < t.Rate; i++ {
|
||||
// each transaction embeds connection index, tx number and hash of the hostname
|
||||
tx := generateTx(connIndex, txNumber, t.Size, hostnameHash)
|
||||
paramsJSON, err := json.Marshal(map[string]interface{}{"tx": hex.EncodeToString(tx)})
|
||||
// update tx number of the tx, and the corresponding hex
|
||||
updateTx(tx, txHex, txNumber)
|
||||
paramsJSON, err := json.Marshal(map[string]interface{}{"tx": txHex})
|
||||
if err != nil {
|
||||
fmt.Printf("failed to encode params: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
rawParamsJSON := json.RawMessage(paramsJSON)
|
||||
|
||||
c.SetWriteDeadline(time.Now().Add(sendTimeout))
|
||||
c.SetWriteDeadline(now.Add(sendTimeout))
|
||||
err = c.WriteJSON(rpctypes.RPCRequest{
|
||||
JSONRPC: "2.0",
|
||||
ID: "tm-bench",
|
||||
@@ -182,9 +203,10 @@ func (t *transacter) sendLoop(connIndex int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Time added here is 7.13 ns/op, not significant enough to worry about
|
||||
if i%20 == 0 {
|
||||
if time.Now().After(endTime) {
|
||||
// cache the time.Now() reads to save time.
|
||||
if i%5 == 0 {
|
||||
now = time.Now()
|
||||
if now.After(endTime) {
|
||||
// Plus one accounts for sending this tx
|
||||
numTxSent = i + 1
|
||||
break
|
||||
@@ -250,3 +272,13 @@ func generateTx(connIndex int, txNumber int, txSize int, hostnameHash [md5.Size]
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
// warning, mutates input byte slice
|
||||
func updateTx(tx []byte, txHex []byte, txNumber int) {
|
||||
binary.PutUvarint(tx[8:16], uint64(txNumber))
|
||||
hexUpdate := make([]byte, 16)
|
||||
hex.Encode(hexUpdate, tx[8:16])
|
||||
for i := 16; i < 32; i++ {
|
||||
txHex[i] = hexUpdate[i-16]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// This test tests that the output of generate tx and update tx is consistent
|
||||
func TestGenerateTxUpdateTxConsistentency(t *testing.T) {
|
||||
cases := []struct {
|
||||
connIndex int
|
||||
startingTxNumber int
|
||||
txSize int
|
||||
hostname string
|
||||
numTxsToTest int
|
||||
}{
|
||||
{0, 0, 50, "localhost:26657", 1000},
|
||||
{70, 300, 10000, "localhost:26657", 1000},
|
||||
{0, 50, 100000, "localhost:26657", 1000},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
hostnameHash := md5.Sum([]byte(tc.hostname))
|
||||
// Tx generated from update tx. This is defined outside of the loop, since we have
|
||||
// to a have something initially to update
|
||||
updatedTx := generateTx(tc.connIndex, tc.startingTxNumber, tc.txSize, hostnameHash)
|
||||
updatedHex := make([]byte, len(updatedTx)*2)
|
||||
hex.Encode(updatedHex, updatedTx)
|
||||
for i := 0; i < tc.numTxsToTest; i++ {
|
||||
expectedTx := generateTx(tc.connIndex, tc.startingTxNumber+i, tc.txSize, hostnameHash)
|
||||
expectedHex := make([]byte, len(expectedTx)*2)
|
||||
hex.Encode(expectedHex, expectedTx)
|
||||
|
||||
updateTx(updatedTx, updatedHex, tc.startingTxNumber+i)
|
||||
|
||||
// after first 32 bytes is 8 bytes of time, then purely random bytes
|
||||
require.Equal(t, expectedTx[:32], updatedTx[:32],
|
||||
"First 32 bytes of the txs differed. tc #%d, i #%d", tcIndex, i)
|
||||
require.Equal(t, expectedHex[:64], updatedHex[:64],
|
||||
"First 64 bytes of the hex differed. tc #%d, i #%d", tcIndex, i)
|
||||
// Test the lengths of the txs are as expected
|
||||
require.Equal(t, tc.txSize, len(expectedTx),
|
||||
"Length of expected Tx differed. tc #%d, i #%d", tcIndex, i)
|
||||
require.Equal(t, tc.txSize, len(updatedTx),
|
||||
"Length of expected Tx differed. tc #%d, i #%d", tcIndex, i)
|
||||
require.Equal(t, tc.txSize*2, len(expectedHex),
|
||||
"Length of expected hex differed. tc #%d, i #%d", tcIndex, i)
|
||||
require.Equal(t, tc.txSize*2, len(updatedHex),
|
||||
"Length of updated hex differed. tc #%d, i #%d", tcIndex, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIterationOfSendLoop(b *testing.B) {
|
||||
var (
|
||||
connIndex = 0
|
||||
txSize = 25000
|
||||
)
|
||||
|
||||
now := time.Now()
|
||||
// something too far away to matter
|
||||
endTime := now.Add(time.Hour)
|
||||
txNumber := 0
|
||||
hostnameHash := md5.Sum([]byte{0})
|
||||
tx := generateTx(connIndex, txNumber, txSize, hostnameHash)
|
||||
txHex := make([]byte, len(tx)*2)
|
||||
hex.Encode(txHex, tx)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateTx(tx, txHex, txNumber)
|
||||
paramsJSON, err := json.Marshal(map[string]interface{}{"tx": txHex})
|
||||
if err != nil {
|
||||
fmt.Printf("failed to encode params: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
_ = json.RawMessage(paramsJSON)
|
||||
_ = now.Add(sendTimeout)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err,
|
||||
fmt.Sprintf("txs send failed on connection #%d", connIndex))
|
||||
logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Cache the now operations
|
||||
if i%5 == 0 {
|
||||
now = time.Now()
|
||||
if now.After(endTime) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
txNumber++
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user