Merge pull request #54 from getamis/feature/load-test-skeleton
tests: load test skeleton
This commit is contained in:
commit
de7b73ea4d
9
Makefile
9
Makefile
|
@ -1,4 +1,5 @@
|
|||
GOBIN = build/bin
|
||||
CURDIR = $(shell pwd)
|
||||
GOBIN = $(CURDIR)/build/bin
|
||||
GO ?= latest
|
||||
|
||||
istanbul:
|
||||
|
@ -6,5 +7,9 @@ istanbul:
|
|||
@echo "Done building."
|
||||
@echo "Run \"$(GOBIN)/istanbul\" to launch istanbul."
|
||||
|
||||
load-testing:
|
||||
@echo "Run load testing"
|
||||
@CURDIR=$(CURDIR) go test -v github.com/getamis/istanbul-tools/tests/load/... --timeout 1h
|
||||
|
||||
clean:
|
||||
rm -rf build/bin/
|
||||
rm -rf build/bin/
|
||||
|
|
|
@ -177,7 +177,7 @@ spec:
|
|||
- --maxpeers
|
||||
- "100"
|
||||
- --verbosity
|
||||
- "4"
|
||||
- "{{ .Values.ethereum.verbosity }}"
|
||||
- --syncmode
|
||||
- "full"
|
||||
ports:
|
||||
|
@ -232,6 +232,10 @@ spec:
|
|||
- name: nodekey
|
||||
mountPath: "{{ .Values.ethereum.nodekey.mountPath }}"
|
||||
volumes:
|
||||
{{- if .Values.testing.enabled }}
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
- name: genesis
|
||||
configMap:
|
||||
name: {{ .Values.genesis.config }}
|
||||
|
@ -244,6 +248,8 @@ spec:
|
|||
- name: static-nodes
|
||||
configMap:
|
||||
name: {{ .Values.ethereum.staticNodes.config }}
|
||||
{{- if .Values.testing.enabled }}
|
||||
{{- else }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
|
@ -253,3 +259,4 @@ spec:
|
|||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.volumes.chaindir.size }}
|
||||
{{- end }}
|
|
@ -2,6 +2,9 @@
|
|||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
testing:
|
||||
enabled: true
|
||||
|
||||
# service.yaml
|
||||
service:
|
||||
type: ClusterIP
|
||||
|
@ -12,8 +15,8 @@ service:
|
|||
# statefulset.yaml
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: quay.io/maicoin/ottoman_geth
|
||||
tag: latest
|
||||
repository: quay.io/amis/geth
|
||||
tag: istanbul_develop
|
||||
pullPolicy: Always
|
||||
|
||||
ethereum:
|
||||
|
@ -27,26 +30,26 @@ ethereum:
|
|||
enabled: true
|
||||
path: ""
|
||||
rpc:
|
||||
enabled: true
|
||||
addr: 0.0.0.0
|
||||
port: 8545
|
||||
api: "eth,net,web3,personal"
|
||||
corsdomain: "*"
|
||||
ws:
|
||||
enabled: false
|
||||
addr: 0.0.0.0
|
||||
port: 8545
|
||||
api: "eth,net,web3,personal,miner,admin"
|
||||
corsdomain: "*"
|
||||
ws:
|
||||
enabled: true
|
||||
addr: 0.0.0.0
|
||||
port: 8546
|
||||
api: "eth,net,web3,personal"
|
||||
api: "eth,net,web3,personal,miner,admin"
|
||||
origins: "*"
|
||||
mining:
|
||||
enabled: true
|
||||
enabled: false
|
||||
threads: 1
|
||||
etherbase: "1a9afb711302c5f83b5902843d1c007a1a137632"
|
||||
staticNodes:
|
||||
config: static-nodes
|
||||
mountPath: "/staticNodes"
|
||||
ethstats:
|
||||
enabled: true
|
||||
enabled: false
|
||||
addr: ws://eth-netstats
|
||||
port: 3000
|
||||
secret: bb98a0b6442386d0cdf8a31b267892c1
|
||||
|
@ -58,11 +61,12 @@ ethereum:
|
|||
address: "1a9afb711302c5f83b5902843d1c007a1a137632"
|
||||
data: '{"address":"1a9afb711302c5f83b5902843d1c007a1a137632","Crypto":{"cipher":"aes-128-ctr","ciphertext":"132b50d7c8944a115824de7c00911c40a90f84f27c614b7a3ef05ee8fd414312","cipherparams":{"iv":"0f745599d1b3303988ce210fb82b8c7f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"bce940bac232b4a9c5a2d50e5be51fde5cecfa7da9d49d8f650f91167bebf0de"},"mac":"36d515070b797aec58a574a3e04ea109498ee7674b15d7f952322cda7dcb68e3"},"id":"5d212b4c-3dd0-4c52-a32f-e42bf1b41133","version":3}'
|
||||
mountPath: "/keystore"
|
||||
verbosity: 3
|
||||
|
||||
volumes:
|
||||
chaindir:
|
||||
name: chaindir
|
||||
size: 1000Gi
|
||||
size: 10Gi
|
||||
mountPath: "/data"
|
||||
storageClass: ""
|
||||
|
||||
|
|
|
@ -14,33 +14,17 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package genesis
|
||||
package charts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLocalDir = "/tmp/gdata"
|
||||
clientIdentifier = "genesis"
|
||||
var (
|
||||
chartBasePath string
|
||||
)
|
||||
|
||||
func generateRandomDir() (string, error) {
|
||||
err := os.MkdirAll(filepath.Join(defaultLocalDir), 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
instanceDir := filepath.Join(defaultLocalDir, fmt.Sprintf("%s-%s", clientIdentifier, uuid.NewV4().String()))
|
||||
if err := os.MkdirAll(instanceDir, 0700); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to create instance dir: %v", err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return instanceDir, nil
|
||||
func init() {
|
||||
chartBasePath = filepath.Join(os.Getenv("CURDIR"), "benchmark/kubernetes")
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package charts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/getamis/istanbul-tools/genesis"
|
||||
)
|
||||
|
||||
type GenesisChart struct {
|
||||
name string
|
||||
chartPath string
|
||||
genesisFile string
|
||||
args []string
|
||||
}
|
||||
|
||||
func NewGenesisChart(addrs []common.Address, gasLimit uint64) *GenesisChart {
|
||||
chartPath := filepath.Join(chartBasePath, "genesis-block")
|
||||
genesisPath := filepath.Join(chartPath, ".genesis")
|
||||
err := os.MkdirAll(genesisPath, 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
chart := &GenesisChart{
|
||||
name: "genesis-block",
|
||||
chartPath: chartPath,
|
||||
genesisFile: genesis.NewFileAt(
|
||||
genesisPath,
|
||||
false,
|
||||
genesis.Validators(addrs...),
|
||||
genesis.GasLimit(gasLimit),
|
||||
),
|
||||
}
|
||||
|
||||
relPath := strings.Replace(chart.genesisFile, chartPath+"/", "", 1)
|
||||
chart.Override("genesisFileName", relPath)
|
||||
|
||||
return chart
|
||||
}
|
||||
|
||||
func (chart *GenesisChart) Override(key, value string) {
|
||||
chart.args = append(chart.args, fmt.Sprintf("%s=%s", key, value))
|
||||
}
|
||||
|
||||
func (chart *GenesisChart) Install(debug bool) error {
|
||||
defer os.RemoveAll(filepath.Dir(chart.genesisFile))
|
||||
|
||||
return installRelease(
|
||||
chart.name,
|
||||
chart.args,
|
||||
chart.chartPath,
|
||||
debug,
|
||||
)
|
||||
}
|
||||
|
||||
func (chart *GenesisChart) Uninstall() error {
|
||||
return uninstallRelease(chart.name)
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package charts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/getamis/istanbul-tools/common"
|
||||
)
|
||||
|
||||
type StaticNodesChart struct {
|
||||
name string
|
||||
chartPath string
|
||||
staticNodesFile string
|
||||
args []string
|
||||
}
|
||||
|
||||
func NewStaticNodesChart(nodekeys []string, ipAddrs []string) *StaticNodesChart {
|
||||
chartPath := filepath.Join(chartBasePath, "static-nodes")
|
||||
staticNodesPath := filepath.Join(chartPath, ".static-nodes")
|
||||
err := os.MkdirAll(staticNodesPath, 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(nodekeys) != len(ipAddrs) {
|
||||
log.Println("The number of nodekeys and the number of IP address should be equal")
|
||||
return nil
|
||||
}
|
||||
|
||||
chart := &StaticNodesChart{
|
||||
name: "static-nodes",
|
||||
chartPath: chartPath,
|
||||
staticNodesFile: common.GenerateStaticNodesAt(staticNodesPath, nodekeys, ipAddrs),
|
||||
}
|
||||
|
||||
relPath := strings.Replace(chart.staticNodesFile, chartPath+"/", "", 1)
|
||||
chart.Override("fileName", relPath)
|
||||
|
||||
return chart
|
||||
}
|
||||
|
||||
func (chart *StaticNodesChart) Override(key, value string) {
|
||||
chart.args = append(chart.args, fmt.Sprintf("%s=%s", key, value))
|
||||
}
|
||||
|
||||
func (chart *StaticNodesChart) Install(debug bool) error {
|
||||
defer os.RemoveAll(filepath.Dir(chart.staticNodesFile))
|
||||
|
||||
return installRelease(
|
||||
chart.name,
|
||||
chart.args,
|
||||
chart.chartPath,
|
||||
debug,
|
||||
)
|
||||
}
|
||||
|
||||
func (chart *StaticNodesChart) Uninstall() error {
|
||||
return uninstallRelease(chart.name)
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package charts
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newInstallCommand() *exec.Cmd {
|
||||
return exec.Command("helm", "install")
|
||||
}
|
||||
|
||||
func newUninstallCommand() *exec.Cmd {
|
||||
return exec.Command("helm", "delete", "--purge")
|
||||
}
|
||||
|
||||
func installRelease(name string, args []string, path string, debug bool) error {
|
||||
cmd := newInstallCommand()
|
||||
|
||||
if name != "" {
|
||||
cmd.Args = append(cmd.Args, "--name")
|
||||
cmd.Args = append(cmd.Args, name)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
cmd.Args = append(cmd.Args, "--set")
|
||||
cmd.Args = append(cmd.Args, strings.Join(args, ","))
|
||||
}
|
||||
|
||||
cmd.Args = append(cmd.Args, path)
|
||||
|
||||
if debug {
|
||||
cmd.Args = append(cmd.Args, "--dry-run")
|
||||
cmd.Args = append(cmd.Args, "--debug")
|
||||
}
|
||||
|
||||
cmd.Args = append(cmd.Args, "--wait")
|
||||
|
||||
if debug {
|
||||
fmt.Println(cmd.Args)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(err, string(output))
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
func uninstallRelease(release string) error {
|
||||
cmd := newUninstallCommand()
|
||||
|
||||
if release != "" {
|
||||
cmd.Args = append(cmd.Args, release)
|
||||
} else {
|
||||
return errors.New("Unknown release name")
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListCharts() {
|
||||
cmd := exec.Command("helm", "list")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package charts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type ValidatorChart struct {
|
||||
name string
|
||||
chartPath string
|
||||
args []string
|
||||
}
|
||||
|
||||
func NewValidatorChart(name string, args []string) *ValidatorChart {
|
||||
chartPath := filepath.Join(chartBasePath, "validator")
|
||||
|
||||
chart := &ValidatorChart{
|
||||
name: "validator-" + name,
|
||||
args: args,
|
||||
chartPath: chartPath,
|
||||
}
|
||||
|
||||
return chart
|
||||
}
|
||||
|
||||
func (chart *ValidatorChart) Override(key, value string) {
|
||||
chart.args = append(chart.args, fmt.Sprintf("%s=%s", key, value))
|
||||
}
|
||||
|
||||
func (chart *ValidatorChart) Install(debug bool) error {
|
||||
return installRelease(
|
||||
chart.name,
|
||||
chart.args,
|
||||
chart.chartPath,
|
||||
debug,
|
||||
)
|
||||
}
|
||||
|
||||
func (chart *ValidatorChart) Uninstall() error {
|
||||
return uninstallRelease(chart.name)
|
||||
}
|
||||
|
||||
func (chart *ValidatorChart) Name() string {
|
||||
return chart.name
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/getamis/go-ethereum/p2p/discover"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLocalDir = "/tmp/gdata"
|
||||
clientIdentifier = "geth"
|
||||
nodekeyFileName = "nodekey"
|
||||
)
|
||||
|
||||
func GenerateIPs(num int) (ips []string) {
|
||||
for i := 0; i < num; i++ {
|
||||
ips = append(ips, fmt.Sprintf("10.1.1.%d", i+2))
|
||||
}
|
||||
|
||||
return ips
|
||||
}
|
||||
|
||||
func GenerateRandomDir() (string, error) {
|
||||
err := os.MkdirAll(filepath.Join(defaultLocalDir), 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
instanceDir := filepath.Join(defaultLocalDir, fmt.Sprintf("%s-%s", clientIdentifier, uuid.NewV4().String()))
|
||||
if err := os.MkdirAll(instanceDir, 0700); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to create instance dir: %v", err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return instanceDir, nil
|
||||
}
|
||||
|
||||
func GenerateKeys(num int) (keys []*ecdsa.PrivateKey, nodekeys []string, addrs []common.Address) {
|
||||
for i := 0; i < num; i++ {
|
||||
nodekey := RandomHex()[2:]
|
||||
nodekeys = append(nodekeys, nodekey)
|
||||
|
||||
key, err := crypto.HexToECDSA(nodekey)
|
||||
if err != nil {
|
||||
log.Fatalf("couldn't generate key: " + err.Error())
|
||||
}
|
||||
keys = append(keys, key)
|
||||
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
return keys, nodekeys, addrs
|
||||
}
|
||||
|
||||
func SaveNodeKey(key *ecdsa.PrivateKey, dataDir string) error {
|
||||
keyDir := filepath.Join(dataDir, clientIdentifier)
|
||||
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to create key dir: %v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
keyfile := filepath.Join(keyDir, nodekeyFileName)
|
||||
if err := crypto.SaveECDSA(keyfile, key); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to persist node key: %v", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GenerateStaticNodesAt(dir string, nodekeys []string, ipAddrs []string) (filename string) {
|
||||
var nodes []string
|
||||
|
||||
for i, nodekey := range nodekeys {
|
||||
key, err := crypto.HexToECDSA(nodekey)
|
||||
if err != nil {
|
||||
log.Printf("Failed to create key, err: %v\n", err)
|
||||
return ""
|
||||
}
|
||||
node := discover.NewNode(
|
||||
discover.PubkeyID(&key.PublicKey),
|
||||
net.ParseIP(ipAddrs[i]),
|
||||
0,
|
||||
uint16(30303))
|
||||
|
||||
nodes = append(nodes, node.String())
|
||||
}
|
||||
|
||||
filename = filepath.Join(dir, "static-nodes.json")
|
||||
bytes, _ := json.Marshal(nodes)
|
||||
if err := ioutil.WriteFile(filename, bytes, 0644); err != nil {
|
||||
log.Printf("Failed to write '%s', err: %v\n", filename, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return filename
|
||||
}
|
||||
|
||||
func GenerateStaticNodes(nodekeys []string, ipAddrs []string) (filename string) {
|
||||
dir, err := GenerateRandomDir()
|
||||
if err != nil {
|
||||
log.Printf("Failed to generate directory, err: %v\n", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return GenerateStaticNodesAt(dir, nodekeys, ipAddrs)
|
||||
}
|
||||
|
||||
func RandomHex() string {
|
||||
b, _ := RandomBytes(32)
|
||||
return common.BytesToHash(b).Hex()
|
||||
}
|
||||
|
||||
func RandomBytes(len int) ([]byte, error) {
|
||||
b := make([]byte, len)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/phayes/freeport"
|
||||
|
||||
istcommon "github.com/getamis/istanbul-tools/common"
|
||||
"github.com/getamis/istanbul-tools/genesis"
|
||||
)
|
||||
|
||||
|
@ -137,7 +138,7 @@ func NewDefaultBlockchainWithFaulty(network *DockerNetwork, numOfNormal int, num
|
|||
log.Fatalf("Failed to get free ip addresses, err: %v", err)
|
||||
}
|
||||
|
||||
keys, addrs := generateKeys(totalNodes)
|
||||
keys, _, addrs := istcommon.GenerateKeys(totalNodes)
|
||||
bc.setupGenesis(addrs)
|
||||
// Create normal validators
|
||||
bc.opts = normalOpts
|
||||
|
@ -319,7 +320,7 @@ func (bc *blockchain) CreateNodes(num int, options ...Option) (nodes []Ethereum,
|
|||
opts = append(opts, options...)
|
||||
|
||||
// Host data directory
|
||||
dataDir, err := generateRandomDir()
|
||||
dataDir, err := istcommon.GenerateRandomDir()
|
||||
if err != nil {
|
||||
log.Println("Failed to create data dir", err)
|
||||
return nil, err
|
||||
|
@ -353,7 +354,7 @@ func (bc *blockchain) addValidators(numOfValidators int) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keys, addrs := generateKeys(numOfValidators)
|
||||
keys, _, addrs := istcommon.GenerateKeys(numOfValidators)
|
||||
bc.setupGenesis(addrs)
|
||||
bc.setupValidators(ips, keys, bc.opts...)
|
||||
|
||||
|
@ -394,7 +395,7 @@ func (bc *blockchain) setupValidators(ips []net.IP, keys []*ecdsa.PrivateKey, op
|
|||
opts = append(opts, options...)
|
||||
|
||||
// Host data directory
|
||||
dataDir, err := generateRandomDir()
|
||||
dataDir, err := istcommon.GenerateRandomDir()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create data dir", err)
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ import (
|
|||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
|
||||
istcommon "github.com/getamis/istanbul-tools/common"
|
||||
)
|
||||
|
||||
//TODO: refactor this with ethereum options?
|
||||
|
@ -192,7 +194,7 @@ func (ct *constellation) Image() string {
|
|||
|
||||
func (ct *constellation) GenerateKey() (localWorkDir string, err error) {
|
||||
// Generate empty password file
|
||||
ct.localWorkDir, err = generateRandomDir()
|
||||
ct.localWorkDir, err = istcommon.GenerateRandomDir()
|
||||
if err != nil {
|
||||
log.Printf("Failed to generate working dir, err: :%v\n", err)
|
||||
return "", err
|
||||
|
|
|
@ -43,6 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
|
||||
istcommon "github.com/getamis/istanbul-tools/common"
|
||||
"github.com/getamis/istanbul-tools/genesis"
|
||||
"github.com/getamis/istanbul-tools/istclient"
|
||||
)
|
||||
|
@ -146,7 +147,7 @@ type ethereum struct {
|
|||
}
|
||||
|
||||
func (eth *ethereum) Init(genesisFile string) error {
|
||||
if err := saveNodeKey(eth.key, eth.dataDir); err != nil {
|
||||
if err := istcommon.SaveNodeKey(eth.key, eth.dataDir); err != nil {
|
||||
log.Fatal("Failed to save nodekey", err)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,74 +17,15 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/istanbul"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/getamis/istanbul-tools/cmd/istanbul/extra"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLocalDir = "/tmp/gdata"
|
||||
clientIdentifier = "geth"
|
||||
nodekeyFileName = "nodekey"
|
||||
)
|
||||
|
||||
func generateRandomDir() (string, error) {
|
||||
err := os.MkdirAll(filepath.Join(defaultLocalDir), 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
instanceDir := filepath.Join(defaultLocalDir, fmt.Sprintf("%s-%s", clientIdentifier, uuid.NewV4().String()))
|
||||
if err := os.MkdirAll(instanceDir, 0700); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to create instance dir: %v", err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return instanceDir, nil
|
||||
}
|
||||
|
||||
func generateKeys(num int) (keys []*ecdsa.PrivateKey, addrs []common.Address) {
|
||||
for i := 0; i < num; i++ {
|
||||
key, err := crypto.GenerateKey()
|
||||
if err != nil {
|
||||
log.Fatalf("couldn't generate key: " + err.Error())
|
||||
}
|
||||
keys = append(keys, key)
|
||||
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
return keys, addrs
|
||||
}
|
||||
|
||||
func saveNodeKey(key *ecdsa.PrivateKey, dataDir string) error {
|
||||
keyDir := filepath.Join(dataDir, clientIdentifier)
|
||||
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to create key dir: %v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
keyfile := filepath.Join(keyDir, nodekeyFileName)
|
||||
if err := crypto.SaveECDSA(keyfile, key); err != nil {
|
||||
log.Println(fmt.Sprintf("Failed to persist node key: %v", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sigHash(header *types.Header) (hash common.Hash) {
|
||||
hasher := sha3.NewKeccak256()
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
"github.com/getamis/istanbul-tools/common"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -64,11 +66,7 @@ func New(options ...Option) *core.Genesis {
|
|||
return genesis
|
||||
}
|
||||
|
||||
func NewFile(isQuorum bool, options ...Option) string {
|
||||
dir, err := generateRandomDir()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create random directory, err: %v", err)
|
||||
}
|
||||
func NewFileAt(dir string, isQuorum bool, options ...Option) string {
|
||||
genesis := New(options...)
|
||||
if err := Save(dir, genesis, isQuorum); err != nil {
|
||||
log.Fatalf("Failed to save genesis to '%s', err: %v", dir, err)
|
||||
|
@ -77,6 +75,14 @@ func NewFile(isQuorum bool, options ...Option) string {
|
|||
return filepath.Join(dir, FileName)
|
||||
}
|
||||
|
||||
func NewFile(isQuorum bool, options ...Option) string {
|
||||
dir, err := common.GenerateRandomDir()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create random directory, err: %v", err)
|
||||
}
|
||||
return NewFileAt(dir, isQuorum, options...)
|
||||
}
|
||||
|
||||
func Save(dataDir string, genesis *core.Genesis, isQuorum bool) error {
|
||||
filePath := filepath.Join(dataDir, FileName)
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package tests
|
||||
|
||||
type ChartInstaller interface {
|
||||
Install(bool) error
|
||||
Uninstall() error
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package load
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/getamis/istanbul-tools/charts"
|
||||
"github.com/getamis/istanbul-tools/common"
|
||||
|
||||
"github.com/getamis/istanbul-tools/tests"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("TPS-01: Large amount of transactions", func() {
|
||||
tests.CaseTable("with number of validators",
|
||||
func(numberOfValidators int) {
|
||||
tests.CaseTable("with gas limit",
|
||||
func(gaslimit int) {
|
||||
tests.CaseTable("with txpool size",
|
||||
func(txpoolSize int) {
|
||||
runTests(numberOfValidators, gaslimit, txpoolSize)
|
||||
},
|
||||
|
||||
tests.Case("2048", 2048),
|
||||
tests.Case("10240", 10240),
|
||||
)
|
||||
},
|
||||
|
||||
tests.Case("21000*1000", 21000*1000),
|
||||
tests.Case("21000*3000", 21000*3000),
|
||||
)
|
||||
},
|
||||
|
||||
tests.Case("4 validators", 4),
|
||||
tests.Case("7 validators", 7),
|
||||
tests.Case("10 validators", 10),
|
||||
)
|
||||
})
|
||||
|
||||
func runTests(numberOfValidators int, gaslimit int, txpoolSize int) {
|
||||
Describe("", func() {
|
||||
var (
|
||||
genesisChart tests.ChartInstaller
|
||||
staticNodesChart tests.ChartInstaller
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
_, nodekeys, addrs := common.GenerateKeys(numberOfValidators)
|
||||
genesisChart = charts.NewGenesisChart(addrs, uint64(gaslimit))
|
||||
Expect(genesisChart.Install(false)).To(BeNil())
|
||||
|
||||
staticNodesChart = charts.NewStaticNodesChart(nodekeys, common.GenerateIPs(len(nodekeys)))
|
||||
Expect(staticNodesChart.Install(false)).To(BeNil())
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(genesisChart.Uninstall()).To(BeNil())
|
||||
Expect(staticNodesChart.Uninstall()).To(BeNil())
|
||||
})
|
||||
|
||||
It("", func() {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func IstanbulLoadTest(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Istanbul Load Test Suite")
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2017 AMIS Technologies
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
)
|
||||
|
||||
func CaseTable(description string, itBody interface{}, entries ...tableEntry) bool {
|
||||
caseTable(description, itBody, entries, false, false)
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
You can focus a table with `FCaseTable`.
|
||||
*/
|
||||
func FCaseTable(description string, itBody interface{}, entries ...tableEntry) bool {
|
||||
caseTable(description, itBody, entries, false, true)
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
You can mark a table as pending with `PCaseTable`.
|
||||
*/
|
||||
func PCaseTable(description string, itBody interface{}, entries ...tableEntry) bool {
|
||||
caseTable(description, itBody, entries, true, false)
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
You can mark a table as pending with `XCaseTable`.
|
||||
*/
|
||||
func XCaseTable(description string, itBody interface{}, entries ...tableEntry) bool {
|
||||
caseTable(description, itBody, entries, true, false)
|
||||
return true
|
||||
}
|
||||
|
||||
func caseTable(description string, itBody interface{}, entries []tableEntry, pending bool, focused bool) {
|
||||
itBodyValue := reflect.ValueOf(itBody)
|
||||
if itBodyValue.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody))
|
||||
}
|
||||
|
||||
if pending {
|
||||
ginkgo.PDescribe(description, func() {
|
||||
for _, entry := range entries {
|
||||
entry.generate(itBodyValue, entries, pending, focused)
|
||||
}
|
||||
})
|
||||
} else if focused {
|
||||
ginkgo.FDescribe(description, func() {
|
||||
for _, entry := range entries {
|
||||
entry.generate(itBodyValue, entries, pending, focused)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ginkgo.Describe(description, func() {
|
||||
for _, entry := range entries {
|
||||
entry.generate(itBodyValue, entries, pending, focused)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
)
|
||||
|
||||
/*
|
||||
TableEntry represents an entry in a table test. You generally use the `Entry` constructor.
|
||||
*/
|
||||
type tableEntry struct {
|
||||
Description string
|
||||
Parameters []interface{}
|
||||
Pending bool
|
||||
Focused bool
|
||||
}
|
||||
|
||||
func (t tableEntry) generate(itBody reflect.Value, entries []tableEntry, pending bool, focused bool) {
|
||||
if t.Pending {
|
||||
ginkgo.PDescribe(t.Description, func() {
|
||||
for _, entry := range entries {
|
||||
entry.generate(itBody, entries, pending, focused)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
values := []reflect.Value{}
|
||||
for i, param := range t.Parameters {
|
||||
var value reflect.Value
|
||||
|
||||
if param == nil {
|
||||
inType := itBody.Type().In(i)
|
||||
value = reflect.Zero(inType)
|
||||
} else {
|
||||
value = reflect.ValueOf(param)
|
||||
}
|
||||
|
||||
values = append(values, value)
|
||||
}
|
||||
|
||||
body := func() {
|
||||
itBody.Call(values)
|
||||
}
|
||||
|
||||
if t.Focused {
|
||||
ginkgo.FDescribe(t.Description, body)
|
||||
} else {
|
||||
ginkgo.Describe(t.Description, body)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Entry constructs a tableEntry.
|
||||
|
||||
The first argument is a required description (this becomes the content of the generated Ginkgo `It`).
|
||||
Subsequent parameters are saved off and sent to the callback passed in to `DescribeTable`.
|
||||
|
||||
Each Entry ends up generating an individual Ginkgo It.
|
||||
*/
|
||||
func Case(description string, parameters ...interface{}) tableEntry {
|
||||
return tableEntry{description, parameters, false, false}
|
||||
}
|
||||
|
||||
/*
|
||||
You can focus a particular entry with FEntry. This is equivalent to FIt.
|
||||
*/
|
||||
func FCase(description string, parameters ...interface{}) tableEntry {
|
||||
return tableEntry{description, parameters, false, true}
|
||||
}
|
||||
|
||||
/*
|
||||
You can mark a particular entry as pending with PEntry. This is equivalent to PIt.
|
||||
*/
|
||||
func PCase(description string, parameters ...interface{}) tableEntry {
|
||||
return tableEntry{description, parameters, true, false}
|
||||
}
|
||||
|
||||
/*
|
||||
You can mark a particular entry as pending with XEntry. This is equivalent to XIt.
|
||||
*/
|
||||
func XCase(description string, parameters ...interface{}) tableEntry {
|
||||
return tableEntry{description, parameters, true, false}
|
||||
}
|
Loading…
Reference in New Issue