Merge branch 'release/0.9.5'
This commit is contained in:
commit
7868e50496
41
Makefile
41
Makefile
|
@ -5,25 +5,24 @@ GOBIN = build/bin
|
||||||
GO ?= latest
|
GO ?= latest
|
||||||
|
|
||||||
statusgo:
|
statusgo:
|
||||||
build/env.sh go build -i -o $(GOBIN)/statusgo -v $(shell build/testnet-flags.sh) ./cmd/status
|
build/env.sh go build -i -o $(GOBIN)/statusd -v $(shell build/testnet-flags.sh) ./cmd/statusd
|
||||||
@echo "status go compilation done."
|
@echo "\nCompilation done.\nRun \"build/bin/statusd help\" to view available commands."
|
||||||
@echo "Run \"build/bin/statusgo\" to view available commands"
|
|
||||||
|
|
||||||
statusgo-cross: statusgo-android statusgo-ios
|
statusgo-cross: statusgo-android statusgo-ios
|
||||||
@echo "Full cross compilation done."
|
@echo "Full cross compilation done."
|
||||||
@ls -ld $(GOBIN)/statusgo-*
|
@ls -ld $(GOBIN)/statusgo-*
|
||||||
|
|
||||||
statusgo-android: xgo
|
statusgo-android: xgo
|
||||||
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=android-16/aar -v $(shell build/testnet-flags.sh) ./cmd/status
|
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=android-16/aar -v $(shell build/testnet-flags.sh) ./cmd/statusd
|
||||||
@echo "Android cross compilation done."
|
@echo "Android cross compilation done."
|
||||||
|
|
||||||
statusgo-ios: xgo
|
statusgo-ios: xgo
|
||||||
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/testnet-flags.sh) ./cmd/status
|
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/testnet-flags.sh) ./cmd/statusd
|
||||||
@echo "iOS framework cross compilation done."
|
@echo "iOS framework cross compilation done."
|
||||||
|
|
||||||
statusgo-ios-simulator: xgo
|
statusgo-ios-simulator: xgo
|
||||||
@build/env.sh docker pull farazdagi/xgo-ios-simulator
|
@build/env.sh docker pull farazdagi/xgo-ios-simulator
|
||||||
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo-ios-simulator --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/testnet-flags.sh) ./cmd/status
|
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo-ios-simulator --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/testnet-flags.sh) ./cmd/statusd
|
||||||
@echo "iOS framework cross compilation done."
|
@echo "iOS framework cross compilation done."
|
||||||
|
|
||||||
xgo:
|
xgo:
|
||||||
|
@ -31,49 +30,55 @@ xgo:
|
||||||
build/env.sh go get github.com/karalabe/xgo
|
build/env.sh go get github.com/karalabe/xgo
|
||||||
|
|
||||||
statusgo-mainnet:
|
statusgo-mainnet:
|
||||||
build/env.sh go build -i -o $(GOBIN)/statusgo -v $(shell build/mainnet-flags.sh) ./cmd/status
|
build/env.sh go build -i -o $(GOBIN)/statusgo -v $(shell build/mainnet-flags.sh) ./cmd/statusd
|
||||||
@echo "status go compilation done (mainnet)."
|
@echo "status go compilation done (mainnet)."
|
||||||
@echo "Run \"build/bin/statusgo\" to view available commands"
|
@echo "Run \"build/bin/statusgo\" to view available commands"
|
||||||
|
|
||||||
statusgo-android-mainnet: xgo
|
statusgo-android-mainnet: xgo
|
||||||
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=android-16/aar -v $(shell build/mainnet-flags.sh) ./cmd/status
|
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=android-16/aar -v $(shell build/mainnet-flags.sh) ./cmd/statusd
|
||||||
@echo "Android cross compilation done (mainnet)."
|
@echo "Android cross compilation done (mainnet)."
|
||||||
|
|
||||||
statusgo-ios-mainnet: xgo
|
statusgo-ios-mainnet: xgo
|
||||||
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/mainnet-flags.sh) ./cmd/status
|
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/mainnet-flags.sh) ./cmd/statusd
|
||||||
@echo "iOS framework cross compilation done (mainnet)."
|
@echo "iOS framework cross compilation done (mainnet)."
|
||||||
|
|
||||||
statusgo-ios-simulator-mainnet: xgo
|
statusgo-ios-simulator-mainnet: xgo
|
||||||
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo-ios-simulator --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/mainnet-flags.sh) ./cmd/status
|
build/env.sh $(GOBIN)/xgo --image farazdagi/xgo-ios-simulator --go=$(GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v $(shell build/mainnet-flags.sh) ./cmd/statusd
|
||||||
@echo "iOS framework cross compilation done (mainnet)."
|
@echo "iOS framework cross compilation done (mainnet)."
|
||||||
|
|
||||||
ci:
|
ci:
|
||||||
build/env.sh go test -v -cover ./geth
|
build/env.sh go test -v -cover ./geth
|
||||||
build/env.sh go test -v -cover ./jail
|
build/env.sh go test -v -cover ./geth/params
|
||||||
|
build/env.sh go test -v -cover ./geth/jail
|
||||||
build/env.sh go test -v -cover ./extkeys
|
build/env.sh go test -v -cover ./extkeys
|
||||||
|
|
||||||
test-all:
|
test:
|
||||||
@build/env.sh echo "mode: set" > coverage-all.out
|
@build/env.sh echo "mode: set" > coverage-all.out
|
||||||
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth
|
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth
|
||||||
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
||||||
build/env.sh go test -coverprofile=coverage.out -covermode=set ./jail
|
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth/params
|
||||||
|
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
||||||
|
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth/jail
|
||||||
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
||||||
build/env.sh go test -coverprofile=coverage.out -covermode=set ./extkeys
|
build/env.sh go test -coverprofile=coverage.out -covermode=set ./extkeys
|
||||||
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
||||||
build/env.sh go test -coverprofile=coverage.out -covermode=set ./cmd/status
|
build/env.sh go test -coverprofile=coverage.out -covermode=set ./cmd/statusd
|
||||||
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
|
||||||
@build/env.sh go tool cover -html=coverage-all.out -o coverage.html
|
@build/env.sh go tool cover -html=coverage-all.out -o coverage.html
|
||||||
@build/env.sh go tool cover -func=coverage-all.out
|
@build/env.sh go tool cover -func=coverage-all.out
|
||||||
|
|
||||||
test: test-all
|
|
||||||
|
|
||||||
test-geth:
|
test-geth:
|
||||||
build/env.sh go test -v -coverprofile=coverage.out ./geth
|
build/env.sh go test -v -coverprofile=coverage.out ./geth
|
||||||
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
||||||
@build/env.sh go tool cover -func=coverage.out
|
@build/env.sh go tool cover -func=coverage.out
|
||||||
|
|
||||||
|
test-params:
|
||||||
|
build/env.sh go test -v -coverprofile=coverage.out ./geth/params
|
||||||
|
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
||||||
|
@build/env.sh go tool cover -func=coverage.out
|
||||||
|
|
||||||
test-jail:
|
test-jail:
|
||||||
build/env.sh go test -v -coverprofile=coverage.out ./jail
|
build/env.sh go test -v -coverprofile=coverage.out ./geth/jail
|
||||||
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
||||||
@build/env.sh go tool cover -func=coverage.out
|
@build/env.sh go tool cover -func=coverage.out
|
||||||
|
|
||||||
|
@ -83,7 +88,7 @@ test-extkeys:
|
||||||
@build/env.sh go tool cover -func=coverage.out
|
@build/env.sh go tool cover -func=coverage.out
|
||||||
|
|
||||||
test-cmd:
|
test-cmd:
|
||||||
build/env.sh go test -v -coverprofile=coverage.out ./cmd/status
|
build/env.sh go test -v -coverprofile=coverage.out ./cmd/statusd
|
||||||
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
@build/env.sh go tool cover -html=coverage.out -o coverage.html
|
||||||
@build/env.sh go tool cover -func=coverage.out
|
@build/env.sh go tool cover -func=coverage.out
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,5 @@ fi
|
||||||
|
|
||||||
# set gitCommit when running from a Git checkout.
|
# set gitCommit when running from a Git checkout.
|
||||||
if [ -f ".git/HEAD" ]; then
|
if [ -f ".git/HEAD" ]; then
|
||||||
echo "-ldflags '-X github.com/status-im/status-go/geth.UseTestnetFlag=false -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'";
|
echo "-ldflags '-X github.com/status-im/status-go/geth/params.UseMainnetFlag=true -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'";
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -9,5 +9,5 @@ fi
|
||||||
|
|
||||||
# set gitCommit when running from a Git checkout.
|
# set gitCommit when running from a Git checkout.
|
||||||
if [ -f ".git/HEAD" ]; then
|
if [ -f ".git/HEAD" ]; then
|
||||||
echo "-ldflags '-X github.com/status-im/status-go/geth.UseTestnetFlag=true -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'";
|
echo "-ldflags '-X github.com/status-im/status-go/geth/params.UseMainnetFlag=false -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'";
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/status-im/status-go/geth"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
gitCommit = "rely on linker: -ldflags -X main.GitCommit"
|
|
||||||
buildStamp = "rely on linker: -ldflags -X main.buildStamp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
verString := fmt.Sprintf("%d.%d.%d", geth.VersionMajor, geth.VersionMinor, geth.VersionPatch)
|
|
||||||
if geth.VersionMeta != "" {
|
|
||||||
verString += "-" + geth.VersionMeta
|
|
||||||
}
|
|
||||||
if gitCommit != "" {
|
|
||||||
verString += "-" + gitCommit[:8]
|
|
||||||
}
|
|
||||||
netVersion := "mainnet"
|
|
||||||
if geth.UseTestnet {
|
|
||||||
netVersion = "testnet"
|
|
||||||
}
|
|
||||||
fmt.Printf("Status\nGit Commit: %s\nBuild Time: %s\nVersion: %s\nNetwork: %s\n",
|
|
||||||
gitCommit, buildStamp, verString, netVersion)
|
|
||||||
}
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
"github.com/status-im/status-go/jail"
|
"github.com/status-im/status-go/geth/jail"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export CreateAccount
|
//export CreateAccount
|
||||||
|
@ -197,18 +197,29 @@ func DiscardTransactions(ids *C.char) *C.char {
|
||||||
return C.CString(string(outBytes))
|
return C.CString(string(outBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export StartNode
|
//export GenerateConfig
|
||||||
func StartNode(datadir *C.char) *C.char {
|
func GenerateConfig(datadir *C.char, networkId C.int) *C.char {
|
||||||
// This starts a geth node with the given datadir
|
config, err := params.NewNodeConfig(C.GoString(datadir), int(networkId))
|
||||||
err := geth.CreateAndRunNode(&geth.NodeConfig{
|
if err != nil {
|
||||||
DataDir: C.GoString(datadir),
|
return makeJSONErrorResponse(err)
|
||||||
IPCEnabled: false,
|
}
|
||||||
HTTPPort: geth.HTTPPort,
|
|
||||||
WSEnabled: false,
|
|
||||||
WSPort: geth.WSPort,
|
|
||||||
TLSEnabled: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
outBytes, err := json.Marshal(&config)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONErrorResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.CString(string(outBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export StartNode
|
||||||
|
func StartNode(configJSON *C.char) *C.char {
|
||||||
|
config, err := params.LoadNodeConfig(C.GoString(configJSON))
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONErrorResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = geth.CreateAndRunNode(config)
|
||||||
return makeJSONErrorResponse(err)
|
return makeJSONErrorResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,19 +241,6 @@ func ResetChainData() *C.char {
|
||||||
return makeJSONErrorResponse(err)
|
return makeJSONErrorResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export StartTLSNode
|
|
||||||
func StartTLSNode(datadir *C.char) *C.char {
|
|
||||||
// This starts a geth node with the given datadir
|
|
||||||
err := geth.CreateAndRunNode(&geth.NodeConfig{
|
|
||||||
DataDir: C.GoString(datadir),
|
|
||||||
HTTPPort: geth.HTTPPort,
|
|
||||||
WSPort: geth.WSPort,
|
|
||||||
TLSEnabled: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
return makeJSONErrorResponse(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//export StopNodeRPCServer
|
//export StopNodeRPCServer
|
||||||
func StopNodeRPCServer() *C.char {
|
func StopNodeRPCServer() *C.char {
|
||||||
_, err := geth.NodeManagerInstance().StopNodeRPCServer()
|
_, err := geth.NodeManagerInstance().StopNodeRPCServer()
|
||||||
|
@ -297,43 +295,6 @@ func AddPeer(url *C.char) *C.char {
|
||||||
return C.CString(string(outBytes))
|
return C.CString(string(outBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export AddWhisperFilter
|
|
||||||
func AddWhisperFilter(filterJson *C.char) *C.char {
|
|
||||||
|
|
||||||
var id int
|
|
||||||
var filter whisper.NewFilterArgs
|
|
||||||
|
|
||||||
err := json.Unmarshal([]byte(C.GoString(filterJson)), &filter)
|
|
||||||
if err == nil {
|
|
||||||
id = geth.AddWhisperFilter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
errString := ""
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
errString = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
out := geth.AddWhisperFilterResult{
|
|
||||||
Id: id,
|
|
||||||
Error: errString,
|
|
||||||
}
|
|
||||||
outBytes, _ := json.Marshal(&out)
|
|
||||||
|
|
||||||
return C.CString(string(outBytes))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//export RemoveWhisperFilter
|
|
||||||
func RemoveWhisperFilter(idFilter int) {
|
|
||||||
geth.RemoveWhisperFilter(idFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
//export ClearWhisperFilters
|
|
||||||
func ClearWhisperFilters() {
|
|
||||||
geth.ClearWhisperFilters()
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeJSONErrorResponse(err error) *C.char {
|
func makeJSONErrorResponse(err error) *C.char {
|
||||||
errString := ""
|
errString := ""
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -0,0 +1,183 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/geth"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
gitCommit = "rely on linker: -ldflags -X main.GitCommit"
|
||||||
|
buildStamp = "rely on linker: -ldflags -X main.buildStamp"
|
||||||
|
app = makeApp(gitCommit)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DataDirFlag = cli.StringFlag{
|
||||||
|
Name: "datadir",
|
||||||
|
Usage: "Data directory for the databases and keystore",
|
||||||
|
Value: params.DefaultDataDir,
|
||||||
|
}
|
||||||
|
NetworkIdFlag = cli.IntFlag{
|
||||||
|
Name: "networkid",
|
||||||
|
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
|
||||||
|
Value: params.TestNetworkId,
|
||||||
|
}
|
||||||
|
LightEthEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "les",
|
||||||
|
Usage: "LES protocol enabled",
|
||||||
|
}
|
||||||
|
WhisperEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "shh",
|
||||||
|
Usage: "SHH protocol enabled",
|
||||||
|
}
|
||||||
|
SwarmEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "swarm",
|
||||||
|
Usage: "Swarm protocol enabled",
|
||||||
|
}
|
||||||
|
HTTPEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "http",
|
||||||
|
Usage: "HTTP RPC enpoint enabled",
|
||||||
|
}
|
||||||
|
HTTPPortFlag = cli.IntFlag{
|
||||||
|
Name: "httpport",
|
||||||
|
Usage: "HTTP RPC server's listening port",
|
||||||
|
Value: params.DefaultHTTPPort,
|
||||||
|
}
|
||||||
|
IPCEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "ipc",
|
||||||
|
Usage: "IPC RPC enpoint enabled",
|
||||||
|
}
|
||||||
|
LogLevelFlag = cli.StringFlag{
|
||||||
|
Name: "log",
|
||||||
|
Usage: `Log level, one of: ""ERROR", "WARNING", "INFO", "DEBUG", and "DETAIL"`,
|
||||||
|
Value: "INFO",
|
||||||
|
}
|
||||||
|
TestAccountKey = cli.StringFlag{
|
||||||
|
Name: "accountkey",
|
||||||
|
Usage: "Test account PK (will be loaded into accounts cache, and injected to Whisper)",
|
||||||
|
}
|
||||||
|
TestAccountPasswd = cli.StringFlag{
|
||||||
|
Name: "accountpasswd",
|
||||||
|
Usage: "Test account password",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// setup the app
|
||||||
|
app.Action = statusd
|
||||||
|
app.HideVersion = true // separate command prints version
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Action: version,
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Print app version",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
DataDirFlag,
|
||||||
|
NetworkIdFlag,
|
||||||
|
LightEthEnabledFlag,
|
||||||
|
WhisperEnabledFlag,
|
||||||
|
SwarmEnabledFlag,
|
||||||
|
HTTPEnabledFlag,
|
||||||
|
HTTPPortFlag,
|
||||||
|
IPCEnabledFlag,
|
||||||
|
LogLevelFlag,
|
||||||
|
}
|
||||||
|
app.Before = func(ctx *cli.Context) error {
|
||||||
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
app.After = func(ctx *cli.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// statusd runs Status node
|
||||||
|
func statusd(ctx *cli.Context) error {
|
||||||
|
config, err := makeNodeConfig(ctx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "can not parse config: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := geth.CreateAndRunNode(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait till node has been stopped
|
||||||
|
geth.NodeManagerInstance().Node().GethStack().Wait()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeNodeConfig parses incoming CLI options and returns node configuration object
|
||||||
|
func makeNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
||||||
|
nodeConfig, err := params.NewNodeConfig(ctx.GlobalString(DataDirFlag.Name), ctx.GlobalInt(NetworkIdFlag.Name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.GlobalBool(HTTPEnabledFlag.Name) {
|
||||||
|
nodeConfig.HTTPHost = "" // HTTP RPC is disabled
|
||||||
|
}
|
||||||
|
nodeConfig.IPCEnabled = ctx.GlobalBool(IPCEnabledFlag.Name)
|
||||||
|
nodeConfig.LightEthConfig.Enabled = ctx.GlobalBool(LightEthEnabledFlag.Name)
|
||||||
|
nodeConfig.WhisperConfig.Enabled = ctx.GlobalBool(WhisperEnabledFlag.Name)
|
||||||
|
nodeConfig.SwarmConfig.Enabled = ctx.GlobalBool(SwarmEnabledFlag.Name)
|
||||||
|
nodeConfig.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name)
|
||||||
|
|
||||||
|
if logLevel := ctx.GlobalString(LogLevelFlag.Name); len(logLevel) > 0 {
|
||||||
|
nodeConfig.LogEnabled = true
|
||||||
|
nodeConfig.LogLevel = logLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// version displays app version
|
||||||
|
func version(ctx *cli.Context) error {
|
||||||
|
fmt.Println(strings.Title(params.DefaultClientIdentifier))
|
||||||
|
fmt.Println("Version:", params.Version)
|
||||||
|
if gitCommit != "" {
|
||||||
|
fmt.Println("Git Commit:", gitCommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Network Id:", ctx.GlobalInt(NetworkIdFlag.Name))
|
||||||
|
fmt.Println("Go Version:", runtime.Version())
|
||||||
|
fmt.Println("OS:", runtime.GOOS)
|
||||||
|
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
||||||
|
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeApp creates an app with sane defaults.
|
||||||
|
func makeApp(gitCommit string) *cli.App {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = filepath.Base(os.Args[0])
|
||||||
|
app.Author = ""
|
||||||
|
//app.Authors = nil
|
||||||
|
app.Email = ""
|
||||||
|
app.Version = params.Version
|
||||||
|
if gitCommit != "" {
|
||||||
|
app.Version += "-" + gitCommit[:8]
|
||||||
|
}
|
||||||
|
app.Usage = "Status CLI"
|
||||||
|
return app
|
||||||
|
}
|
|
@ -7,25 +7,25 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/les/status"
|
"github.com/ethereum/go-ethereum/les/status"
|
||||||
|
gethparams "github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var testConfig *geth.TestConfig
|
||||||
testDataDir = "../../.ethereumtest"
|
|
||||||
testNodeSyncSeconds = 30
|
func init() {
|
||||||
testAddress = "0xadaf150b905cf5e6a778e553e15a139b6618bbb7"
|
// error is ignored, as it will occur on non-test compilation only, and there testConfig is not used at all
|
||||||
testAddressPassword = "asdfasdf"
|
// (we have to use "main" package due to restrictions on including C imports into *_test packages)
|
||||||
newAccountPassword = "badpassword"
|
testConfig, _ = geth.LoadTestConfig()
|
||||||
testAddress1 = "0xadd4d1d02e71c7360c53296968e59d57fd15e2ba"
|
}
|
||||||
testStatusJsFile = "../../jail/testdata/status.js"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testExportedAPI(t *testing.T, done chan struct{}) {
|
func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||||
<-startTestNode(t)
|
<-startTestNode(t)
|
||||||
|
@ -34,6 +34,10 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||||
name string
|
name string
|
||||||
fn func(t *testing.T) bool
|
fn func(t *testing.T) bool
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
"check default configuration",
|
||||||
|
testGetDefaultConfig,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"reset blockchain data",
|
"reset blockchain data",
|
||||||
testResetChainData,
|
testResetChainData,
|
||||||
|
@ -97,6 +101,97 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testGetDefaultConfig(t *testing.T) bool {
|
||||||
|
// test Mainnet config
|
||||||
|
nodeConfig := params.NodeConfig{}
|
||||||
|
|
||||||
|
rawResponse := GenerateConfig(C.CString("/tmp/data-folder"), 1)
|
||||||
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
|
||||||
|
t.Errorf("cannot decode reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
chainConfig := nodeConfig.ChainConfig
|
||||||
|
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
|
||||||
|
t.Error("invalid chainConfig.HomesteadBlock")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 {
|
||||||
|
t.Error("invalid chainConfig.DAOForkBlock")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkSupport != true {
|
||||||
|
t.Error("invalid chainConfig.DAOForkSupport")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 {
|
||||||
|
t.Error("invalid chainConfig.EIP150Block")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash {
|
||||||
|
t.Error("invalid chainConfig.EIP150Hash")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
|
||||||
|
t.Error("invalid chainConfig.EIP155Block")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
|
||||||
|
t.Error("invalid chainConfig.EIP158Block")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 {
|
||||||
|
t.Error("invalid chainConfig.ChainId")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// test Testnet
|
||||||
|
nodeConfig = params.NodeConfig{}
|
||||||
|
rawResponse = GenerateConfig(C.CString("/tmp/data-folder"), 3)
|
||||||
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
|
||||||
|
t.Errorf("cannot decode reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
chainConfig = nodeConfig.ChainConfig
|
||||||
|
refChainConfig := gethparams.TestnetChainConfig
|
||||||
|
|
||||||
|
if chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock) != 0 {
|
||||||
|
t.Error("invalid chainConfig.HomesteadBlock")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkBlock != nil { // already forked
|
||||||
|
t.Error("invalid chainConfig.DAOForkBlock")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkSupport != refChainConfig.DAOForkSupport {
|
||||||
|
t.Error("invalid chainConfig.DAOForkSupport")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block) != 0 {
|
||||||
|
t.Error("invalid chainConfig.EIP150Block")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Hash != refChainConfig.EIP150Hash {
|
||||||
|
t.Error("invalid chainConfig.EIP150Hash")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block) != 0 {
|
||||||
|
t.Error("invalid chainConfig.EIP155Block")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block) != 0 {
|
||||||
|
t.Error("invalid chainConfig.EIP158Block")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if chainConfig.ChainId.Cmp(refChainConfig.ChainId) != 0 {
|
||||||
|
t.Error("invalid chainConfig.ChainId")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func testResetChainData(t *testing.T) bool {
|
func testResetChainData(t *testing.T) bool {
|
||||||
resetChainDataResponse := geth.JSONError{}
|
resetChainDataResponse := geth.JSONError{}
|
||||||
rawResponse := ResetChainData()
|
rawResponse := ResetChainData()
|
||||||
|
@ -110,7 +205,7 @@ func testResetChainData(t *testing.T) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(testNodeSyncSeconds * time.Second) // allow to re-sync blockchain
|
time.Sleep(testConfig.Node.SyncSeconds * time.Second) // allow to re-sync blockchain
|
||||||
|
|
||||||
testCompleteTransaction(t)
|
testCompleteTransaction(t)
|
||||||
|
|
||||||
|
@ -126,7 +221,7 @@ func testStopResumeNode(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
address1, pubKey1, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -134,13 +229,13 @@ func testStopResumeNode(t *testing.T) bool {
|
||||||
t.Logf("account created: {address: %s, key: %s}", address1, pubKey1)
|
t.Logf("account created: {address: %s, key: %s}", address1, pubKey1)
|
||||||
|
|
||||||
// make sure that identity is not (yet injected)
|
// make sure that identity is not (yet injected)
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
// select account
|
// select account
|
||||||
loginResponse := geth.JSONError{}
|
loginResponse := geth.JSONError{}
|
||||||
rawResponse := Login(C.CString(address1), C.CString(newAccountPassword))
|
rawResponse := Login(C.CString(address1), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -151,7 +246,7 @@ func testStopResumeNode(t *testing.T) bool {
|
||||||
t.Errorf("could not select account: %v", err)
|
t.Errorf("could not select account: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if !whisperService.HasIdentity(pubKey1) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +295,7 @@ func testStopResumeNode(t *testing.T) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("whisper service not running: %v", err)
|
t.Errorf("whisper service not running: %v", err)
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if !whisperService.HasIdentity(pubKey1) {
|
||||||
t.Errorf("identity evicted from whisper on node restart: %v", err)
|
t.Errorf("identity evicted from whisper on node restart: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +340,7 @@ func testRestartNodeRPC(t *testing.T) bool {
|
||||||
t.Errorf("cannot decode StartNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode StartNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
expectedError := "HTTP RPC already running on localhost:8545"
|
expectedError := "HTTP RPC already running on localhost:8645"
|
||||||
if startNodeRPCServerResponse.Error != expectedError {
|
if startNodeRPCServerResponse.Error != expectedError {
|
||||||
t.Errorf("expected error not thrown: %s", expectedError)
|
t.Errorf("expected error not thrown: %s", expectedError)
|
||||||
return false
|
return false
|
||||||
|
@ -265,7 +360,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
createAccountResponse := geth.AccountInfo{}
|
createAccountResponse := geth.AccountInfo{}
|
||||||
rawResponse := CreateAccount(C.CString(newAccountPassword))
|
rawResponse := CreateAccount(C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createAccountResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createAccountResponse); err != nil {
|
||||||
t.Errorf("cannot decode CreateAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode CreateAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -286,7 +381,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
|
// obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
|
||||||
account, key, err := keyStore.AccountDecryptedKey(account, newAccountPassword)
|
account, key, err := keyStore.AccountDecryptedKey(account, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -299,7 +394,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
|
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
|
||||||
createSubAccountResponse := geth.AccountInfo{}
|
createSubAccountResponse := geth.AccountInfo{}
|
||||||
rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword))
|
rawResponse = CreateChildAccount(C.CString(""), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil {
|
||||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -311,7 +406,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
err = geth.SelectAccount(address, newAccountPassword)
|
err = geth.SelectAccount(address, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -333,7 +428,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// create sub-account (from implicit parent)
|
// create sub-account (from implicit parent)
|
||||||
createSubAccountResponse1 := geth.AccountInfo{}
|
createSubAccountResponse1 := geth.AccountInfo{}
|
||||||
rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword))
|
rawResponse = CreateChildAccount(C.CString(""), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse1); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse1); err != nil {
|
||||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -347,7 +442,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// make sure that sub-account index automatically progresses
|
// make sure that sub-account index automatically progresses
|
||||||
createSubAccountResponse2 := geth.AccountInfo{}
|
createSubAccountResponse2 := geth.AccountInfo{}
|
||||||
rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword))
|
rawResponse = CreateChildAccount(C.CString(""), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse2); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse2); err != nil {
|
||||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -365,7 +460,7 @@ func testCreateChildAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// create sub-account (from explicit parent)
|
// create sub-account (from explicit parent)
|
||||||
createSubAccountResponse3 := geth.AccountInfo{}
|
createSubAccountResponse3 := geth.AccountInfo{}
|
||||||
rawResponse = CreateChildAccount(C.CString(createSubAccountResponse2.Address), C.CString(newAccountPassword))
|
rawResponse = CreateChildAccount(C.CString(createSubAccountResponse2.Address), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse3); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse3); err != nil {
|
||||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -391,7 +486,7 @@ func testRecoverAccount(t *testing.T) bool {
|
||||||
keyStore, _ := geth.NodeManagerInstance().AccountKeyStore()
|
keyStore, _ := geth.NodeManagerInstance().AccountKeyStore()
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword)
|
address, pubKey, mnemonic, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -400,7 +495,7 @@ func testRecoverAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// try recovering using password + mnemonic
|
// try recovering using password + mnemonic
|
||||||
recoverAccountResponse := geth.AccountInfo{}
|
recoverAccountResponse := geth.AccountInfo{}
|
||||||
rawResponse := RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic))
|
rawResponse := RecoverAccount(C.CString(testConfig.Account1.Password), C.CString(mnemonic))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -422,19 +517,19 @@ func testRecoverAccount(t *testing.T) bool {
|
||||||
t.Errorf("can not get account from address: %v", err)
|
t.Errorf("can not get account from address: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
account, key, err := keyStore.AccountDecryptedKey(account, newAccountPassword)
|
account, key, err := keyStore.AccountDecryptedKey(account, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
extChild2String := key.ExtendedKey.String()
|
extChild2String := key.ExtendedKey.String()
|
||||||
|
|
||||||
if err := keyStore.Delete(account, newAccountPassword); err != nil {
|
if err := keyStore.Delete(account, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot remove account: %v", err)
|
t.Errorf("cannot remove account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
recoverAccountResponse = geth.AccountInfo{}
|
recoverAccountResponse = geth.AccountInfo{}
|
||||||
rawResponse = RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic))
|
rawResponse = RecoverAccount(C.CString(testConfig.Account1.Password), C.CString(mnemonic))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -451,7 +546,7 @@ func testRecoverAccount(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that extended key exists and is imported ok too
|
// make sure that extended key exists and is imported ok too
|
||||||
account, key, err = keyStore.AccountDecryptedKey(account, newAccountPassword)
|
account, key, err = keyStore.AccountDecryptedKey(account, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -462,7 +557,7 @@ func testRecoverAccount(t *testing.T) bool {
|
||||||
|
|
||||||
// make sure that calling import several times, just returns from cache (no error is expected)
|
// make sure that calling import several times, just returns from cache (no error is expected)
|
||||||
recoverAccountResponse = geth.AccountInfo{}
|
recoverAccountResponse = geth.AccountInfo{}
|
||||||
rawResponse = RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic))
|
rawResponse = RecoverAccount(C.CString(testConfig.Account1.Password), C.CString(mnemonic))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -485,15 +580,15 @@ func testRecoverAccount(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that identity is not (yet injected)
|
// make sure that identity is not (yet injected)
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) {
|
if whisperService.HasIdentity(pubKeyCheck) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
err = geth.SelectAccount(addressCheck, newAccountPassword)
|
err = geth.SelectAccount(addressCheck, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) {
|
if !whisperService.HasIdentity(pubKeyCheck) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,14 +603,14 @@ func testAccountSelect(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
address1, pubKey1, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||||
|
|
||||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
address2, pubKey2, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Test failed: could not create account")
|
t.Error("Test failed: could not create account")
|
||||||
return false
|
return false
|
||||||
|
@ -523,7 +618,7 @@ func testAccountSelect(t *testing.T) bool {
|
||||||
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||||
|
|
||||||
// make sure that identity is not (yet injected)
|
// make sure that identity is not (yet injected)
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,7 +637,7 @@ func testAccountSelect(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
loginResponse = geth.JSONError{}
|
loginResponse = geth.JSONError{}
|
||||||
rawResponse = Login(C.CString(address1), C.CString(newAccountPassword))
|
rawResponse = Login(C.CString(address1), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -553,17 +648,17 @@ func testAccountSelect(t *testing.T) bool {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if !whisperService.HasIdentity(pubKey1) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// select another account, make sure that previous account is wiped out from Whisper cache
|
// select another account, make sure that previous account is wiped out from Whisper cache
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if whisperService.HasIdentity(pubKey2) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
loginResponse = geth.JSONError{}
|
loginResponse = geth.JSONError{}
|
||||||
rawResponse = Login(C.CString(address2), C.CString(newAccountPassword))
|
rawResponse = Login(C.CString(address2), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -574,10 +669,10 @@ func testAccountSelect(t *testing.T) bool {
|
||||||
t.Errorf("Test failed: could not select account: %v", loginResponse.Error)
|
t.Errorf("Test failed: could not select account: %v", loginResponse.Error)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if !whisperService.HasIdentity(pubKey2) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity should be removed, but it is still present in whisper")
|
t.Error("identity should be removed, but it is still present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,25 +687,25 @@ func testAccountLogout(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address, pubKey, _, err := geth.CreateAccount(newAccountPassword)
|
address, pubKey, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that identity doesn't exist (yet) in Whisper
|
// make sure that identity doesn't exist (yet) in Whisper
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
if whisperService.HasIdentity(pubKey) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// select/login
|
// select/login
|
||||||
err = geth.SelectAccount(address, newAccountPassword)
|
err = geth.SelectAccount(address, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
if !whisperService.HasIdentity(pubKey) {
|
||||||
t.Error("identity not injected into whisper")
|
t.Error("identity not injected into whisper")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -629,7 +724,7 @@ func testAccountLogout(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now, logout and check if identity is removed indeed
|
// now, logout and check if identity is removed indeed
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
if whisperService.HasIdentity(pubKey) {
|
||||||
t.Error("identity not cleared from whisper")
|
t.Error("identity not cleared from whisper")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -650,8 +745,8 @@ func testCompleteTransaction(t *testing.T) bool {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,11 +765,10 @@ func testCompleteTransaction(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
t.Logf("transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
completeTxResponse := geth.CompleteTransactionResult{}
|
completeTxResponse := geth.CompleteTransactionResult{}
|
||||||
rawResponse := CompleteTransaction(C.CString(event["id"].(string)), C.CString(testAddressPassword))
|
rawResponse := CompleteTransaction(C.CString(event["id"].(string)), C.CString(testConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &completeTxResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &completeTxResponse); err != nil {
|
||||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||||
|
@ -694,8 +788,8 @@ func testCompleteTransaction(t *testing.T) bool {
|
||||||
|
|
||||||
// this call blocks, up until Complete Transaction is called
|
// this call blocks, up until Complete Transaction is called
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -735,8 +829,8 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,8 +859,8 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -789,7 +883,7 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
|
||||||
updatedTxIdStrings, _ := json.Marshal(parsedIds)
|
updatedTxIdStrings, _ := json.Marshal(parsedIds)
|
||||||
|
|
||||||
// complete
|
// complete
|
||||||
resultsString := CompleteTransactions(C.CString(string(updatedTxIdStrings)), C.CString(testAddressPassword))
|
resultsString := CompleteTransactions(C.CString(string(updatedTxIdStrings)), C.CString(testConfig.Account1.Password))
|
||||||
resultsStruct := geth.CompleteTransactionsResult{}
|
resultsStruct := geth.CompleteTransactionsResult{}
|
||||||
json.Unmarshal([]byte(C.GoString(resultsString)), &resultsStruct)
|
json.Unmarshal([]byte(C.GoString(resultsString)), &resultsStruct)
|
||||||
results := resultsStruct.Results
|
results := resultsStruct.Results
|
||||||
|
@ -870,8 +964,8 @@ func testDiscardTransaction(t *testing.T) bool {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,7 +1006,7 @@ func testDiscardTransaction(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
_, err = geth.CompleteTransaction(txId, testAddressPassword)
|
_, err = geth.CompleteTransaction(txId, testConfig.Account1.Password)
|
||||||
if err.Error() != "transaction hash not found" {
|
if err.Error() != "transaction hash not found" {
|
||||||
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
||||||
return
|
return
|
||||||
|
@ -950,8 +1044,8 @@ func testDiscardTransaction(t *testing.T) bool {
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != status.ErrQueuedTxDiscarded {
|
if err != status.ErrQueuedTxDiscarded {
|
||||||
|
@ -990,8 +1084,8 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1049,8 +1143,8 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != status.ErrQueuedTxDiscarded {
|
if err != status.ErrQueuedTxDiscarded {
|
||||||
|
@ -1084,7 +1178,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
completeResultsString := CompleteTransactions(C.CString(string(updatedTxIdStrings)), C.CString(testAddressPassword))
|
completeResultsString := CompleteTransactions(C.CString(string(updatedTxIdStrings)), C.CString(testConfig.Account1.Password))
|
||||||
completeResultsStruct := geth.CompleteTransactionsResult{}
|
completeResultsStruct := geth.CompleteTransactionsResult{}
|
||||||
json.Unmarshal([]byte(C.GoString(completeResultsString)), &completeResultsStruct)
|
json.Unmarshal([]byte(C.GoString(completeResultsString)), &completeResultsStruct)
|
||||||
completeResults := completeResultsStruct.Results
|
completeResults := completeResultsStruct.Results
|
||||||
|
@ -1178,7 +1272,7 @@ func testJailFunctionCall(t *testing.T) bool {
|
||||||
InitJail(C.CString(""))
|
InitJail(C.CString(""))
|
||||||
|
|
||||||
// load Status JS and add test command to it
|
// load Status JS and add test command to it
|
||||||
statusJS := geth.LoadFromFile(testStatusJsFile) + `;
|
statusJS := geth.LoadFromFile(filepath.Join(geth.RootDir, "geth/jail/testdata/status.js")) + `;
|
||||||
_status_catalog.commands["testCommand"] = function (params) {
|
_status_catalog.commands["testCommand"] = function (params) {
|
||||||
return params.val * params.val;
|
return params.val * params.val;
|
||||||
};`
|
};`
|
||||||
|
@ -1209,10 +1303,34 @@ func testJailFunctionCall(t *testing.T) bool {
|
||||||
|
|
||||||
func startTestNode(t *testing.T) <-chan struct{} {
|
func startTestNode(t *testing.T) <-chan struct{} {
|
||||||
syncRequired := false
|
syncRequired := false
|
||||||
if _, err := os.Stat(filepath.Join(testDataDir, "testnet")); os.IsNotExist(err) {
|
if _, err := os.Stat(geth.TestDataDir); os.IsNotExist(err) {
|
||||||
syncRequired = true
|
syncRequired = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare node directory
|
||||||
|
if err := os.MkdirAll(filepath.Join(geth.TestDataDir, "testnet", "keystore"), os.ModePerm); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// import test account (with test ether on it)
|
||||||
|
importTestAccount := func(accountFile string) error {
|
||||||
|
dst := filepath.Join(geth.TestDataDir, "keystore", accountFile)
|
||||||
|
if _, err := os.Stat(dst); os.IsNotExist(err) {
|
||||||
|
err = geth.CopyFile(dst, filepath.Join(geth.RootDir, "data", accountFile))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := importTestAccount("test-account1.pk"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := importTestAccount("test-account2.pk"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
waitForNodeStart := make(chan struct{}, 1)
|
waitForNodeStart := make(chan struct{}, 1)
|
||||||
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
||||||
t.Log(jsonEvent)
|
t.Log(jsonEvent)
|
||||||
|
@ -1234,8 +1352,8 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
||||||
|
|
||||||
// sync
|
// sync
|
||||||
if syncRequired {
|
if syncRequired {
|
||||||
t.Logf("Sync is required, it will take %d seconds", testNodeSyncSeconds)
|
t.Logf("Sync is required, it will take %d seconds", testConfig.Node.SyncSeconds)
|
||||||
time.Sleep(testNodeSyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done
|
time.Sleep(testConfig.Node.SyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done
|
||||||
} else {
|
} else {
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
}
|
}
|
||||||
|
@ -1246,12 +1364,20 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
||||||
})
|
})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
response := StartNode(C.CString(testDataDir))
|
configJSON := `{
|
||||||
|
"NetworkId": ` + strconv.Itoa(params.TestNetworkId) + `,
|
||||||
|
"DataDir": "` + geth.TestDataDir + `",
|
||||||
|
"HTTPPort": ` + strconv.Itoa(testConfig.Node.HTTPPort) + `,
|
||||||
|
"WSPort": ` + strconv.Itoa(testConfig.Node.WSPort) + `,
|
||||||
|
"LogEnabled": true,
|
||||||
|
"LogLevel": "INFO"
|
||||||
|
}`
|
||||||
|
response := StartNode(C.CString(configJSON))
|
||||||
err := geth.JSONError{}
|
err := geth.JSONError{}
|
||||||
|
|
||||||
json.Unmarshal([]byte(C.GoString(response)), &err)
|
json.Unmarshal([]byte(C.GoString(response)), &err)
|
||||||
if err.Error != "" {
|
if err.Error != "" {
|
||||||
t.Error("cannot start node")
|
panic("cannot start node: " + err.Error)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"address":"65c01586aa0ce152835c788ace665e91ab3527b8","crypto":{"cipher":"aes-128-ctr","ciphertext":"26155f5c315492ccb40f24aeb34ff6bfbdbdcb7402b9e7bb558fa4c936be51ff","cipherparams":{"iv":"1d9b3043b59c3995c410f82cd96bfe05"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"4bb6d2080121e7ecc8b3dcba95cd0031cf3b36174612247c14486266580ed4b8"},"mac":"cc8f209d9128a4e9a836c691324e1459d4d3d2a2b0627cf94e99a7e8b305b6dc"},"id":"756c215e-d3af-435d-8fcf-39eb62d9a590","version":3,"whisperenabled":true,"extendedkey":{"cipher":"aes-128-ctr","ciphertext":"dd5cc47cde930bdb9a1625ff2efd230bac9a52e9d7e220aa699c017c4ac1ff645765a721ac6f4143ffa551ecf775f20b25e7cd5d3856ef59e7f31d407bf2d0404f2323919101c37c94952fb8462d4281a92b005e9f81a6dd1aff2f4eb15cb4c6a56df907c9591503c7d89b0cea08cb","cipherparams":{"iv":"f66b414b6678816bc3e5bb214624b4f7"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"094ba4f65bac68f8a9807871187dd915540013a0792bf3d11d019ae3cea7d7c0"},"mac":"2e2979943a75cff762480c26b3daff0fac78cdf12e0ed791e6a1321f3ed8fc91"},"subaccountindex":0}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"Node": {
|
||||||
|
"SyncSeconds": 90,
|
||||||
|
"HTTPPort": 8645,
|
||||||
|
"WSPort": 8646
|
||||||
|
},
|
||||||
|
"Account1": {
|
||||||
|
"Address": "0xadaf150b905cf5e6a778e553e15a139b6618bbb7",
|
||||||
|
"Password": "asdfasdf"
|
||||||
|
},
|
||||||
|
"Account2": {
|
||||||
|
"Address": "0x65c01586aa0ce152835c788ace665e91ab3527b8",
|
||||||
|
"Password": "asdfasdf"
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +29,7 @@ func TestAccountsList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address, _, _, err := geth.CreateAccount(newAccountPassword)
|
address, _, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -45,7 +43,7 @@ func TestAccountsList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// select account (sub-accounts will be created for this key)
|
// select account (sub-accounts will be created for this key)
|
||||||
err = geth.SelectAccount(address, newAccountPassword)
|
err = geth.SelectAccount(address, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -63,7 +61,7 @@ func TestAccountsList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create sub-account 1
|
// create sub-account 1
|
||||||
subAccount1, subPubKey1, err := geth.CreateChildAccount("", newAccountPassword)
|
subAccount1, subPubKey1, err := geth.CreateChildAccount("", testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot create sub-account: %v", err)
|
t.Errorf("cannot create sub-account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -86,7 +84,7 @@ func TestAccountsList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create sub-account 2, index automatically progresses
|
// create sub-account 2, index automatically progresses
|
||||||
subAccount2, subPubKey2, err := geth.CreateChildAccount("", newAccountPassword)
|
subAccount2, subPubKey2, err := geth.CreateChildAccount("", testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot create sub-account: %v", err)
|
t.Errorf("cannot create sub-account: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -120,7 +118,7 @@ func TestAccountsList(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateChildAccount(t *testing.T) {
|
func TestAccountsCreateChildAccount(t *testing.T) {
|
||||||
err := geth.PrepareTestNode()
|
err := geth.PrepareTestNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -136,7 +134,7 @@ func TestCreateChildAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword)
|
address, pubKey, mnemonic, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -150,7 +148,7 @@ func TestCreateChildAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
|
// obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
|
||||||
account, key, err := keyStore.AccountDecryptedKey(account, newAccountPassword)
|
account, key, err := keyStore.AccountDecryptedKey(account, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -162,13 +160,13 @@ func TestCreateChildAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
|
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
|
||||||
_, _, err = geth.CreateChildAccount("", newAccountPassword)
|
_, _, err = geth.CreateChildAccount("", testConfig.Account1.Password)
|
||||||
if !reflect.DeepEqual(err, geth.ErrNoAccountSelected) {
|
if !reflect.DeepEqual(err, geth.ErrNoAccountSelected) {
|
||||||
t.Errorf("expected error is not returned (tried to create sub-account w/o login): %v", err)
|
t.Errorf("expected error is not returned (tried to create sub-account w/o login): %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = geth.SelectAccount(address, newAccountPassword)
|
err = geth.SelectAccount(address, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -182,14 +180,14 @@ func TestCreateChildAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create sub-account (from implicit parent)
|
// create sub-account (from implicit parent)
|
||||||
subAccount1, subPubKey1, err := geth.CreateChildAccount("", newAccountPassword)
|
subAccount1, subPubKey1, err := geth.CreateChildAccount("", testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot create sub-account: %v", err)
|
t.Errorf("cannot create sub-account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that sub-account index automatically progresses
|
// make sure that sub-account index automatically progresses
|
||||||
subAccount2, subPubKey2, err := geth.CreateChildAccount("", newAccountPassword)
|
subAccount2, subPubKey2, err := geth.CreateChildAccount("", testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot create sub-account: %v", err)
|
t.Errorf("cannot create sub-account: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -199,7 +197,7 @@ func TestCreateChildAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create sub-account (from explicit parent)
|
// create sub-account (from explicit parent)
|
||||||
subAccount3, subPubKey3, err := geth.CreateChildAccount(subAccount2, newAccountPassword)
|
subAccount3, subPubKey3, err := geth.CreateChildAccount(subAccount2, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot create sub-account: %v", err)
|
t.Errorf("cannot create sub-account: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -209,7 +207,7 @@ func TestCreateChildAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecoverAccount(t *testing.T) {
|
func TestAccountsRecoverAccount(t *testing.T) {
|
||||||
err := geth.PrepareTestNode()
|
err := geth.PrepareTestNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -219,7 +217,7 @@ func TestRecoverAccount(t *testing.T) {
|
||||||
keyStore, _ := geth.NodeManagerInstance().AccountKeyStore()
|
keyStore, _ := geth.NodeManagerInstance().AccountKeyStore()
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword)
|
address, pubKey, mnemonic, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -227,7 +225,7 @@ func TestRecoverAccount(t *testing.T) {
|
||||||
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||||
|
|
||||||
// try recovering using password + mnemonic
|
// try recovering using password + mnemonic
|
||||||
addressCheck, pubKeyCheck, err := geth.RecoverAccount(newAccountPassword, mnemonic)
|
addressCheck, pubKeyCheck, err := geth.RecoverAccount(testConfig.Account1.Password, mnemonic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("recover account failed: %v", err)
|
t.Errorf("recover account failed: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -242,18 +240,18 @@ func TestRecoverAccount(t *testing.T) {
|
||||||
t.Errorf("can not get account from address: %v", err)
|
t.Errorf("can not get account from address: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
account, key, err := keyStore.AccountDecryptedKey(account, newAccountPassword)
|
account, key, err := keyStore.AccountDecryptedKey(account, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
extChild2String := key.ExtendedKey.String()
|
extChild2String := key.ExtendedKey.String()
|
||||||
|
|
||||||
if err := keyStore.Delete(account, newAccountPassword); err != nil {
|
if err := keyStore.Delete(account, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot remove account: %v", err)
|
t.Errorf("cannot remove account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
addressCheck, pubKeyCheck, err = geth.RecoverAccount(newAccountPassword, mnemonic)
|
addressCheck, pubKeyCheck, err = geth.RecoverAccount(testConfig.Account1.Password, mnemonic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("recover account failed (for non-cached account): %v", err)
|
t.Errorf("recover account failed (for non-cached account): %v", err)
|
||||||
return
|
return
|
||||||
|
@ -263,7 +261,7 @@ func TestRecoverAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that extended key exists and is imported ok too
|
// make sure that extended key exists and is imported ok too
|
||||||
account, key, err = keyStore.AccountDecryptedKey(account, newAccountPassword)
|
account, key, err = keyStore.AccountDecryptedKey(account, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -273,7 +271,7 @@ func TestRecoverAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that calling import several times, just returns from cache (no error is expected)
|
// make sure that calling import several times, just returns from cache (no error is expected)
|
||||||
addressCheck, pubKeyCheck, err = geth.RecoverAccount(newAccountPassword, mnemonic)
|
addressCheck, pubKeyCheck, err = geth.RecoverAccount(testConfig.Account1.Password, mnemonic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("recover account failed (for non-cached account): %v", err)
|
t.Errorf("recover account failed (for non-cached account): %v", err)
|
||||||
return
|
return
|
||||||
|
@ -289,15 +287,15 @@ func TestRecoverAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that identity is not (yet injected)
|
// make sure that identity is not (yet injected)
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) {
|
if whisperService.HasIdentity(pubKeyCheck) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
err = geth.SelectAccount(addressCheck, newAccountPassword)
|
err = geth.SelectAccount(addressCheck, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) {
|
if !whisperService.HasIdentity(pubKeyCheck) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,14 +315,14 @@ func TestAccountSelect(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
address1, pubKey1, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||||
|
|
||||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
address2, pubKey2, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Test failed: could not create account")
|
t.Error("Test failed: could not create account")
|
||||||
return
|
return
|
||||||
|
@ -332,7 +330,7 @@ func TestAccountSelect(t *testing.T) {
|
||||||
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||||
|
|
||||||
// make sure that identity is not (yet injected)
|
// make sure that identity is not (yet injected)
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,33 +340,33 @@ func TestAccountSelect(t *testing.T) {
|
||||||
t.Error("select account is expected to throw error: wrong password used")
|
t.Error("select account is expected to throw error: wrong password used")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = geth.SelectAccount(address1, newAccountPassword)
|
err = geth.SelectAccount(address1, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if !whisperService.HasIdentity(pubKey1) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// select another account, make sure that previous account is wiped out from Whisper cache
|
// select another account, make sure that previous account is wiped out from Whisper cache
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if whisperService.HasIdentity(pubKey2) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
err = geth.SelectAccount(address2, newAccountPassword)
|
err = geth.SelectAccount(address2, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if !whisperService.HasIdentity(pubKey2) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity should be removed, but it is still present in whisper")
|
t.Error("identity should be removed, but it is still present in whisper")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountLogout(t *testing.T) {
|
func TestAccountsLogout(t *testing.T) {
|
||||||
|
|
||||||
err := geth.PrepareTestNode()
|
err := geth.PrepareTestNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -382,24 +380,24 @@ func TestAccountLogout(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
address, pubKey, _, err := geth.CreateAccount(newAccountPassword)
|
address, pubKey, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that identity doesn't exist (yet) in Whisper
|
// make sure that identity doesn't exist (yet) in Whisper
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
if whisperService.HasIdentity(pubKey) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
// select/login
|
// select/login
|
||||||
err = geth.SelectAccount(address, newAccountPassword)
|
err = geth.SelectAccount(address, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
if !whisperService.HasIdentity(pubKey) {
|
||||||
t.Error("identity not injected into whisper")
|
t.Error("identity not injected into whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,12 +407,12 @@ func TestAccountLogout(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now, logout and check if identity is removed indeed
|
// now, logout and check if identity is removed indeed
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
if whisperService.HasIdentity(pubKey) {
|
||||||
t.Error("identity not cleared from whisper")
|
t.Error("identity not cleared from whisper")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectedAccountOnNodeRestart(t *testing.T) {
|
func TestAccountsSelectedAccountOnNodeRestart(t *testing.T) {
|
||||||
err := geth.PrepareTestNode()
|
err := geth.PrepareTestNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -428,13 +426,13 @@ func TestSelectedAccountOnNodeRestart(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create test accounts
|
// create test accounts
|
||||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
address1, pubKey1, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.Logf("account1 created: {address: %s, key: %s}", address1, pubKey1)
|
t.Logf("account1 created: {address: %s, key: %s}", address1, pubKey1)
|
||||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
address2, pubKey2, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -442,7 +440,7 @@ func TestSelectedAccountOnNodeRestart(t *testing.T) {
|
||||||
t.Logf("account2 created: {address: %s, key: %s}", address2, pubKey2)
|
t.Logf("account2 created: {address: %s, key: %s}", address2, pubKey2)
|
||||||
|
|
||||||
// make sure that identity is not (yet injected)
|
// make sure that identity is not (yet injected)
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,28 +456,28 @@ func TestSelectedAccountOnNodeRestart(t *testing.T) {
|
||||||
t.Error("select account is expected to throw error: wrong password used")
|
t.Error("select account is expected to throw error: wrong password used")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = geth.SelectAccount(address1, newAccountPassword)
|
err = geth.SelectAccount(address1, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not select account: %v", err)
|
t.Errorf("could not select account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if !whisperService.HasIdentity(pubKey1) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// select another account, make sure that previous account is wiped out from Whisper cache
|
// select another account, make sure that previous account is wiped out from Whisper cache
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if whisperService.HasIdentity(pubKey2) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
err = geth.SelectAccount(address2, newAccountPassword)
|
err = geth.SelectAccount(address2, testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
t.Errorf("Test failed: could not select account: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if !whisperService.HasIdentity(pubKey2) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity should be removed, but it is still present in whisper")
|
t.Error("identity should be removed, but it is still present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,15 +518,15 @@ func TestSelectedAccountOnNodeRestart(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("whisper service not running: %v", err)
|
t.Errorf("whisper service not running: %v", err)
|
||||||
}
|
}
|
||||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
if !whisperService.HasIdentity(pubKey2) {
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
t.Errorf("identity not injected into whisper: %v", err)
|
||||||
}
|
}
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity should not be present, but it is still present in whisper")
|
t.Error("identity should not be present, but it is still present in whisper")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeRestartWithNoSelectedAccount(t *testing.T) {
|
func TestAccountsNodeRestartWithNoSelectedAccount(t *testing.T) {
|
||||||
err := geth.PrepareTestNode()
|
err := geth.PrepareTestNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -544,7 +542,7 @@ func TestNodeRestartWithNoSelectedAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create test accounts
|
// create test accounts
|
||||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
address1, pubKey1, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -552,7 +550,7 @@ func TestNodeRestartWithNoSelectedAccount(t *testing.T) {
|
||||||
t.Logf("account1 created: {address: %s, key: %s}", address1, pubKey1)
|
t.Logf("account1 created: {address: %s, key: %s}", address1, pubKey1)
|
||||||
|
|
||||||
// make sure that identity is not present
|
// make sure that identity is not present
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity already present in whisper")
|
t.Error("identity already present in whisper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,7 +589,7 @@ func TestNodeRestartWithNoSelectedAccount(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("whisper service not running: %v", err)
|
t.Errorf("whisper service not running: %v", err)
|
||||||
}
|
}
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
if whisperService.HasIdentity(pubKey1) {
|
||||||
t.Error("identity should not be present, but it is present in whisper")
|
t.Error("identity should not be present, but it is present in whisper")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package jail_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -9,22 +10,42 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
"github.com/status-im/status-go/jail"
|
"github.com/status-im/status-go/geth/jail"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TEST_ADDRESS = "0xadaf150b905cf5e6a778e553e15a139b6618bbb7"
|
whisperMessage1 = `test message 1 (K1 -> K2, signed+encrypted, from us)`
|
||||||
TEST_ADDRESS_PASSWORD = "asdfasdf"
|
whisperMessage2 = `test message 2 (K1 -> K1, signed+encrypted to ourselves)`
|
||||||
CHAT_ID_INIT = "CHAT_ID_INIT_TEST"
|
whisperMessage3 = `test message 3 (K1 -> "", signed broadcast)`
|
||||||
CHAT_ID_CALL = "CHAT_ID_CALL_TEST"
|
whisperMessage4 = `test message 4 ("" -> "", anon broadcast)`
|
||||||
CHAT_ID_SEND = "CHAT_ID_CALL_SEND"
|
whisperMessage5 = `test message 5 ("" -> K1, encrypted anon broadcast)`
|
||||||
CHAT_ID_NON_EXISTENT = "CHAT_IDNON_EXISTENT"
|
whisperMessage6 = `test message 6 (K2 -> K1, signed+encrypted, to us)`
|
||||||
|
chatID = "testChat"
|
||||||
TESTDATA_STATUS_JS = "testdata/status.js"
|
statusJSFilePath = "testdata/status.js"
|
||||||
TESTDATA_TX_SEND_JS = "testdata/tx-send/"
|
txSendFolder = "testdata/tx-send/"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var testConfig *geth.TestConfig
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// load shared test configuration
|
||||||
|
var err error
|
||||||
|
testConfig, err = geth.LoadTestConfig()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run tests
|
||||||
|
retCode := m.Run()
|
||||||
|
|
||||||
|
//time.Sleep(25 * time.Second) // to give some time to propagate txs to the rest of the network
|
||||||
|
os.Exit(retCode)
|
||||||
|
}
|
||||||
|
|
||||||
func TestJailUnInited(t *testing.T) {
|
func TestJailUnInited(t *testing.T) {
|
||||||
errorWrapper := func(err error) string {
|
errorWrapper := func(err error) string {
|
||||||
return `{"error":"` + err.Error() + `"}`
|
return `{"error":"` + err.Error() + `"}`
|
||||||
|
@ -33,17 +54,17 @@ func TestJailUnInited(t *testing.T) {
|
||||||
expectedError := errorWrapper(jail.ErrInvalidJail)
|
expectedError := errorWrapper(jail.ErrInvalidJail)
|
||||||
|
|
||||||
var jailInstance *jail.Jail
|
var jailInstance *jail.Jail
|
||||||
response := jailInstance.Parse(CHAT_ID_CALL, ``)
|
response := jailInstance.Parse(chatID, ``)
|
||||||
if response != expectedError {
|
if response != expectedError {
|
||||||
t.Errorf("error expected, but got: %v", response)
|
t.Errorf("error expected, but got: %v", response)
|
||||||
}
|
}
|
||||||
|
|
||||||
response = jailInstance.Call(CHAT_ID_CALL, `["commands", "testCommand"]`, `{"val": 12}`)
|
response = jailInstance.Call(chatID, `["commands", "testCommand"]`, `{"val": 12}`)
|
||||||
if response != expectedError {
|
if response != expectedError {
|
||||||
t.Errorf("error expected, but got: %v", response)
|
t.Errorf("error expected, but got: %v", response)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := jailInstance.GetVM(CHAT_ID_CALL)
|
_, err := jailInstance.GetVM(chatID)
|
||||||
if err != jail.ErrInvalidJail {
|
if err != jail.ErrInvalidJail {
|
||||||
t.Errorf("error expected, but got: %v", err)
|
t.Errorf("error expected, but got: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -59,18 +80,18 @@ func TestJailUnInited(t *testing.T) {
|
||||||
t.Error("jail instance shouldn't be nil at this point")
|
t.Error("jail instance shouldn't be nil at this point")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
statusJS := geth.LoadFromFile(TESTDATA_STATUS_JS) + `;
|
statusJS := geth.LoadFromFile(statusJSFilePath) + `;
|
||||||
_status_catalog.commands["testCommand"] = function (params) {
|
_status_catalog.commands["testCommand"] = function (params) {
|
||||||
return params.val * params.val;
|
return params.val * params.val;
|
||||||
};`
|
};`
|
||||||
response = jailInstance.Parse(CHAT_ID_CALL, statusJS)
|
response = jailInstance.Parse(chatID, statusJS)
|
||||||
expectedResponse := `{"result": {"commands":{},"responses":{}}}`
|
expectedResponse := `{"result": {"commands":{},"responses":{}}}`
|
||||||
if response != expectedResponse {
|
if response != expectedResponse {
|
||||||
t.Errorf("unexpected response received: %v", response)
|
t.Errorf("unexpected response received: %v", response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// however, we still expect issue voiced if somebody tries to execute code with Call
|
// however, we still expect issue voiced if somebody tries to execute code with Call
|
||||||
response = jailInstance.Call(CHAT_ID_CALL, `["commands", "testCommand"]`, `{"val": 12}`)
|
response = jailInstance.Call(chatID, `["commands", "testCommand"]`, `{"val": 12}`)
|
||||||
if response != errorWrapper(geth.ErrInvalidGethNode) {
|
if response != errorWrapper(geth.ErrInvalidGethNode) {
|
||||||
t.Errorf("error expected, but got: %v", response)
|
t.Errorf("error expected, but got: %v", response)
|
||||||
}
|
}
|
||||||
|
@ -81,7 +102,7 @@ func TestJailUnInited(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response = jailInstance.Call(CHAT_ID_CALL, `["commands", "testCommand"]`, `{"val": 12}`)
|
response = jailInstance.Call(chatID, `["commands", "testCommand"]`, `{"val": 12}`)
|
||||||
expectedResponse = `{"result": 144}`
|
expectedResponse = `{"result": 144}`
|
||||||
if response != expectedResponse {
|
if response != expectedResponse {
|
||||||
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, response)
|
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, response)
|
||||||
|
@ -108,7 +129,7 @@ func TestJailInit(t *testing.T) {
|
||||||
return x * x;
|
return x * x;
|
||||||
};
|
};
|
||||||
`
|
`
|
||||||
response := jailInstance.Parse(CHAT_ID_INIT, extraCode)
|
response := jailInstance.Parse("newChat", extraCode)
|
||||||
|
|
||||||
expectedResponse := `{"result": {"foo":"bar"}}`
|
expectedResponse := `{"result": {"foo":"bar"}}`
|
||||||
|
|
||||||
|
@ -128,22 +149,22 @@ func TestJailFunctionCall(t *testing.T) {
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
|
|
||||||
// load Status JS and add test command to it
|
// load Status JS and add test command to it
|
||||||
statusJS := geth.LoadFromFile(TESTDATA_STATUS_JS) + `;
|
statusJS := geth.LoadFromFile(statusJSFilePath) + `;
|
||||||
_status_catalog.commands["testCommand"] = function (params) {
|
_status_catalog.commands["testCommand"] = function (params) {
|
||||||
return params.val * params.val;
|
return params.val * params.val;
|
||||||
};`
|
};`
|
||||||
jailInstance.Parse(CHAT_ID_CALL, statusJS)
|
jailInstance.Parse(chatID, statusJS)
|
||||||
|
|
||||||
// call with wrong chat id
|
// call with wrong chat id
|
||||||
response := jailInstance.Call(CHAT_ID_NON_EXISTENT, "", "")
|
response := jailInstance.Call("chatIdNonExistent", "", "")
|
||||||
expectedError := `{"error":"Cell[CHAT_IDNON_EXISTENT] doesn't exist."}`
|
expectedError := `{"error":"Cell[chatIdNonExistent] doesn't exist."}`
|
||||||
if response != expectedError {
|
if response != expectedError {
|
||||||
t.Errorf("expected error is not returned: expected %s, got %s", expectedError, response)
|
t.Errorf("expected error is not returned: expected %s, got %s", expectedError, response)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// call extraFunc()
|
// call extraFunc()
|
||||||
response = jailInstance.Call(CHAT_ID_CALL, `["commands", "testCommand"]`, `{"val": 12}`)
|
response = jailInstance.Call(chatID, `["commands", "testCommand"]`, `{"val": 12}`)
|
||||||
expectedResponse := `{"result": 144}`
|
expectedResponse := `{"result": 144}`
|
||||||
if response != expectedResponse {
|
if response != expectedResponse {
|
||||||
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, response)
|
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, response)
|
||||||
|
@ -161,11 +182,11 @@ func TestJailRPCSend(t *testing.T) {
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
|
|
||||||
// load Status JS and add test command to it
|
// load Status JS and add test command to it
|
||||||
statusJS := geth.LoadFromFile(TESTDATA_STATUS_JS)
|
statusJS := geth.LoadFromFile(statusJSFilePath)
|
||||||
jailInstance.Parse(CHAT_ID_CALL, statusJS)
|
jailInstance.Parse(chatID, statusJS)
|
||||||
|
|
||||||
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
||||||
vm, err := jailInstance.GetVM(CHAT_ID_CALL)
|
vm, err := jailInstance.GetVM(chatID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot get VM: %v", err)
|
t.Errorf("cannot get VM: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -174,7 +195,7 @@ func TestJailRPCSend(t *testing.T) {
|
||||||
// internally (since we replaced `web3.send` with `jail.Send`)
|
// internally (since we replaced `web3.send` with `jail.Send`)
|
||||||
// all requests to web3 are forwarded to `jail.Send`
|
// all requests to web3 are forwarded to `jail.Send`
|
||||||
_, err = vm.Run(`
|
_, err = vm.Run(`
|
||||||
var balance = web3.eth.getBalance("` + TEST_ADDRESS + `");
|
var balance = web3.eth.getBalance("` + testConfig.Account1.Address + `");
|
||||||
var sendResult = web3.fromWei(balance, "ether")
|
var sendResult = web3.fromWei(balance, "ether")
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -199,7 +220,7 @@ func TestJailRPCSend(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Balance of %.2f ETH found on '%s' account", balance, TEST_ADDRESS)
|
t.Logf("Balance of %.2f ETH found on '%s' account", balance, testConfig.Account1.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJailSendQueuedTransaction(t *testing.T) {
|
func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
|
@ -210,13 +231,13 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(TEST_ADDRESS, TEST_ADDRESS_PASSWORD); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", TEST_ADDRESS)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
txParams := `{
|
txParams := `{
|
||||||
"from": "` + TEST_ADDRESS + `",
|
"from": "` + testConfig.Account1.Address + `",
|
||||||
"to": "0xf82da7547534045b4e00442bc89e16186cf8c272",
|
"to": "0xf82da7547534045b4e00442bc89e16186cf8c272",
|
||||||
"value": "0.000001"
|
"value": "0.000001"
|
||||||
}`
|
}`
|
||||||
|
@ -251,11 +272,10 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Logf("Transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
var txHash common.Hash
|
var txHash common.Hash
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), TEST_ADDRESS_PASSWORD); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Transaction complete: https://testnet.etherscan.io/tx/%s", txHash.Hex())
|
t.Logf("Transaction complete: https://testnet.etherscan.io/tx/%s", txHash.Hex())
|
||||||
|
@ -293,7 +313,7 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`["commands", "getBalance"]`,
|
`["commands", "getBalance"]`,
|
||||||
`{"address": "` + TEST_ADDRESS + `"}`,
|
`{"address": "` + testConfig.Account1.Address + `"}`,
|
||||||
`{"result": {"balance":42}}`,
|
`{"result": {"balance":42}}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -311,7 +331,7 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`["commands", "getBalance"]`,
|
`["commands", "getBalance"]`,
|
||||||
`{"address": "` + TEST_ADDRESS + `"}`,
|
`{"address": "` + testConfig.Account1.Address + `"}`,
|
||||||
`{"result": {"context":{},"result":{"balance":42}}}`, // note emtpy (but present) context!
|
`{"result": {"context":{},"result":{"balance":42}}}`, // note emtpy (but present) context!
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -329,7 +349,7 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`["commands", "getBalance"]`,
|
`["commands", "getBalance"]`,
|
||||||
`{"address": "` + TEST_ADDRESS + `"}`,
|
`{"address": "` + testConfig.Account1.Address + `"}`,
|
||||||
`{"result": {"balance":42}}`, // note emtpy context!
|
`{"result": {"balance":42}}`, // note emtpy context!
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -347,7 +367,7 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`["commands", "getBalance"]`,
|
`["commands", "getBalance"]`,
|
||||||
`{"address": "` + TEST_ADDRESS + `"}`,
|
`{"address": "` + testConfig.Account1.Address + `"}`,
|
||||||
`{"result": {"context":{"message_id":"42"},"result":{"balance":42}}}`, // message id in context, but default one is used!
|
`{"result": {"context":{"message_id":"42"},"result":{"balance":42}}}`, // message id in context, but default one is used!
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -355,16 +375,16 @@ func TestJailSendQueuedTransaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
jailInstance := jail.Init(geth.LoadFromFile(TESTDATA_TX_SEND_JS + test.file))
|
jailInstance := jail.Init(geth.LoadFromFile(txSendFolder + test.file))
|
||||||
geth.PanicAfter(60*time.Second, txCompletedSuccessfully, test.name)
|
geth.PanicAfter(60*time.Second, txCompletedSuccessfully, test.name)
|
||||||
jailInstance.Parse(CHAT_ID_SEND, ``)
|
jailInstance.Parse(chatID, ``)
|
||||||
|
|
||||||
requireMessageId = test.requireMessageId
|
requireMessageId = test.requireMessageId
|
||||||
|
|
||||||
for _, command := range test.commands {
|
for _, command := range test.commands {
|
||||||
go func(jail *jail.Jail, test testCase, command testCommand) {
|
go func(jail *jail.Jail, test testCase, command testCommand) {
|
||||||
t.Logf("->%s: %s", test.name, command.command)
|
t.Logf("->%s: %s", test.name, command.command)
|
||||||
response := jail.Call(CHAT_ID_SEND, command.command, command.params)
|
response := jail.Call(chatID, command.command, command.params)
|
||||||
var txHash common.Hash
|
var txHash common.Hash
|
||||||
if command.command == `["commands", "send"]` {
|
if command.command == `["commands", "send"]` {
|
||||||
txHash = <-txHashes
|
txHash = <-txHashes
|
||||||
|
@ -412,16 +432,16 @@ func TestJailGetVM(t *testing.T) {
|
||||||
|
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
|
|
||||||
expectedError := `Cell[` + CHAT_ID_NON_EXISTENT + `] doesn't exist.`
|
expectedError := `Cell[nonExistentChat] doesn't exist.`
|
||||||
_, err = jailInstance.GetVM(CHAT_ID_NON_EXISTENT)
|
_, err = jailInstance.GetVM("nonExistentChat")
|
||||||
if err == nil || err.Error() != expectedError {
|
if err == nil || err.Error() != expectedError {
|
||||||
t.Error("expected error, but call succeeded")
|
t.Error("expected error, but call succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
// now let's create VM..
|
// now let's create VM..
|
||||||
jailInstance.Parse(CHAT_ID_CALL, ``)
|
jailInstance.Parse(chatID, ``)
|
||||||
// ..and see if VM becomes available
|
// ..and see if VM becomes available
|
||||||
_, err = jailInstance.GetVM(CHAT_ID_CALL)
|
_, err = jailInstance.GetVM(chatID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -435,10 +455,10 @@ func TestIsConnected(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
jailInstance.Parse(CHAT_ID_CALL, "")
|
jailInstance.Parse(chatID, "")
|
||||||
|
|
||||||
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
||||||
vm, err := jailInstance.GetVM(CHAT_ID_CALL)
|
vm, err := jailInstance.GetVM(chatID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot get VM: %v", err)
|
t.Errorf("cannot get VM: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -480,10 +500,10 @@ func TestLocalStorageSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
jailInstance.Parse(CHAT_ID_CALL, "")
|
jailInstance.Parse(chatID, "")
|
||||||
|
|
||||||
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
||||||
vm, err := jailInstance.GetVM(CHAT_ID_CALL)
|
vm, err := jailInstance.GetVM(chatID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot get VM: %v", err)
|
t.Errorf("cannot get VM: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -507,8 +527,8 @@ func TestLocalStorageSet(t *testing.T) {
|
||||||
t.Error("Chat id is required, but not found")
|
t.Error("Chat id is required, but not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if chatId != CHAT_ID_CALL {
|
if chatId != chatID {
|
||||||
t.Errorf("incorrect chat id: expected %q, got: %q", CHAT_ID_CALL, chatId)
|
t.Errorf("incorrect chat id: expected %q, got: %q", chatID, chatId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,10 +592,10 @@ func TestContractDeployment(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
jailInstance.Parse(CHAT_ID_CALL, "")
|
jailInstance.Parse(chatID, "")
|
||||||
|
|
||||||
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
||||||
vm, err := jailInstance.GetVM(CHAT_ID_CALL)
|
vm, err := jailInstance.GetVM(chatID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot get VM: %v", err)
|
t.Errorf("cannot get VM: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -596,15 +616,14 @@ func TestContractDeployment(t *testing.T) {
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
|
|
||||||
t.Logf("Transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
if err := geth.SelectAccount(TEST_ADDRESS, TEST_ADDRESS_PASSWORD); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", TEST_ADDRESS)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), TEST_ADDRESS_PASSWORD); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
@ -620,9 +639,9 @@ func TestContractDeployment(t *testing.T) {
|
||||||
var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]);
|
var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]);
|
||||||
var test = testContract.new(
|
var test = testContract.new(
|
||||||
{
|
{
|
||||||
from: '` + TEST_ADDRESS + `',
|
from: '` + testConfig.Account1.Address + `',
|
||||||
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
|
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
|
||||||
gas: '` + strconv.Itoa(geth.DefaultGas) + `'
|
gas: '` + strconv.Itoa(params.DefaultGas) + `'
|
||||||
}, function (e, contract){
|
}, function (e, contract){
|
||||||
if (!e) {
|
if (!e) {
|
||||||
responseValue = contract.transactionHash
|
responseValue = contract.transactionHash
|
||||||
|
@ -663,10 +682,10 @@ func TestGasEstimation(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jailInstance := jail.Init("")
|
jailInstance := jail.Init("")
|
||||||
jailInstance.Parse(CHAT_ID_CALL, "")
|
jailInstance.Parse(chatID, "")
|
||||||
|
|
||||||
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
// obtain VM for a given chat (to send custom JS to jailed version of Send())
|
||||||
vm, err := jailInstance.GetVM(CHAT_ID_CALL)
|
vm, err := jailInstance.GetVM(chatID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot get VM: %v", err)
|
t.Errorf("cannot get VM: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -689,12 +708,12 @@ func TestGasEstimation(t *testing.T) {
|
||||||
|
|
||||||
t.Logf("Transaction queued (will be completed immediately): {id: %s}\n", event["id"].(string))
|
t.Logf("Transaction queued (will be completed immediately): {id: %s}\n", event["id"].(string))
|
||||||
|
|
||||||
if err := geth.SelectAccount(TEST_ADDRESS, TEST_ADDRESS_PASSWORD); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", TEST_ADDRESS)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), TEST_ADDRESS_PASSWORD); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
@ -710,7 +729,7 @@ func TestGasEstimation(t *testing.T) {
|
||||||
var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]);
|
var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]);
|
||||||
var test = testContract.new(
|
var test = testContract.new(
|
||||||
{
|
{
|
||||||
from: '` + TEST_ADDRESS + `',
|
from: '` + testConfig.Account1.Address + `',
|
||||||
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
|
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
|
||||||
}, function (e, contract){
|
}, function (e, contract){
|
||||||
if (!e) {
|
if (!e) {
|
||||||
|
@ -741,5 +760,383 @@ func TestGasEstimation(t *testing.T) {
|
||||||
if !reflect.DeepEqual(response, expectedResponse) {
|
if !reflect.DeepEqual(response, expectedResponse) {
|
||||||
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, response)
|
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, response)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJailWhisper(t *testing.T) {
|
||||||
|
err := geth.PrepareTestNode()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
whisperService, err := geth.NodeManagerInstance().WhisperService()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("whisper service not running: %v", err)
|
||||||
|
}
|
||||||
|
whisperAPI := whisper.NewPublicWhisperAPI(whisperService)
|
||||||
|
|
||||||
|
// account1
|
||||||
|
_, accountKey1, err := geth.AddressToDecryptedAccount(testConfig.Account1.Address, testConfig.Account1.Password)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
accountKey1Hex := common.ToHex(crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey))
|
||||||
|
|
||||||
|
whisperService.AddIdentity(accountKey1.PrivateKey)
|
||||||
|
if ok, err := whisperAPI.HasIdentity(accountKey1Hex); err != nil || !ok {
|
||||||
|
t.Fatalf("identity not injected: %v", accountKey1Hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// account2
|
||||||
|
_, accountKey2, err := geth.AddressToDecryptedAccount(testConfig.Account2.Address, testConfig.Account2.Password)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
accountKey2Hex := common.ToHex(crypto.FromECDSAPub(&accountKey2.PrivateKey.PublicKey))
|
||||||
|
|
||||||
|
whisperService.AddIdentity(accountKey2.PrivateKey)
|
||||||
|
if ok, err := whisperAPI.HasIdentity(accountKey2Hex); err != nil || !ok {
|
||||||
|
t.Fatalf("identity not injected: %v", accountKey2Hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
passedTests := map[string]bool{
|
||||||
|
whisperMessage1: false,
|
||||||
|
whisperMessage2: false,
|
||||||
|
whisperMessage3: false,
|
||||||
|
whisperMessage4: false,
|
||||||
|
whisperMessage5: false,
|
||||||
|
whisperMessage6: false,
|
||||||
|
}
|
||||||
|
installedFilters := map[string]string{
|
||||||
|
whisperMessage1: "",
|
||||||
|
whisperMessage2: "",
|
||||||
|
whisperMessage3: "",
|
||||||
|
whisperMessage4: "",
|
||||||
|
whisperMessage5: "",
|
||||||
|
whisperMessage6: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
jailInstance := jail.Init("")
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
testCode string
|
||||||
|
useFilter bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"test 0: ensure correct version of Whisper is used",
|
||||||
|
`
|
||||||
|
var expectedVersion = '0x5';
|
||||||
|
if (web3.version.whisper != expectedVersion) {
|
||||||
|
throw 'unexpected shh version, expected: ' + expectedVersion + ', got: ' + web3.version.whisper;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test 1: encrypted signed message from us (From != nil && To != nil)",
|
||||||
|
`
|
||||||
|
var identity1 = '` + accountKey1Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity1)) {
|
||||||
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var identity2 = '` + accountKey2Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity2)) {
|
||||||
|
throw 'idenitity "` + accountKey2Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = 'example1';
|
||||||
|
var payload = '` + whisperMessage1 + `';
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
from: identity1,
|
||||||
|
to: identity2,
|
||||||
|
topics: [web3.fromAscii(topic)]
|
||||||
|
});
|
||||||
|
|
||||||
|
// post message
|
||||||
|
var message = {
|
||||||
|
from: identity1,
|
||||||
|
to: identity2,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20,
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
throw 'message not sent: ' + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterName = '` + whisperMessage1 + `';
|
||||||
|
var filterId = filter.filterId;
|
||||||
|
if (!filterId) {
|
||||||
|
throw 'filter not installed properly';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test 2: encrypted signed message to yourself (From != nil && To != nil)",
|
||||||
|
`
|
||||||
|
var identity = '` + accountKey1Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity)) {
|
||||||
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = 'example2';
|
||||||
|
var payload = '` + whisperMessage2 + `';
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
from: identity,
|
||||||
|
to: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
});
|
||||||
|
|
||||||
|
// post message
|
||||||
|
var message = {
|
||||||
|
from: identity,
|
||||||
|
to: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20,
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
throw 'message not sent: ' + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterName = '` + whisperMessage2 + `';
|
||||||
|
var filterId = filter.filterId;
|
||||||
|
if (!filterId) {
|
||||||
|
throw 'filter not installed properly';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test 3: signed (known sender) broadcast (From != nil && To == nil)",
|
||||||
|
`
|
||||||
|
var identity = '` + accountKey1Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity)) {
|
||||||
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = 'example3';
|
||||||
|
var payload = '` + whisperMessage3 + `';
|
||||||
|
|
||||||
|
// generate symmetric key (if doesn't already exist)
|
||||||
|
if (!shh.hasSymKey(topic)) {
|
||||||
|
shh.addSymKey(topic, "0xdeadbeef"); // alternatively: shh.generateSymKey("example3");
|
||||||
|
// to delete key, rely on: shh.deleteSymKey(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
from: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
keyname: topic // you can use some other name for key too
|
||||||
|
});
|
||||||
|
|
||||||
|
// post message
|
||||||
|
var message = {
|
||||||
|
from: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20,
|
||||||
|
keyname: topic
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
throw 'message not sent: ' + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterName = '` + whisperMessage3 + `';
|
||||||
|
var filterId = filter.filterId;
|
||||||
|
if (!filterId) {
|
||||||
|
throw 'filter not installed properly';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test 4: anonymous broadcast (From == nil && To == nil)",
|
||||||
|
`
|
||||||
|
var topic = 'example4';
|
||||||
|
var payload = '` + whisperMessage4 + `';
|
||||||
|
|
||||||
|
// generate symmetric key (if doesn't already exist)
|
||||||
|
if (!shh.hasSymKey(topic)) {
|
||||||
|
shh.addSymKey(topic, "0xdeadbeef"); // alternatively: shh.generateSymKey("example3");
|
||||||
|
// to delete key, rely on: shh.deleteSymKey(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
keyname: topic // you can use some other name for key too
|
||||||
|
});
|
||||||
|
|
||||||
|
// post message
|
||||||
|
var message = {
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20,
|
||||||
|
keyname: topic
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
throw 'message not sent: ' + err;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterName = '` + whisperMessage4 + `';
|
||||||
|
var filterId = filter.filterId;
|
||||||
|
if (!filterId) {
|
||||||
|
throw 'filter not installed properly';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test 5: encrypted anonymous message (From == nil && To != nil)",
|
||||||
|
`
|
||||||
|
var identity = '` + accountKey2Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity)) {
|
||||||
|
throw 'idenitity "` + accountKey2Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = 'example5';
|
||||||
|
var payload = '` + whisperMessage5 + `';
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
to: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
});
|
||||||
|
|
||||||
|
// post message
|
||||||
|
var message = {
|
||||||
|
to: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
throw 'message not sent: ' + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterName = '` + whisperMessage5 + `';
|
||||||
|
var filterId = filter.filterId;
|
||||||
|
if (!filterId) {
|
||||||
|
throw 'filter not installed properly';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test 6: encrypted signed response to us (From != nil && To != nil)",
|
||||||
|
`
|
||||||
|
var identity1 = '` + accountKey1Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity1)) {
|
||||||
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var identity2 = '` + accountKey2Hex + `';
|
||||||
|
if (!web3.shh.hasIdentity(identity2)) {
|
||||||
|
throw 'idenitity "` + accountKey2Hex + `" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = 'example6';
|
||||||
|
var payload = '` + whisperMessage6 + `';
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
from: identity2,
|
||||||
|
to: identity1,
|
||||||
|
topics: [web3.fromAscii(topic)]
|
||||||
|
});
|
||||||
|
|
||||||
|
// post message
|
||||||
|
var message = {
|
||||||
|
from: identity2,
|
||||||
|
to: identity1,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
throw 'message not sent: ' + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterName = '` + whisperMessage6 + `';
|
||||||
|
var filterId = filter.filterId;
|
||||||
|
if (!filterId) {
|
||||||
|
throw 'filter not installed properly';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Log(testCase.name)
|
||||||
|
testCaseKey := crypto.Keccak256Hash([]byte(testCase.name)).Hex()
|
||||||
|
jailInstance.Parse(testCaseKey, `var shh = web3.shh;`)
|
||||||
|
vm, err := jailInstance.GetVM(testCaseKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("cannot get VM: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// post messages
|
||||||
|
if _, err := vm.Run(testCase.testCode); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !testCase.useFilter {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// update installed filters
|
||||||
|
filterId, err := vm.Get("filterId")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("cannot get filterId: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
filterName, err := vm.Get("filterName")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("cannot get filterName: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := installedFilters[filterName.String()]; !ok {
|
||||||
|
t.Fatal("unrecognized filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
installedFilters[filterName.String()] = filterId.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second) // allow whisper to poll
|
||||||
|
|
||||||
|
for testKey, filter := range installedFilters {
|
||||||
|
if filter != "" {
|
||||||
|
t.Logf("filter found: %v", filter)
|
||||||
|
for _, message := range whisperAPI.GetFilterChanges(filter) {
|
||||||
|
t.Logf("message found: %s", common.FromHex(message.Payload))
|
||||||
|
passedTests[testKey] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for testName, passedTest := range passedTests {
|
||||||
|
if !passedTest {
|
||||||
|
t.Fatalf("test not passed: %v", testName)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>web3.js sample</title>
|
||||||
|
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
<script
|
||||||
|
src="https://code.jquery.com/jquery-3.1.1.js"
|
||||||
|
integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||||
|
<script type="text/javascript" src="./bignumber.js"></script>
|
||||||
|
<script type="text/javascript" src="./web3.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var web3 = new Web3();
|
||||||
|
var shh = web3.shh;
|
||||||
|
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8645'));
|
||||||
|
|
||||||
|
var identity = '0x04eedbaafd6adf4a9233a13e7b1c3c14461fffeba2e9054b8d456ce5f6ebeafadcbf3dce3716253fbc391277fa5a086b60b283daf61fb5b1f26895f456c2f31ae3';
|
||||||
|
if (!web3.shh.hasIdentity(identity)) {
|
||||||
|
throw 'idenitity "0x04eedbaafd6adf4a9233a13e7b1c3c14461fffeba2e9054b8d456ce5f6ebeafadcbf3dce3716253fbc391277fa5a086b60b283daf61fb5b1f26895f456c2f31ae3" not found in whisper';
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = 'example3';
|
||||||
|
var payload = 'test message 3 (K1 -> "", signed broadcast)';
|
||||||
|
|
||||||
|
// generate symmetric key (if doesn't already exist)
|
||||||
|
if (!shh.hasSymKey(topic)) {
|
||||||
|
shh.addSymKey(topic, "0xdeadbeef"); // alternatively: shh.generateSymKey("example3");
|
||||||
|
// to delete key, rely on: shh.deleteSymKey(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start watching for messages
|
||||||
|
var filter = shh.filter({
|
||||||
|
from: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
keyname: topic // you can use some other name for key too
|
||||||
|
});
|
||||||
|
filter.watch(function(error, result){
|
||||||
|
if (!error) {
|
||||||
|
console.log("Message received1: ", result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
var message = {
|
||||||
|
from: identity,
|
||||||
|
topics: [web3.fromAscii(topic)],
|
||||||
|
payload: payload,
|
||||||
|
ttl: 20,
|
||||||
|
keyname: topic
|
||||||
|
};
|
||||||
|
var err = shh.post(message)
|
||||||
|
if (err !== null) {
|
||||||
|
console.log("message NOT sent")
|
||||||
|
} else {
|
||||||
|
console.log("message sent OK")
|
||||||
|
}
|
||||||
|
}, 3000)
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Static navbar -->
|
||||||
|
<nav class="navbar navbar-default navbar-static-top">
|
||||||
|
<div class="container">
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="jumbotron">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -3453,6 +3453,7 @@ var getOptions = function (options) {
|
||||||
topics: options.topics,
|
topics: options.topics,
|
||||||
from: options.from,
|
from: options.from,
|
||||||
to: options.to,
|
to: options.to,
|
||||||
|
keyname: options.keyname,
|
||||||
address: options.address,
|
address: options.address,
|
||||||
fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),
|
fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),
|
||||||
toBlock: formatters.inputBlockNumberFormatter(options.toBlock)
|
toBlock: formatters.inputBlockNumberFormatter(options.toBlock)
|
||||||
|
@ -5646,12 +5647,40 @@ var methods = function () {
|
||||||
params: 0
|
params: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var generateSymKey = new Method({
|
||||||
|
name: 'generateSymKey',
|
||||||
|
call: 'shh_generateSymKey',
|
||||||
|
params: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasSymKey = new Method({
|
||||||
|
name: 'hasSymKey',
|
||||||
|
call: 'shh_hasSymKey',
|
||||||
|
params: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var deleteSymKey = new Method({
|
||||||
|
name: 'deleteSymKey',
|
||||||
|
call: 'shh_deleteSymKey',
|
||||||
|
params: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var addSymKey = new Method({
|
||||||
|
name: 'addSymKey',
|
||||||
|
call: 'shh_addSymKey',
|
||||||
|
params: 2
|
||||||
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
post,
|
post,
|
||||||
newIdentity,
|
newIdentity,
|
||||||
hasIdentity,
|
hasIdentity,
|
||||||
newGroup,
|
newGroup,
|
||||||
addToGroup
|
addToGroup,
|
||||||
|
generateSymKey,
|
||||||
|
hasSymKey,
|
||||||
|
deleteSymKey,
|
||||||
|
addSymKey
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
239
geth/node.go
239
geth/node.go
|
@ -4,7 +4,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/les"
|
"github.com/ethereum/go-ethereum/les"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
@ -24,55 +22,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
gethparams "github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "StatusIM" // Client identifier to advertise over the network
|
|
||||||
VersionMajor = 0 // Major version component of the current release
|
|
||||||
VersionMinor = 9 // Minor version component of the current release
|
|
||||||
VersionPatch = 4 // Patch version component of the current release
|
|
||||||
VersionMeta = "stable" // Version metadata to append to the version string
|
|
||||||
IPCFile = "geth.ipc" // Filename of exposed IPC-RPC Server
|
|
||||||
HTTPPort = 8545 // HTTP-RPC port (replaced in unit tests)
|
|
||||||
WSPort = 8546 // WS-RPC port (replaced in unit tests)
|
|
||||||
MaxPeers = 25
|
|
||||||
MaxLightPeers = 20
|
|
||||||
MaxPendingPeers = 0
|
|
||||||
DefaultGas = 180000
|
|
||||||
|
|
||||||
ProcessFileDescriptorLimit = uint64(2048)
|
|
||||||
DatabaseCacheSize = 128 // Megabytes of memory allocated to internal caching (min 16MB / database forced)
|
|
||||||
|
|
||||||
EventNodeStarted = "node.started"
|
EventNodeStarted = "node.started"
|
||||||
EventNodeCrashed = "node.crashed"
|
EventNodeCrashed = "node.crashed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gas price settings
|
|
||||||
var (
|
|
||||||
GasPrice = new(big.Int).Mul(big.NewInt(20), common.Shannon) // Minimal gas price to accept for mining a transactions
|
|
||||||
GpoMinGasPrice = new(big.Int).Mul(big.NewInt(20), common.Shannon) // Minimum suggested gas price
|
|
||||||
GpoMaxGasPrice = new(big.Int).Mul(big.NewInt(500), common.Shannon) // Maximum suggested gas price
|
|
||||||
GpoFullBlockRatio = 80 // Full block threshold for gas price calculation (%)
|
|
||||||
GpobaseStepDown = 10 // Suggested gas price base step down ratio (1/1000)
|
|
||||||
GpobaseStepUp = 100 // Suggested gas price base step up ratio (1/1000)
|
|
||||||
GpobaseCorrectionFactor = 110 // Suggested gas price base correction factor (%)
|
|
||||||
)
|
|
||||||
|
|
||||||
// default node configuration options
|
|
||||||
var (
|
|
||||||
UseTestnetFlag = "true" // to be overridden via -ldflags '-X geth.UseTestnetFlag'
|
|
||||||
UseTestnet = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if UseTestnetFlag == "true" { // set at compile time, here we make sure to set corresponding boolean flag
|
|
||||||
UseTestnet = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// node-related errors
|
// node-related errors
|
||||||
var (
|
var (
|
||||||
ErrEthServiceRegistrationFailure = errors.New("failed to register the Ethereum service")
|
ErrEthServiceRegistrationFailure = errors.New("failed to register the Ethereum service")
|
||||||
|
@ -80,22 +39,12 @@ var (
|
||||||
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
|
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeConfig stores configuration options for a node
|
|
||||||
type NodeConfig struct {
|
|
||||||
DataDir string // base data directory
|
|
||||||
IPCEnabled bool // whether IPC-RPC Server is enabled or not
|
|
||||||
HTTPPort int // HTTP-RPC Server port
|
|
||||||
WSPort int // WS-RPC Server port
|
|
||||||
WSEnabled bool // whether WS-RPC Server is enabled or not
|
|
||||||
TLSEnabled bool // whether TLS support should be enabled on node or not
|
|
||||||
}
|
|
||||||
|
|
||||||
// Node represents running node (serves as a wrapper around P2P node)
|
// Node represents running node (serves as a wrapper around P2P node)
|
||||||
type Node struct {
|
type Node struct {
|
||||||
config *NodeConfig // configuration used to create Status node
|
config *params.NodeConfig // configuration used to create Status node
|
||||||
geth *node.Node // reference to the running Geth node
|
geth *node.Node // reference to the running Geth node
|
||||||
gethConfig *node.Config // configuration used to create P2P node
|
gethConfig *node.Config // configuration used to create P2P node
|
||||||
started chan struct{} // channel to wait for node to start
|
started chan struct{} // channel to wait for node to start
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inited checks whether status node has been properly initialized
|
// Inited checks whether status node has been properly initialized
|
||||||
|
@ -109,24 +58,25 @@ func (n *Node) GethStack() *node.Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeNode create a geth node entity
|
// MakeNode create a geth node entity
|
||||||
func MakeNode(config *NodeConfig) *Node {
|
func MakeNode(config *params.NodeConfig) *Node {
|
||||||
glog.CopyStandardLogTo("INFO")
|
// make sure data directory exists
|
||||||
glog.SetToStderr(true)
|
if err := os.MkdirAll(filepath.Join(config.DataDir), os.ModePerm); err != nil {
|
||||||
|
Fatalf(err)
|
||||||
dataDir := config.DataDir
|
|
||||||
if UseTestnet {
|
|
||||||
dataDir = filepath.Join(config.DataDir, "testnet")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exposed RPC APIs
|
// setup logging
|
||||||
exposedAPIs := "db,eth,net,web3,shh,personal,admin" // TODO remove "admin" on main net
|
glog.CopyStandardLogTo("INFO")
|
||||||
|
glog.SetToStderr(true)
|
||||||
|
if _, err := params.SetupLogger(config); err != nil {
|
||||||
|
Fatalf(err)
|
||||||
|
}
|
||||||
|
|
||||||
// configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config)
|
// configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config)
|
||||||
stackConfig := &node.Config{
|
stackConfig := &node.Config{
|
||||||
DataDir: dataDir,
|
DataDir: config.DataDir,
|
||||||
UseLightweightKDF: true,
|
UseLightweightKDF: true,
|
||||||
Name: ClientIdentifier,
|
Name: config.Name,
|
||||||
Version: fmt.Sprintf("%d.%d.%d-%s", VersionMajor, VersionMinor, VersionPatch, VersionMeta),
|
Version: config.Version,
|
||||||
NoDiscovery: true,
|
NoDiscovery: true,
|
||||||
DiscoveryV5: false,
|
DiscoveryV5: false,
|
||||||
DiscoveryV5Addr: ":0",
|
DiscoveryV5Addr: ":0",
|
||||||
|
@ -134,17 +84,17 @@ func MakeNode(config *NodeConfig) *Node {
|
||||||
BootstrapNodesV5: makeBootstrapNodesV5(),
|
BootstrapNodesV5: makeBootstrapNodesV5(),
|
||||||
ListenAddr: ":0",
|
ListenAddr: ":0",
|
||||||
NAT: nat.Any(),
|
NAT: nat.Any(),
|
||||||
MaxPeers: MaxPeers,
|
MaxPeers: config.MaxPeers,
|
||||||
MaxPendingPeers: MaxPendingPeers,
|
MaxPendingPeers: config.MaxPendingPeers,
|
||||||
IPCPath: makeIPCPath(dataDir, config.IPCEnabled),
|
IPCPath: makeIPCPath(config),
|
||||||
HTTPHost: node.DefaultHTTPHost,
|
HTTPHost: config.HTTPHost,
|
||||||
HTTPPort: config.HTTPPort,
|
HTTPPort: config.HTTPPort,
|
||||||
HTTPCors: "*",
|
HTTPCors: "*",
|
||||||
HTTPModules: strings.Split(exposedAPIs, ","),
|
HTTPModules: strings.Split(config.APIModules, ","),
|
||||||
WSHost: makeWSHost(config.WSEnabled),
|
WSHost: makeWSHost(config),
|
||||||
WSPort: config.WSPort,
|
WSPort: config.WSPort,
|
||||||
WSOrigins: "*",
|
WSOrigins: "*",
|
||||||
WSModules: strings.Split(exposedAPIs, ","),
|
WSModules: strings.Split(config.APIModules, ","),
|
||||||
}
|
}
|
||||||
|
|
||||||
stack, err := node.New(stackConfig)
|
stack, err := node.New(stackConfig)
|
||||||
|
@ -153,12 +103,12 @@ func MakeNode(config *NodeConfig) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start Ethereum service
|
// start Ethereum service
|
||||||
if err := activateEthService(stack, makeDefaultExtra()); err != nil {
|
if err := activateEthService(stack, config); err != nil {
|
||||||
Fatalf(fmt.Errorf("%v: %v", ErrEthServiceRegistrationFailure, err))
|
Fatalf(fmt.Errorf("%v: %v", ErrEthServiceRegistrationFailure, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// start Whisper service
|
// start Whisper service
|
||||||
if err := activateShhService(stack); err != nil {
|
if err := activateShhService(stack, config); err != nil {
|
||||||
Fatalf(fmt.Errorf("%v: %v", ErrSshServiceRegistrationFailure, err))
|
Fatalf(fmt.Errorf("%v: %v", ErrSshServiceRegistrationFailure, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,33 +121,32 @@ func MakeNode(config *NodeConfig) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// activateEthService configures and registers the eth.Ethereum service with a given node.
|
// activateEthService configures and registers the eth.Ethereum service with a given node.
|
||||||
func activateEthService(stack *node.Node, extra []byte) error {
|
func activateEthService(stack *node.Node, config *params.NodeConfig) error {
|
||||||
ethConf := ð.Config{
|
if !config.LightEthConfig.Enabled {
|
||||||
Etherbase: common.Address{},
|
glog.V(logger.Info).Infoln("LES protocol is disabled")
|
||||||
ChainConfig: makeChainConfig(stack),
|
return nil
|
||||||
FastSync: false,
|
|
||||||
LightMode: true,
|
|
||||||
LightServ: 60,
|
|
||||||
LightPeers: MaxLightPeers,
|
|
||||||
MaxPeers: MaxPeers,
|
|
||||||
DatabaseCache: DatabaseCacheSize,
|
|
||||||
DatabaseHandles: makeDatabaseHandles(),
|
|
||||||
NetworkId: 1, // Olympic
|
|
||||||
MinerThreads: runtime.NumCPU(),
|
|
||||||
GasPrice: GasPrice,
|
|
||||||
GpoMinGasPrice: GpoMinGasPrice,
|
|
||||||
GpoMaxGasPrice: GpoMaxGasPrice,
|
|
||||||
GpoFullBlockRatio: GpoFullBlockRatio,
|
|
||||||
GpobaseStepDown: GpobaseStepDown,
|
|
||||||
GpobaseStepUp: GpobaseStepUp,
|
|
||||||
GpobaseCorrectionFactor: GpobaseCorrectionFactor,
|
|
||||||
SolcPath: "solc",
|
|
||||||
AutoDAG: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if UseTestnet {
|
ethConf := ð.Config{
|
||||||
ethConf.NetworkId = 3
|
Etherbase: common.Address{},
|
||||||
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
ChainConfig: makeChainConfig(config),
|
||||||
|
FastSync: false,
|
||||||
|
LightMode: true,
|
||||||
|
MaxPeers: config.MaxPeers,
|
||||||
|
DatabaseCache: config.LightEthConfig.DatabaseCache,
|
||||||
|
DatabaseHandles: makeDatabaseHandles(),
|
||||||
|
NetworkId: config.NetworkId,
|
||||||
|
Genesis: config.LightEthConfig.Genesis,
|
||||||
|
MinerThreads: runtime.NumCPU(),
|
||||||
|
GasPrice: params.GasPrice,
|
||||||
|
GpoMinGasPrice: params.GpoMinGasPrice,
|
||||||
|
GpoMaxGasPrice: params.GpoMaxGasPrice,
|
||||||
|
GpoFullBlockRatio: params.GpoFullBlockRatio,
|
||||||
|
GpobaseStepDown: params.GpobaseStepDown,
|
||||||
|
GpobaseStepUp: params.GpobaseStepUp,
|
||||||
|
GpobaseCorrectionFactor: params.GpobaseCorrectionFactor,
|
||||||
|
SolcPath: "solc",
|
||||||
|
AutoDAG: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
|
@ -210,7 +159,11 @@ func activateEthService(stack *node.Node, extra []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// activateShhService configures Whisper and adds it to the given node.
|
// activateShhService configures Whisper and adds it to the given node.
|
||||||
func activateShhService(stack *node.Node) error {
|
func activateShhService(stack *node.Node, config *params.NodeConfig) error {
|
||||||
|
if !config.WhisperConfig.Enabled {
|
||||||
|
glog.V(logger.Info).Infoln("SHH protocol is disabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
serviceConstructor := func(*node.ServiceContext) (node.Service, error) {
|
serviceConstructor := func(*node.ServiceContext) (node.Service, error) {
|
||||||
return whisper.New(), nil
|
return whisper.New(), nil
|
||||||
}
|
}
|
||||||
|
@ -222,47 +175,44 @@ func activateShhService(stack *node.Node) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeIPCPath returns IPC-RPC filename
|
// makeIPCPath returns IPC-RPC filename
|
||||||
func makeIPCPath(dataDir string, ipcEnabled bool) string {
|
func makeIPCPath(config *params.NodeConfig) string {
|
||||||
if !ipcEnabled {
|
if !config.IPCEnabled {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.Join(dataDir, IPCFile)
|
return path.Join(config.DataDir, config.IPCFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeWSHost returns WS-RPC Server host, given enabled/disabled flag
|
// makeWSHost returns WS-RPC Server host, given enabled/disabled flag
|
||||||
func makeWSHost(wsEnabled bool) string {
|
func makeWSHost(config *params.NodeConfig) string {
|
||||||
if !wsEnabled {
|
if !config.WSEnabled {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.DefaultWSHost
|
return config.WSHost
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeChainConfig reads the chain configuration from the database in the datadir.
|
// makeChainConfig reads the chain configuration from the database in the datadir.
|
||||||
func makeChainConfig(stack *node.Node) *params.ChainConfig {
|
func makeChainConfig(config *params.NodeConfig) *gethparams.ChainConfig {
|
||||||
config := new(params.ChainConfig)
|
chainConfig := new(gethparams.ChainConfig)
|
||||||
|
|
||||||
if UseTestnet {
|
// Homestead fork
|
||||||
config = params.TestnetChainConfig
|
chainConfig.HomesteadBlock = config.HomesteadBlock
|
||||||
} else {
|
|
||||||
// Homestead fork
|
|
||||||
config.HomesteadBlock = params.MainNetHomesteadBlock
|
|
||||||
// DAO fork
|
|
||||||
config.DAOForkBlock = params.MainNetDAOForkBlock
|
|
||||||
config.DAOForkSupport = true
|
|
||||||
|
|
||||||
// DoS reprice fork
|
// DAO fork
|
||||||
config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
|
chainConfig.DAOForkBlock = config.DAOForkBlock
|
||||||
config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
|
chainConfig.DAOForkSupport = config.DAOForkSupport
|
||||||
|
|
||||||
// DoS state cleanup fork
|
// DoS reprice fork
|
||||||
config.EIP155Block = params.MainNetSpuriousDragon
|
chainConfig.EIP150Block = config.EIP150Block
|
||||||
config.EIP158Block = params.MainNetSpuriousDragon
|
chainConfig.EIP150Hash = config.EIP150Hash
|
||||||
config.ChainId = params.MainNetChainID
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
// DoS state cleanup fork
|
||||||
|
chainConfig.EIP155Block = config.EIP155Block
|
||||||
|
chainConfig.EIP158Block = config.EIP158Block
|
||||||
|
chainConfig.ChainId = config.ChainId
|
||||||
|
|
||||||
|
return chainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeDatabaseHandles makes sure that enough file descriptors are available to the process
|
// makeDatabaseHandles makes sure that enough file descriptors are available to the process
|
||||||
|
@ -276,8 +226,8 @@ func makeDatabaseHandles() int {
|
||||||
|
|
||||||
// increase limit
|
// increase limit
|
||||||
limit.Cur = limit.Max
|
limit.Cur = limit.Max
|
||||||
if limit.Cur > ProcessFileDescriptorLimit {
|
if limit.Cur > params.DefaultFileDescriptorLimit {
|
||||||
limit.Cur = ProcessFileDescriptorLimit
|
limit.Cur = params.DefaultFileDescriptorLimit
|
||||||
}
|
}
|
||||||
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
|
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
|
||||||
Fatalf(err)
|
Fatalf(err)
|
||||||
|
@ -289,34 +239,13 @@ func makeDatabaseHandles() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cap limit
|
// cap limit
|
||||||
if limit.Cur > ProcessFileDescriptorLimit {
|
if limit.Cur > params.DefaultFileDescriptorLimit {
|
||||||
limit.Cur = ProcessFileDescriptorLimit
|
limit.Cur = params.DefaultFileDescriptorLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(limit.Cur) / 2
|
return int(limit.Cur) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDefaultExtra() []byte {
|
|
||||||
var clientInfo = struct {
|
|
||||||
Version uint
|
|
||||||
Name string
|
|
||||||
GoVersion string
|
|
||||||
Os string
|
|
||||||
}{uint(VersionMajor<<16 | VersionMinor<<8 | VersionPatch), ClientIdentifier, runtime.Version(), runtime.GOOS}
|
|
||||||
extra, err := rlp.EncodeToBytes(clientInfo)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
|
|
||||||
glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
|
|
||||||
glog.V(logger.Debug).Infof("extra: %x\n", extra)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return extra
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeBootstrapNodes returns default (hence bootstrap) list of peers
|
// makeBootstrapNodes returns default (hence bootstrap) list of peers
|
||||||
func makeBootstrapNodes() []*discover.Node {
|
func makeBootstrapNodes() []*discover.Node {
|
||||||
// on desktops params.TestnetBootnodes and params.MainBootnodes,
|
// on desktops params.TestnetBootnodes and params.MainBootnodes,
|
||||||
|
|
|
@ -18,8 +18,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SelectedExtKey is a container for currently selected (logged in) account
|
// SelectedExtKey is a container for currently selected (logged in) account
|
||||||
|
@ -46,7 +46,6 @@ type NodeServiceStack struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrDataDirPreprocessingFailed = errors.New("failed to pre-process data directory")
|
|
||||||
ErrInvalidGethNode = errors.New("no running geth node detected")
|
ErrInvalidGethNode = errors.New("no running geth node detected")
|
||||||
ErrInvalidAccountManager = errors.New("could not retrieve account manager")
|
ErrInvalidAccountManager = errors.New("could not retrieve account manager")
|
||||||
ErrInvalidWhisperService = errors.New("whisper service is unavailable")
|
ErrInvalidWhisperService = errors.New("whisper service is unavailable")
|
||||||
|
@ -65,7 +64,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way)
|
// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way)
|
||||||
func CreateAndRunNode(config *NodeConfig) error {
|
func CreateAndRunNode(config *params.NodeConfig) error {
|
||||||
defer HaltOnPanic()
|
defer HaltOnPanic()
|
||||||
|
|
||||||
nodeManager := NewNodeManager(config)
|
nodeManager := NewNodeManager(config)
|
||||||
|
@ -80,7 +79,7 @@ func CreateAndRunNode(config *NodeConfig) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeManager makes new instance of node manager
|
// NewNodeManager makes new instance of node manager
|
||||||
func NewNodeManager(config *NodeConfig) *NodeManager {
|
func NewNodeManager(config *params.NodeConfig) *NodeManager {
|
||||||
createOnce.Do(func() {
|
createOnce.Do(func() {
|
||||||
nodeManagerInstance = &NodeManager{
|
nodeManagerInstance = &NodeManager{
|
||||||
services: &NodeServiceStack{
|
services: &NodeServiceStack{
|
||||||
|
@ -116,15 +115,13 @@ func (m *NodeManager) RunNode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup handlers
|
// setup handlers
|
||||||
lightEthereum, err := m.LightEthereumService()
|
if lightEthereum, err := m.LightEthereumService(); err == nil {
|
||||||
if err != nil {
|
lightEthereum.StatusBackend.SetTransactionQueueHandler(onSendTransactionRequest)
|
||||||
panic("service stack misses LES")
|
lightEthereum.StatusBackend.SetAccountsFilterHandler(onAccountsListRequest)
|
||||||
|
lightEthereum.StatusBackend.SetTransactionReturnHandler(onSendTransactionReturn)
|
||||||
}
|
}
|
||||||
|
|
||||||
lightEthereum.StatusBackend.SetTransactionQueueHandler(onSendTransactionRequest)
|
var err error
|
||||||
lightEthereum.StatusBackend.SetAccountsFilterHandler(onAccountsListRequest)
|
|
||||||
lightEthereum.StatusBackend.SetTransactionReturnHandler(onSendTransactionReturn)
|
|
||||||
|
|
||||||
m.services.rpcClient, err = m.node.geth.Attach()
|
m.services.rpcClient, err = m.node.geth.Attach()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Warn).Infoln("cannot get RPC client service:", ErrInvalidClient)
|
glog.V(logger.Warn).Infoln("cannot get RPC client service:", ErrInvalidClient)
|
||||||
|
@ -265,7 +262,7 @@ func (m *NodeManager) StopNodeRPCServer() (bool, error) {
|
||||||
return m.api.StopRPC()
|
return m.api.StopRPC()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasNode checks whether manager has initialized node attached
|
// NodeInited checks whether manager has initialized node attached
|
||||||
func (m *NodeManager) NodeInited() bool {
|
func (m *NodeManager) NodeInited() bool {
|
||||||
if m == nil || !m.node.Inited() {
|
if m == nil || !m.node.Inited() {
|
||||||
return false
|
return false
|
||||||
|
@ -274,6 +271,15 @@ func (m *NodeManager) NodeInited() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Node returns attached node if it has been initialized
|
||||||
|
func (m *NodeManager) Node() *Node {
|
||||||
|
if !m.NodeInited() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.node
|
||||||
|
}
|
||||||
|
|
||||||
// AccountManager exposes reference to accounts manager
|
// AccountManager exposes reference to accounts manager
|
||||||
func (m *NodeManager) AccountManager() (*accounts.Manager, error) {
|
func (m *NodeManager) AccountManager() (*accounts.Manager, error) {
|
||||||
if m == nil || !m.NodeInited() {
|
if m == nil || !m.NodeInited() {
|
||||||
|
|
|
@ -1,67 +1,28 @@
|
||||||
package geth_test
|
package geth_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var testConfig *geth.TestConfig
|
||||||
testAddress = "0xadaf150b905cf5e6a778e553e15a139b6618bbb7"
|
|
||||||
testAddressPassword = "asdfasdf"
|
|
||||||
newAccountPassword = "badpassword"
|
|
||||||
testAddress1 = "0xadd4d1d02e71c7360c53296968e59d57fd15e2ba"
|
|
||||||
|
|
||||||
whisperMessage1 = "test message 1 (K1 -> K1)"
|
|
||||||
whisperMessage2 = "test message 2 (K1 -> '')"
|
|
||||||
whisperMessage3 = "test message 3 ('' -> '')"
|
|
||||||
whisperMessage4 = "test message 4 ('' -> K1)"
|
|
||||||
whisperMessage5 = "test message 5 (K2 -> K1)"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
syncRequired := false
|
// load shared test configuration
|
||||||
if _, err := os.Stat(filepath.Join(geth.TestDataDir, "testnet")); os.IsNotExist(err) {
|
var err error
|
||||||
syncRequired = true
|
testConfig, err = geth.LoadTestConfig()
|
||||||
}
|
|
||||||
// make sure you panic if node start signal is not received
|
|
||||||
signalRecieved := make(chan struct{}, 1)
|
|
||||||
abortPanic := make(chan struct{}, 1)
|
|
||||||
if syncRequired {
|
|
||||||
geth.PanicAfter(geth.TestNodeSyncSeconds*time.Second, abortPanic, "TestNodeSetup")
|
|
||||||
} else {
|
|
||||||
geth.PanicAfter(10*time.Second, abortPanic, "TestNodeSetup")
|
|
||||||
}
|
|
||||||
|
|
||||||
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
|
||||||
var envelope geth.SignalEnvelope
|
|
||||||
if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil {
|
|
||||||
panic(fmt.Errorf("cannot unmarshal event's JSON: %s", jsonEvent))
|
|
||||||
}
|
|
||||||
if envelope.Type == geth.EventNodeCrashed {
|
|
||||||
geth.TriggerDefaultNodeNotificationHandler(jsonEvent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if jsonEvent == `{"type":"node.started","event":{}}` {
|
|
||||||
signalRecieved <- struct{}{}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
err := geth.PrepareTestNode()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-signalRecieved // block and wait for either panic or successful signal
|
// run tests
|
||||||
abortPanic <- struct{}{}
|
retCode := m.Run()
|
||||||
|
|
||||||
os.Exit(m.Run())
|
//time.Sleep(25 * time.Second) // to give some time to propagate txs to the rest of the network
|
||||||
|
os.Exit(retCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResetChainData(t *testing.T) {
|
func TestResetChainData(t *testing.T) {
|
||||||
|
@ -77,7 +38,7 @@ func TestResetChainData(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow some time to re-sync
|
// allow some time to re-sync
|
||||||
time.Sleep(geth.TestNodeSyncSeconds * time.Second)
|
time.Sleep(testConfig.Node.SyncSeconds * time.Second)
|
||||||
|
|
||||||
// now make sure that everything is intact
|
// now make sure that everything is intact
|
||||||
TestQueuedTransactions(t)
|
TestQueuedTransactions(t)
|
||||||
|
|
|
@ -1,43 +1,51 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
// MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the main Ethereum network.
|
// MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the main Ethereum network.
|
||||||
var MainnetBootnodes = []string{
|
var MainnetBootnodes = []string{}
|
||||||
}
|
|
||||||
|
|
||||||
// TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the Ropsten test network.
|
// TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the Ropsten test network.
|
||||||
var TestnetBootnodes = []string{
|
var TestnetBootnodes = []string{
|
||||||
"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30399",
|
"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30379",
|
||||||
|
//"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30399",
|
||||||
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303",
|
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303",
|
||||||
|
|
||||||
"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30399",
|
"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30379",
|
||||||
|
//"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30399",
|
||||||
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303",
|
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303",
|
||||||
|
|
||||||
"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30399",
|
"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30379",
|
||||||
|
//"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30399",
|
||||||
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303",
|
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303",
|
||||||
|
|
||||||
"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30399",
|
"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30379",
|
||||||
|
//"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30399",
|
||||||
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303",
|
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303",
|
||||||
|
|
||||||
"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30399",
|
"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30379",
|
||||||
|
//"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30399",
|
||||||
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303",
|
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303",
|
||||||
|
|
||||||
"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30399",
|
"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30379",
|
||||||
|
//"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30399",
|
||||||
"enode://1fa2dfe6b925ca753496ea197c973b66ef889ef4de2bf52acd5b8665c0cc2e8b95fbd192e764f10735f589297f1ae533f350f004e403063e8d4ad979aae44c12@51.15.61.194:30303",
|
"enode://1fa2dfe6b925ca753496ea197c973b66ef889ef4de2bf52acd5b8665c0cc2e8b95fbd192e764f10735f589297f1ae533f350f004e403063e8d4ad979aae44c12@51.15.61.194:30303",
|
||||||
|
|
||||||
"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30399",
|
"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30379",
|
||||||
|
//"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30399",
|
||||||
"enode://44b91c043bcd96bc5279524f1bfe32df0670374135435ebacb29ba5d0e18192623e63ead711c9c363afdf2500fac423116ac28bdd2d700bd70e096326f95c63f@51.15.35.2:30303",
|
"enode://44b91c043bcd96bc5279524f1bfe32df0670374135435ebacb29ba5d0e18192623e63ead711c9c363afdf2500fac423116ac28bdd2d700bd70e096326f95c63f@51.15.35.2:30303",
|
||||||
|
|
||||||
"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30399",
|
"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30379",
|
||||||
|
//"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30399",
|
||||||
"enode://fb7622d3a50dc603f5c76919dd99c4112e5925cb891a67086b9dce581166fbdad361fd0bfb7ff128ab8f5e24e209e0b923668fbddb7e8b99edb82c1e3d782a80@51.15.54.229:30303",
|
"enode://fb7622d3a50dc603f5c76919dd99c4112e5925cb891a67086b9dce581166fbdad361fd0bfb7ff128ab8f5e24e209e0b923668fbddb7e8b99edb82c1e3d782a80@51.15.54.229:30303",
|
||||||
|
|
||||||
"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30399",
|
"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30379",
|
||||||
|
//"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30399",
|
||||||
"enode://14c2960f57f6d63ed541cf64226aafbc7a21c40c6e4935a2e58fd2466fa7d06ec32082734c64d32f7c4692f4b90f26d019f472ba55cdda6d624ef4d7d8441285@51.15.35.70:30303",
|
"enode://14c2960f57f6d63ed541cf64226aafbc7a21c40c6e4935a2e58fd2466fa7d06ec32082734c64d32f7c4692f4b90f26d019f472ba55cdda6d624ef4d7d8441285@51.15.35.70:30303",
|
||||||
|
|
||||||
"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30399",
|
"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30379",
|
||||||
|
//"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30399",
|
||||||
"enode://02cfa2b02b5431bfdc1bad0f575de8ea151029fe9a9c689074793d704d1b428255bd111bf578f0b4fcaa18267da7c335db9557e1012434f4a8ab2c25f4b3da4d@51.15.39.57:30303",
|
"enode://02cfa2b02b5431bfdc1bad0f575de8ea151029fe9a9c689074793d704d1b428255bd111bf578f0b4fcaa18267da7c335db9557e1012434f4a8ab2c25f4b3da4d@51.15.39.57:30303",
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the
|
// DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the
|
||||||
// experimental RLPx v5 topic-discovery network.
|
// experimental RLPx v5 topic-discovery network.
|
||||||
var DiscoveryV5Bootnodes = []string{
|
var DiscoveryV5Bootnodes = []string{}
|
||||||
}
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// default node configuration options
|
||||||
|
var (
|
||||||
|
UseMainnetFlag = "false" // to be overridden via -ldflags '-X geth/params.UseMainnetFlag'
|
||||||
|
UseMainnet = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if UseMainnetFlag == "true" { // set at compile time, here we make sure to set corresponding boolean flag
|
||||||
|
UseMainnet = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrMissingDataDir = errors.New("missing required 'DataDir' parameter")
|
||||||
|
ErrMissingNetworkId = errors.New("missing required 'NetworkId' parameter")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChainConfig holds core blockchain settings. It is stored in the database on a per block basis.
|
||||||
|
type ChainConfig struct {
|
||||||
|
// ChainId identifies the current chain and is used for replay protection
|
||||||
|
ChainId *big.Int
|
||||||
|
|
||||||
|
// HomesteadBlock is Homestead switch block (nil = no fork, 0 = already homestead)
|
||||||
|
HomesteadBlock *big.Int
|
||||||
|
|
||||||
|
// DAOForkBlock TheDAO hard-fork switch block (nil = no fork)
|
||||||
|
DAOForkBlock *big.Int
|
||||||
|
|
||||||
|
// DAOForkSupport Whether the nodes supports or opposes the DAO hard-fork
|
||||||
|
DAOForkSupport bool
|
||||||
|
|
||||||
|
// EIP150Block is EIP150 HF block (nil = no fork)
|
||||||
|
EIP150Block *big.Int
|
||||||
|
|
||||||
|
// EIP150Hash is EIP150 HF hash (fast sync aid)
|
||||||
|
EIP150Hash common.Hash
|
||||||
|
|
||||||
|
// EIP155Block is EIP155 HF block
|
||||||
|
EIP155Block *big.Int
|
||||||
|
|
||||||
|
// EIP158Block is EIP158 HF block
|
||||||
|
EIP158Block *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// LightEthConfig holds LES-related configuration
|
||||||
|
// Status nodes are always lightweight clients (due to mobile platform constraints)
|
||||||
|
type LightEthConfig struct {
|
||||||
|
// Enabled flag specifies whether protocol is enabled
|
||||||
|
Enabled bool
|
||||||
|
|
||||||
|
// Genesis is JSON to seed the chain database with
|
||||||
|
Genesis string
|
||||||
|
|
||||||
|
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
|
||||||
|
DatabaseCache int
|
||||||
|
}
|
||||||
|
|
||||||
|
// WhisperConfig holds SHH-related configuration
|
||||||
|
type WhisperConfig struct {
|
||||||
|
// Enabled flag specifies whether protocol is enabled
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SwarmConfig holds Swarm-related configuration
|
||||||
|
type SwarmConfig struct {
|
||||||
|
// Enabled flag specifies whether protocol is enabled
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeConfig stores configuration options for a node
|
||||||
|
type NodeConfig struct {
|
||||||
|
// TestNet flag whether given configuration describes a test or mainnet
|
||||||
|
TestNet bool
|
||||||
|
|
||||||
|
// NetworkId sets network to use for selecting peers to connect to
|
||||||
|
NetworkId int
|
||||||
|
|
||||||
|
// DataDir is the file system folder the node should use for any data storage needs.
|
||||||
|
DataDir string
|
||||||
|
|
||||||
|
// Name sets the instance name of the node. It must not contain the / character.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Version exposes program's version. It is used in the devp2p node identifier.
|
||||||
|
Version string
|
||||||
|
|
||||||
|
// APIModules is a comma-separated list of API modules exposed via *any* (HTTP/WS/IPC) RPC interface.
|
||||||
|
APIModules string
|
||||||
|
|
||||||
|
// HTTPHost is the host interface on which to start the HTTP RPC server.
|
||||||
|
// Pass empty string if no HTTP RPC interface needs to be started.
|
||||||
|
HTTPHost string
|
||||||
|
|
||||||
|
// HTTPPort is the TCP port number on which to start the Geth's HTTP RPC server.
|
||||||
|
HTTPPort int
|
||||||
|
|
||||||
|
// WSHost is a host interface for the WebSocket RPC server
|
||||||
|
WSHost string
|
||||||
|
|
||||||
|
// WSPort is the TCP port number on which to start the Geth's WebSocket RPC server.
|
||||||
|
WSPort int
|
||||||
|
|
||||||
|
// WSEnabled specifies whether WS-RPC Server is enabled or not
|
||||||
|
WSEnabled bool
|
||||||
|
|
||||||
|
// IPCFile is filename of exposed IPC RPC Server
|
||||||
|
IPCFile string
|
||||||
|
|
||||||
|
// IPCEnabled specifies whether IPC-RPC Server is enabled or not
|
||||||
|
IPCEnabled bool
|
||||||
|
|
||||||
|
// TLSEnabled specifies whether TLS support should be enabled on node or not
|
||||||
|
// TLS support is only planned in go-ethereum, so we are using our own patch.
|
||||||
|
TLSEnabled bool
|
||||||
|
|
||||||
|
// MaxPeers is the maximum number of (global) peers that can be connected.
|
||||||
|
// Set to zero, if only static or trusted peers are allowed to connect.
|
||||||
|
MaxPeers int
|
||||||
|
|
||||||
|
// MaxPendingPeers is the maximum number of peers that can be pending in the
|
||||||
|
// handshake phase, counted separately for inbound and outbound connections.
|
||||||
|
MaxPendingPeers int
|
||||||
|
|
||||||
|
// LogToFile specified whether logs should be saved into file
|
||||||
|
LogEnabled bool
|
||||||
|
|
||||||
|
// LogFile is filename where exposed logs get written to
|
||||||
|
LogFile string
|
||||||
|
|
||||||
|
// LogLevel defines minimum log level. Valid names are "ERROR", "WARNING", "INFO", "DEBUG", and "DETAIL".
|
||||||
|
LogLevel string
|
||||||
|
|
||||||
|
// ChainConfig extra configuration for blockchain
|
||||||
|
*ChainConfig `json:"ChainConfig,"`
|
||||||
|
|
||||||
|
// LightEthConfig extra configuration for LES
|
||||||
|
LightEthConfig *LightEthConfig `json:"LightEthConfig,"`
|
||||||
|
|
||||||
|
// WhisperConfig extra configuration for SHH
|
||||||
|
WhisperConfig *WhisperConfig `json:"WhisperConfig,"`
|
||||||
|
|
||||||
|
// SwarmConfig extra configuration for Swarm and ENS
|
||||||
|
SwarmConfig *SwarmConfig `json:"SwarmConfig,"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNodeConfig creates new node configuration object
|
||||||
|
func NewNodeConfig(dataDir string, networkId int) (*NodeConfig, error) {
|
||||||
|
nodeConfig := &NodeConfig{
|
||||||
|
NetworkId: networkId,
|
||||||
|
DataDir: dataDir,
|
||||||
|
Name: DefaultClientIdentifier,
|
||||||
|
Version: Version,
|
||||||
|
HTTPHost: DefaultHTTPHost,
|
||||||
|
HTTPPort: DefaultHTTPPort,
|
||||||
|
APIModules: DefaultAPIModules,
|
||||||
|
WSHost: DefaultWSHost,
|
||||||
|
WSPort: DefaultWSPort,
|
||||||
|
MaxPeers: DefaultMaxPeers,
|
||||||
|
MaxPendingPeers: DefaultMaxPendingPeers,
|
||||||
|
IPCFile: DefaultIPCFile,
|
||||||
|
LogFile: DefaultLogFile,
|
||||||
|
LogLevel: DefaultLogLevel,
|
||||||
|
ChainConfig: &ChainConfig{},
|
||||||
|
LightEthConfig: &LightEthConfig{
|
||||||
|
Enabled: true,
|
||||||
|
DatabaseCache: DefaultDatabaseCache,
|
||||||
|
},
|
||||||
|
WhisperConfig: &WhisperConfig{
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
SwarmConfig: &SwarmConfig{},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig.populateChainConfig()
|
||||||
|
|
||||||
|
return nodeConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// populateChainConfig does necessary adjustments to config object (depending on network node will be runnin on)
|
||||||
|
func (c *NodeConfig) populateChainConfig() {
|
||||||
|
c.TestNet = false
|
||||||
|
if c.NetworkId == TestNetworkId {
|
||||||
|
c.TestNet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TestNet {
|
||||||
|
// Homestead fork
|
||||||
|
c.ChainConfig.HomesteadBlock = params.TestnetChainConfig.HomesteadBlock
|
||||||
|
|
||||||
|
// DAO fork
|
||||||
|
c.ChainConfig.DAOForkBlock = params.TestnetChainConfig.DAOForkBlock
|
||||||
|
c.ChainConfig.DAOForkSupport = params.TestnetChainConfig.DAOForkSupport
|
||||||
|
|
||||||
|
// DoS reprice fork
|
||||||
|
c.ChainConfig.EIP150Block = params.TestnetChainConfig.EIP150Block
|
||||||
|
c.ChainConfig.EIP150Hash = params.TestnetChainConfig.EIP150Hash
|
||||||
|
|
||||||
|
// DoS state cleanup fork
|
||||||
|
c.ChainConfig.EIP155Block = params.TestnetChainConfig.EIP155Block
|
||||||
|
c.ChainConfig.EIP158Block = params.TestnetChainConfig.EIP158Block
|
||||||
|
c.ChainConfig.ChainId = params.TestnetChainConfig.ChainId
|
||||||
|
|
||||||
|
c.LightEthConfig.Genesis = core.DefaultTestnetGenesisBlock()
|
||||||
|
} else {
|
||||||
|
// Homestead fork
|
||||||
|
c.ChainConfig.HomesteadBlock = params.MainNetHomesteadBlock
|
||||||
|
// DAO fork
|
||||||
|
c.ChainConfig.DAOForkBlock = params.MainNetDAOForkBlock
|
||||||
|
c.ChainConfig.DAOForkSupport = true
|
||||||
|
|
||||||
|
// DoS reprice fork
|
||||||
|
c.ChainConfig.EIP150Block = params.MainNetHomesteadGasRepriceBlock
|
||||||
|
c.ChainConfig.EIP150Hash = params.MainNetHomesteadGasRepriceHash
|
||||||
|
|
||||||
|
// DoS state cleanup fork
|
||||||
|
c.ChainConfig.EIP155Block = params.MainNetSpuriousDragon
|
||||||
|
c.ChainConfig.EIP158Block = params.MainNetSpuriousDragon
|
||||||
|
c.ChainConfig.ChainId = params.MainNetChainID
|
||||||
|
|
||||||
|
c.LightEthConfig.Genesis = core.DefaultGenesisBlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadNodeConfig parses incoming JSON and returned it as Config
|
||||||
|
func LoadNodeConfig(configJSON string) (*NodeConfig, error) {
|
||||||
|
nodeConfig, err := NewNodeConfig("", 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(configJSON))
|
||||||
|
//decoder.UseNumber()
|
||||||
|
|
||||||
|
// override default configuration with values by JSON input
|
||||||
|
if err := decoder.Decode(&nodeConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// repopulate
|
||||||
|
nodeConfig.populateChainConfig()
|
||||||
|
|
||||||
|
if len(nodeConfig.DataDir) == 0 {
|
||||||
|
return nil, ErrMissingDataDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.NetworkId <= 0 {
|
||||||
|
return nil, ErrMissingNetworkId
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save dumps configuration to the disk
|
||||||
|
func (c *NodeConfig) Save() error {
|
||||||
|
data, err := json.MarshalIndent(c, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(c.DataDir, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
configFilePath := filepath.Join(c.DataDir, "config.json")
|
||||||
|
if err := ioutil.WriteFile(configFilePath, data, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(logger.Info).Infof("config file saved: %v", configFilePath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String dumps config object as nicely indented JSON
|
||||||
|
func (c *NodeConfig) String() string {
|
||||||
|
data, _ := json.MarshalIndent(c, "", " ")
|
||||||
|
return string(data)
|
||||||
|
}
|
|
@ -0,0 +1,297 @@
|
||||||
|
package params_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
gethparams "github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/status-im/status-go/geth"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
var loadConfigTestCases = []struct {
|
||||||
|
name string
|
||||||
|
configJSON string
|
||||||
|
validator func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
`invalid input configuration`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 3
|
||||||
|
"DataDir": "$TMPDIR",
|
||||||
|
"Name": "TestStatusNode",
|
||||||
|
"WSPort": 8546,
|
||||||
|
"IPCEnabled": true,
|
||||||
|
"WSEnabled": false,
|
||||||
|
"LightEthConfig": {
|
||||||
|
"DatabaseCache": 64
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("error is expected, not thrown")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`missing required field (DataDir)`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"Name": "TestStatusNode"
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err != params.ErrMissingDataDir {
|
||||||
|
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingDataDir, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`missing required field (NetworkId)`,
|
||||||
|
`{
|
||||||
|
"DataDir": "$TMPDIR"
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err != params.ErrMissingNetworkId {
|
||||||
|
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingNetworkId, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`check static DataDir passing`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"DataDir": "/storage/emulated/0/ethereum/"
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expectedDataDir := "/storage/emulated/0/ethereum/"
|
||||||
|
if nodeConfig.DataDir != expectedDataDir {
|
||||||
|
t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`test parameter overriding`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"DataDir": "$TMPDIR",
|
||||||
|
"Name": "TestStatusNode",
|
||||||
|
"WSPort": 4242,
|
||||||
|
"IPCEnabled": true,
|
||||||
|
"WSEnabled": false,
|
||||||
|
"LightEthConfig": {
|
||||||
|
"DatabaseCache": 64
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.NetworkId != 3 {
|
||||||
|
t.Fatal("wrong NetworkId")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.Name != "TestStatusNode" {
|
||||||
|
t.Fatal("wrong Name")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.HTTPPort != params.DefaultHTTPPort {
|
||||||
|
t.Fatal("wrong HTTPPort")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.HTTPHost != params.DefaultHTTPHost {
|
||||||
|
t.Fatal("wrong HTTPHost")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.WSPort != 4242 {
|
||||||
|
t.Fatal("wrong WSPort")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.WSEnabled != false {
|
||||||
|
t.Fatal("wrong WSEnabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.IPCEnabled != true {
|
||||||
|
t.Fatal("wrong IPCEnabled")
|
||||||
|
}
|
||||||
|
if nodeConfig.LightEthConfig.DatabaseCache != 64 {
|
||||||
|
t.Fatal("wrong LightEthConfig.DatabaseCache")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`test loading Testnet config`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"DataDir": "$TMPDIR",
|
||||||
|
"Name": "TestStatusNode",
|
||||||
|
"WSPort": 8546,
|
||||||
|
"IPCEnabled": true,
|
||||||
|
"WSEnabled": false,
|
||||||
|
"LightEthConfig": {
|
||||||
|
"DatabaseCache": 64
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chainConfig := nodeConfig.ChainConfig
|
||||||
|
refChainConfig := gethparams.TestnetChainConfig
|
||||||
|
|
||||||
|
if chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.HomesteadBlock")
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkBlock != nil { // already forked
|
||||||
|
t.Fatal("invalid chainConfig.DAOForkBlock")
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkSupport != refChainConfig.DAOForkSupport {
|
||||||
|
t.Fatal("invalid chainConfig.DAOForkSupport")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.EIP150Block")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Hash != refChainConfig.EIP150Hash {
|
||||||
|
t.Fatal("invalid chainConfig.EIP150Hash")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.EIP155Block")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.EIP158Block")
|
||||||
|
}
|
||||||
|
if chainConfig.ChainId.Cmp(refChainConfig.ChainId) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.ChainId")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`test loading Mainnet config`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "$TMPDIR",
|
||||||
|
"Name": "TestStatusNode",
|
||||||
|
"WSPort": 8546,
|
||||||
|
"IPCEnabled": true,
|
||||||
|
"WSEnabled": false,
|
||||||
|
"LightEthConfig": {
|
||||||
|
"DatabaseCache": 64
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chainConfig := nodeConfig.ChainConfig
|
||||||
|
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.HomesteadBlock")
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.DAOForkBlock")
|
||||||
|
}
|
||||||
|
if chainConfig.DAOForkSupport != true {
|
||||||
|
t.Fatal("invalid chainConfig.DAOForkSupport")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.EIP150Block")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash {
|
||||||
|
t.Fatal("invalid chainConfig.EIP150Hash")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.EIP155Block")
|
||||||
|
}
|
||||||
|
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.EIP158Block")
|
||||||
|
}
|
||||||
|
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 {
|
||||||
|
t.Fatal("invalid chainConfig.ChainId")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`test loading Privatenet config`,
|
||||||
|
`{
|
||||||
|
"NetworkId": 311,
|
||||||
|
"DataDir": "$TMPDIR",
|
||||||
|
"Name": "TestStatusNode",
|
||||||
|
"WSPort": 8546,
|
||||||
|
"IPCEnabled": true,
|
||||||
|
"WSEnabled": false,
|
||||||
|
"ChainConfig": {
|
||||||
|
"ChainId": 311
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||||
|
//nodeConfig.LightEthConfig.Genesis = nodeConfig.LightEthConfig.Genesis[:125]
|
||||||
|
//fmt.Println(nodeConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
networkId := 311
|
||||||
|
|
||||||
|
if nodeConfig.NetworkId != networkId {
|
||||||
|
t.Fatalf("unexpected NetworkId, expected: %v, got: %v", networkId, nodeConfig.NetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig.ChainId.Int64() != int64(networkId) {
|
||||||
|
t.Fatalf("unexpected ChainConfig.ChainId, expected: %v, got: %v", networkId, nodeConfig.ChainId)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadNodeConfig(t *testing.T) {
|
||||||
|
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
for _, testCase := range loadConfigTestCases {
|
||||||
|
t.Log("test: " + testCase.name)
|
||||||
|
testCase.configJSON = strings.Replace(testCase.configJSON, "$TMPDIR", tmpDir, -1)
|
||||||
|
nodeConfig, err := params.LoadNodeConfig(testCase.configJSON)
|
||||||
|
testCase.validator(t, tmpDir, nodeConfig, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigWriteRead(t *testing.T) {
|
||||||
|
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
nodeConfig, err := params.NewNodeConfig(tmpDir, params.TestNetworkId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create new config object: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := nodeConfig.Save(); err != nil {
|
||||||
|
t.Fatalf("cannot persist configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot read configuration from disk: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
refConfigData := geth.LoadFromFile("testdata/config.testnet.json")
|
||||||
|
|
||||||
|
refConfigData = strings.Replace(refConfigData, "$TMPDIR", nodeConfig.DataDir, -1)
|
||||||
|
refConfigData = strings.Replace(refConfigData, "$VERSION", params.Version, -1)
|
||||||
|
if string(loadedConfigData) != refConfigData {
|
||||||
|
t.Fatalf("configuration mismatch,\nexpected: %v\ngot: %v", refConfigData, string(loadedConfigData))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultClientIdentifier is client identifier to advertise over the network
|
||||||
|
DefaultClientIdentifier = "StatusIM"
|
||||||
|
|
||||||
|
// DefaultDataDir is default data directory used by statusd executable
|
||||||
|
DefaultDataDir = "statusd-data"
|
||||||
|
|
||||||
|
// DefaultIPCFile is filename of exposed IPC RPC Server
|
||||||
|
DefaultIPCFile = "geth.ipc"
|
||||||
|
|
||||||
|
// DefaultHTTPHost is host interface for the HTTP RPC server
|
||||||
|
DefaultHTTPHost = "localhost"
|
||||||
|
|
||||||
|
// DefaultHTTPPort is HTTP-RPC port (replaced in unit tests)
|
||||||
|
DefaultHTTPPort = 8545
|
||||||
|
|
||||||
|
// DefaultAPIModules is a list of modules to expose vie HTTP RPC
|
||||||
|
// TODO remove "admin" on main net
|
||||||
|
DefaultAPIModules = "db,eth,net,web3,shh,personal,admin"
|
||||||
|
|
||||||
|
// DefaultWSHost is a host interface for the websocket RPC server
|
||||||
|
DefaultWSHost = "localhost"
|
||||||
|
|
||||||
|
// DefaultWSPort is a WS-RPC port (replaced in unit tests)
|
||||||
|
DefaultWSPort = 8546
|
||||||
|
|
||||||
|
// DefaultMaxPeers is the maximum number of global peers
|
||||||
|
DefaultMaxPeers = 25
|
||||||
|
|
||||||
|
// DefaultMaxPendingPeers is the maximum number of peers that can be pending in the
|
||||||
|
// handshake phase, counted separately for inbound and outbound connections.
|
||||||
|
DefaultMaxPendingPeers = 0
|
||||||
|
|
||||||
|
// DefaultGas default amount of gas used for transactions
|
||||||
|
DefaultGas = 180000
|
||||||
|
|
||||||
|
// DefaultFileDescriptorLimit is fd limit that database can use
|
||||||
|
DefaultFileDescriptorLimit = uint64(2048)
|
||||||
|
|
||||||
|
// DefaultDatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
|
||||||
|
DefaultDatabaseCache = 128
|
||||||
|
|
||||||
|
// DefaultLogFile defines where to write logs to
|
||||||
|
DefaultLogFile = "geth.log"
|
||||||
|
|
||||||
|
// DefaultLogLevel defines the minimum log level to report
|
||||||
|
DefaultLogLevel = "INFO"
|
||||||
|
|
||||||
|
// TestNetworkId is id of a test network
|
||||||
|
TestNetworkId = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gas price settings
|
||||||
|
var (
|
||||||
|
GasPrice = new(big.Int).Mul(big.NewInt(20), common.Shannon) // Minimal gas price to accept for mining a transactions
|
||||||
|
GpoMinGasPrice = new(big.Int).Mul(big.NewInt(20), common.Shannon) // Minimum suggested gas price
|
||||||
|
GpoMaxGasPrice = new(big.Int).Mul(big.NewInt(500), common.Shannon) // Maximum suggested gas price
|
||||||
|
GpoFullBlockRatio = 80 // Full block threshold for gas price calculation (%)
|
||||||
|
GpobaseStepDown = 10 // Suggested gas price base step down ratio (1/1000)
|
||||||
|
GpobaseStepUp = 100 // Suggested gas price base step up ratio (1/1000)
|
||||||
|
GpobaseCorrectionFactor = 110 // Suggested gas price base correction factor (%)
|
||||||
|
)
|
|
@ -0,0 +1,145 @@
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger is wrapper for custom logging
|
||||||
|
type Logger struct {
|
||||||
|
sync.Mutex
|
||||||
|
logFile *os.File
|
||||||
|
observer chan string
|
||||||
|
started chan struct{}
|
||||||
|
stopped chan struct{}
|
||||||
|
stopFlag bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var onceStartLogger sync.Once
|
||||||
|
|
||||||
|
// SetupLogger configs logger using parameters in config
|
||||||
|
func SetupLogger(config *NodeConfig) (nodeLogger *Logger, err error) {
|
||||||
|
if !config.LogEnabled {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeLogger = &Logger{
|
||||||
|
started: make(chan struct{}, 1),
|
||||||
|
stopped: make(chan struct{}, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
onceStartLogger.Do(func() {
|
||||||
|
err = nodeLogger.createAndStartLogger(config)
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetV allows to dynamically change log level of messages being written
|
||||||
|
func (l *Logger) SetV(logLevel string) {
|
||||||
|
glog.SetV(parseLogLevel(logLevel))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop marks logger as stopped, forcing to relinquish hold
|
||||||
|
// on os.Stderr and restore it back to the original
|
||||||
|
func (l *Logger) Stop() (stopped chan struct{}) {
|
||||||
|
l.Lock()
|
||||||
|
defer l.Unlock()
|
||||||
|
|
||||||
|
l.stopFlag = true
|
||||||
|
stopped = l.stopped
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe registers extra writer where logs should be written to.
|
||||||
|
// This method is used in unit tests, and should NOT be relied upon otherwise.
|
||||||
|
func (l *Logger) Observe(observer chan string) (started chan struct{}) {
|
||||||
|
l.observer = observer
|
||||||
|
started = l.started
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// createAndStartLogger initializes and starts logger by replacing os.Stderr with custom writer.
|
||||||
|
// Custom writer intercepts all requests to os.Stderr, then forwards to multiple readers, which
|
||||||
|
// include log file and the original os.Stderr (so that logs output on screen as well)
|
||||||
|
func (l *Logger) createAndStartLogger(config *NodeConfig) error {
|
||||||
|
// customize glog
|
||||||
|
glog.CopyStandardLogTo("INFO")
|
||||||
|
glog.SetToStderr(true)
|
||||||
|
glog.SetV(parseLogLevel(config.LogLevel))
|
||||||
|
|
||||||
|
// create log file
|
||||||
|
logFile, err := os.OpenFile(filepath.Join(config.DataDir, config.LogFile), os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject reader to pipe all writes to Stderr
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace Stderr
|
||||||
|
origStderr := os.Stderr
|
||||||
|
os.Stderr = w
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
|
||||||
|
// configure writer, send to the original os.Stderr and log file
|
||||||
|
logWriter := io.MultiWriter(origStderr, logFile)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() { // restore original Stderr
|
||||||
|
os.Stderr = origStderr
|
||||||
|
logFile.Close()
|
||||||
|
close(l.stopped)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// notify observer that it can start polling (unit test, normally)
|
||||||
|
close(l.started)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
fmt.Fprintln(logWriter, scanner.Text())
|
||||||
|
|
||||||
|
if l.observer != nil {
|
||||||
|
l.observer <- scanner.Text()
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow to restore original os.Stderr if logger is stopped
|
||||||
|
if l.stopFlag {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
fmt.Fprintf(origStderr, "error reading logs: %v\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseLogLevel parses string and returns logger.* constant
|
||||||
|
func parseLogLevel(logLevel string) int {
|
||||||
|
switch logLevel {
|
||||||
|
case "ERROR":
|
||||||
|
return logger.Error
|
||||||
|
case "WARNING":
|
||||||
|
return logger.Warn
|
||||||
|
case "INFO":
|
||||||
|
return logger.Info
|
||||||
|
case "DEBUG":
|
||||||
|
return logger.Debug
|
||||||
|
case "DETAIL":
|
||||||
|
return logger.Detail
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger.Info
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
package params_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogger(t *testing.T) {
|
||||||
|
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-logger-tests")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
nodeConfig, err := params.NewNodeConfig(tmpDir, params.TestNetworkId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("cannot create config object")
|
||||||
|
}
|
||||||
|
nodeLogger, err := params.SetupLogger(nodeConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("cannot create logger object")
|
||||||
|
}
|
||||||
|
if nodeLogger != nil {
|
||||||
|
t.Fatalf("logger is not empty (while logs are disabled): %v", nodeLogger)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig.LogEnabled = true
|
||||||
|
nodeLogger, err = params.SetupLogger(nodeConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("cannot create logger object")
|
||||||
|
}
|
||||||
|
if nodeLogger == nil {
|
||||||
|
t.Fatal("logger is empty (while logs are enabled)")
|
||||||
|
}
|
||||||
|
|
||||||
|
logReader := make(chan string, 100)
|
||||||
|
loggerStarted := nodeLogger.Observe(logReader)
|
||||||
|
<-loggerStarted // allow logger to setup itself
|
||||||
|
|
||||||
|
expectedLogTextInLogFile := "" // aggregate log contents accross all tests
|
||||||
|
validateLoggerObserverText := func(observer chan string, expectedLogText string) {
|
||||||
|
logText := ""
|
||||||
|
|
||||||
|
select {
|
||||||
|
case logText = <-observer:
|
||||||
|
expectedLogTextInLogFile += logText + "\n"
|
||||||
|
logText = logText[len(logText)-len(expectedLogText):] // as logs can be prepended with glog info
|
||||||
|
case <-time.After(3 * time.Second):
|
||||||
|
}
|
||||||
|
|
||||||
|
if logText != expectedLogText {
|
||||||
|
t.Fatalf("invalid log, expected: %#v, got: %#v", expectedLogText, logText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loggerTestCases := []struct {
|
||||||
|
name string
|
||||||
|
log func()
|
||||||
|
validate func()
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"log using standard log package",
|
||||||
|
func() {
|
||||||
|
log.Println("use standard log package")
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
validateLoggerObserverText(logReader, "use standard log package")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"log using standard glog package",
|
||||||
|
func() {
|
||||||
|
glog.V(logger.Info).Infoln("use glog package")
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
validateLoggerObserverText(logReader, "use glog package")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"log using os.Stderr (write directly to it)",
|
||||||
|
func() {
|
||||||
|
fmt.Fprintln(os.Stderr, "use os.Stderr package")
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
validateLoggerObserverText(logReader, "use os.Stderr package")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"log using DEBUG log level (with appropriate level set)",
|
||||||
|
func() {
|
||||||
|
nodeLogger.SetV("DEBUG")
|
||||||
|
glog.V(logger.Debug).Info("logged DEBUG log level message")
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
validateLoggerObserverText(logReader, "logged DEBUG log level message")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"log using DEBUG log level (with appropriate level NOT set)",
|
||||||
|
func() {
|
||||||
|
nodeLogger.SetV("INFO")
|
||||||
|
glog.V(logger.Info).Info("logged INFO log level message")
|
||||||
|
glog.V(logger.Debug).Info("logged DEBUG log level message")
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
validateLoggerObserverText(logReader, "logged INFO log level message")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range loggerTestCases {
|
||||||
|
t.Log("test: " + testCase.name)
|
||||||
|
testCase.log()
|
||||||
|
testCase.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
logFileContents, err := ioutil.ReadFile(filepath.Join(tmpDir, nodeConfig.LogFile))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot read logs file: %v", err)
|
||||||
|
}
|
||||||
|
if string(logFileContents) != expectedLogTextInLogFile {
|
||||||
|
t.Fatalf("wrong content of log file, expected:\n%v\ngot:\n%v", expectedLogTextInLogFile, string(logFileContents))
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
glog.Infoln("logging message: ", i)
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// stop logger and see if os.Stderr and glog continue functioning
|
||||||
|
<-nodeLogger.Stop()
|
||||||
|
|
||||||
|
glog.Infoln("logging message: this message happens after custom logger has been stopped")
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,15 @@
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
VersionMajor = 0 // Major version component of the current release
|
||||||
|
VersionMinor = 9 // Minor version component of the current release
|
||||||
|
VersionPatch = 5 // Patch version component of the current release
|
||||||
|
VersionMeta = "stable" // Version metadata to append to the version string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version exposes string representation of program version.
|
||||||
|
var Version = fmt.Sprintf("%d.%d.%d-%s", VersionMajor, VersionMinor, VersionPatch, VersionMeta)
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/les/status"
|
"github.com/ethereum/go-ethereum/les/status"
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQueuedContracts(t *testing.T) {
|
func TestQueuedContracts(t *testing.T) {
|
||||||
|
@ -30,7 +31,7 @@ func TestQueuedContracts(t *testing.T) {
|
||||||
backend := lightEthereum.StatusBackend
|
backend := lightEthereum.StatusBackend
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
sampleAddress, _, _, err := geth.CreateAccount(newAccountPassword)
|
sampleAddress, _, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -40,7 +41,7 @@ func TestQueuedContracts(t *testing.T) {
|
||||||
|
|
||||||
// make sure you panic if transaction complete doesn't return
|
// make sure you panic if transaction complete doesn't return
|
||||||
completeQueuedTransaction := make(chan struct{}, 1)
|
completeQueuedTransaction := make(chan struct{}, 1)
|
||||||
geth.PanicAfter(60*time.Second, completeQueuedTransaction, "TestQueuedContracts")
|
geth.PanicAfter(5*time.Second, completeQueuedTransaction, "TestQueuedContracts")
|
||||||
|
|
||||||
// replace transaction notification handler
|
// replace transaction notification handler
|
||||||
var txHash = common.Hash{}
|
var txHash = common.Hash{}
|
||||||
|
@ -52,37 +53,36 @@ func TestQueuedContracts(t *testing.T) {
|
||||||
}
|
}
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
t.Logf("transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
// the first call will fail (we are not logged in, but trying to complete tx)
|
// the first call will fail (we are not logged in, but trying to complete tx)
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != status.ErrInvalidCompleteTxSender {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != status.ErrInvalidCompleteTxSender {
|
||||||
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the second call will also fail (we are logged in as different user)
|
// the second call will also fail (we are logged in as different user)
|
||||||
if err := geth.SelectAccount(sampleAddress, newAccountPassword); err != nil {
|
if err := geth.SelectAccount(sampleAddress, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", sampleAddress)
|
t.Errorf("cannot select account: %v", sampleAddress)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != status.ErrInvalidCompleteTxSender {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != status.ErrInvalidCompleteTxSender {
|
||||||
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the third call will work as expected (as we are logged in with correct credentials)
|
// the third call will work as expected (as we are logged in with correct credentials)
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("contract transaction complete: https://testnet.etherscan.io/tx/%s", txHash.Hex())
|
t.Logf("contract transaction complete: https://testnet.etherscan.io/tx/%s", txHash.Hex())
|
||||||
completeQueuedTransaction <- struct{}{} // so that timeout is aborted
|
close(completeQueuedTransaction)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -93,22 +93,22 @@ func TestQueuedContracts(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: nil, // marker, contract creation is expected
|
To: nil, // marker, contract creation is expected
|
||||||
//Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), common.Ether)),
|
//Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), common.Ether)),
|
||||||
Gas: (*hexutil.Big)(big.NewInt(geth.DefaultGas)),
|
Gas: (*hexutil.Big)(big.NewInt(params.DefaultGas)),
|
||||||
Data: byteCode,
|
Data: byteCode,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: cannot send transaction: %v", err)
|
t.Errorf("Test failed: cannot send transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(txHash, txHashCheck) {
|
if txHashCheck.Hex() != txHash.Hex() {
|
||||||
t.Errorf("Transaction hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck, txHash)
|
t.Errorf("Transaction hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck.Hex(), txHash.Hex())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
<-completeQueuedTransaction
|
||||||
|
|
||||||
if reflect.DeepEqual(txHashCheck, common.Hash{}) {
|
if reflect.DeepEqual(txHashCheck, common.Hash{}) {
|
||||||
t.Error("Test failed: transaction was never queued or completed")
|
t.Error("Test failed: transaction was never queued or completed")
|
||||||
|
@ -137,7 +137,7 @@ func TestQueuedTransactions(t *testing.T) {
|
||||||
backend := lightEthereum.StatusBackend
|
backend := lightEthereum.StatusBackend
|
||||||
|
|
||||||
// create an account
|
// create an account
|
||||||
sampleAddress, _, _, err := geth.CreateAccount(newAccountPassword)
|
sampleAddress, _, _, err := geth.CreateAccount(testConfig.Account1.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create account: %v", err)
|
t.Errorf("could not create account: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -147,7 +147,7 @@ func TestQueuedTransactions(t *testing.T) {
|
||||||
|
|
||||||
// make sure you panic if transaction complete doesn't return
|
// make sure you panic if transaction complete doesn't return
|
||||||
completeQueuedTransaction := make(chan struct{}, 1)
|
completeQueuedTransaction := make(chan struct{}, 1)
|
||||||
geth.PanicAfter(60*time.Second, completeQueuedTransaction, "TestQueuedTransactions")
|
geth.PanicAfter(5*time.Second, completeQueuedTransaction, "TestQueuedTransactions")
|
||||||
|
|
||||||
// replace transaction notification handler
|
// replace transaction notification handler
|
||||||
var txHash = common.Hash{}
|
var txHash = common.Hash{}
|
||||||
|
@ -159,56 +159,55 @@ func TestQueuedTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
t.Logf("transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
// the first call will fail (we are not logged in, but trying to complete tx)
|
// the first call will fail (we are not logged in, but trying to complete tx)
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != status.ErrInvalidCompleteTxSender {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != status.ErrInvalidCompleteTxSender {
|
||||||
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the second call will also fail (we are logged in as different user)
|
// the second call will also fail (we are logged in as different user)
|
||||||
if err := geth.SelectAccount(sampleAddress, newAccountPassword); err != nil {
|
if err := geth.SelectAccount(sampleAddress, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", sampleAddress)
|
t.Errorf("cannot select account: %v", sampleAddress)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != status.ErrInvalidCompleteTxSender {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != status.ErrInvalidCompleteTxSender {
|
||||||
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
t.Errorf("expected error on queued transation[%v] not thrown: expected %v, got %v", event["id"], status.ErrInvalidCompleteTxSender, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the third call will work as expected (as we are logged in with correct credentials)
|
// the third call will work as expected (as we are logged in with correct credentials)
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("transaction complete: https://testnet.etherscan.io/tx/%s", txHash.Hex())
|
t.Logf("transaction complete: https://testnet.etherscan.io/tx/%s", txHash.Hex())
|
||||||
completeQueuedTransaction <- struct{}{} // so that timeout is aborted
|
close(completeQueuedTransaction)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// this call blocks, up until Complete Transaction is called
|
// this call blocks, up until Complete Transaction is called
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: cannot send transaction: %v", err)
|
t.Errorf("Test failed: cannot send transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(txHash, txHashCheck) {
|
if txHashCheck.Hex() != txHash.Hex() {
|
||||||
t.Errorf("Transaction hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck, txHash)
|
t.Errorf("Transaction hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck.Hex(), txHash.Hex())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
<-completeQueuedTransaction
|
||||||
|
|
||||||
if reflect.DeepEqual(txHashCheck, common.Hash{}) {
|
if reflect.DeepEqual(txHashCheck, common.Hash{}) {
|
||||||
t.Error("Test failed: transaction was never queued or completed")
|
t.Error("Test failed: transaction was never queued or completed")
|
||||||
|
@ -237,8 +236,8 @@ func TestDoubleCompleteQueuedTransactions(t *testing.T) {
|
||||||
backend := lightEthereum.StatusBackend
|
backend := lightEthereum.StatusBackend
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,21 +262,18 @@ func TestDoubleCompleteQueuedTransactions(t *testing.T) {
|
||||||
|
|
||||||
// try with wrong password
|
// try with wrong password
|
||||||
// make sure that tx is NOT removed from the queue (by re-trying with the correct password)
|
// make sure that tx is NOT removed from the queue (by re-trying with the correct password)
|
||||||
if _, err = geth.CompleteTransaction(txId, testAddressPassword+"wrong"); err != keystore.ErrDecrypt {
|
if _, err = geth.CompleteTransaction(txId, testConfig.Account1.Password+"wrong"); err != keystore.ErrDecrypt {
|
||||||
t.Errorf("expects wrong password error, but call succeeded (or got another error: %v)", err)
|
t.Errorf("expects wrong password error, but call succeeded (or got another error: %v)", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
|
||||||
if txCount := backend.TransactionQueue().Count(); txCount != 1 {
|
if txCount := backend.TransactionQueue().Count(); txCount != 1 {
|
||||||
t.Errorf("txqueue cannot be empty, as tx has failed: expected = 1, got = %d", txCount)
|
t.Errorf("txqueue cannot be empty, as tx has failed: expected = 1, got = %d", txCount)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// now try to complete transaction, but with the correct password
|
// now try to complete transaction, but with the correct password
|
||||||
t.Log("allow 5 seconds before sedning the second CompleteTransaction")
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != nil {
|
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -315,8 +311,8 @@ func TestDoubleCompleteQueuedTransactions(t *testing.T) {
|
||||||
|
|
||||||
// this call blocks, and should return on *second* attempt to CompleteTransaction (w/ the correct password)
|
// this call blocks, and should return on *second* attempt to CompleteTransaction (w/ the correct password)
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -324,8 +320,8 @@ func TestDoubleCompleteQueuedTransactions(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(txHash, txHashCheck) {
|
if txHashCheck.Hex() != txHash.Hex() {
|
||||||
t.Errorf("tx hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck, txHash)
|
t.Errorf("tx hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck.Hex(), txHash.Hex())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,9 +339,6 @@ func TestDoubleCompleteQueuedTransactions(t *testing.T) {
|
||||||
t.Error("expected tx failure signal is not received")
|
t.Error("expected tx failure signal is not received")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Log("sleep extra time, to allow sync")
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiscardQueuedTransactions(t *testing.T) {
|
func TestDiscardQueuedTransactions(t *testing.T) {
|
||||||
|
@ -367,8 +360,8 @@ func TestDiscardQueuedTransactions(t *testing.T) {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +396,7 @@ func TestDiscardQueuedTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
_, err = geth.CompleteTransaction(txId, testAddressPassword)
|
_, err = geth.CompleteTransaction(txId, testConfig.Account1.Password)
|
||||||
if err.Error() != "transaction hash not found" {
|
if err.Error() != "transaction hash not found" {
|
||||||
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
||||||
return
|
return
|
||||||
|
@ -441,8 +434,8 @@ func TestDiscardQueuedTransactions(t *testing.T) {
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != status.ErrQueuedTxDiscarded {
|
if err != status.ErrQueuedTxDiscarded {
|
||||||
|
@ -464,9 +457,6 @@ func TestDiscardQueuedTransactions(t *testing.T) {
|
||||||
t.Error("expected tx failure signal is not received")
|
t.Error("expected tx failure signal is not received")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Log("sleep extra time, to allow sync")
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompleteMultipleQueuedTransactions(t *testing.T) {
|
func TestCompleteMultipleQueuedTransactions(t *testing.T) {
|
||||||
|
@ -488,8 +478,8 @@ func TestCompleteMultipleQueuedTransactions(t *testing.T) {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,8 +508,8 @@ func TestCompleteMultipleQueuedTransactions(t *testing.T) {
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -542,7 +532,7 @@ func TestCompleteMultipleQueuedTransactions(t *testing.T) {
|
||||||
updatedTxIdStrings, _ := json.Marshal(parsedIds)
|
updatedTxIdStrings, _ := json.Marshal(parsedIds)
|
||||||
|
|
||||||
// complete
|
// complete
|
||||||
results := geth.CompleteTransactions(string(updatedTxIdStrings), testAddressPassword)
|
results := geth.CompleteTransactions(string(updatedTxIdStrings), testConfig.Account1.Password)
|
||||||
if len(results) != (testTxCount+1) || results["invalid-tx-id"].Error.Error() != "transaction hash not found" {
|
if len(results) != (testTxCount+1) || results["invalid-tx-id"].Error.Error() != "transaction hash not found" {
|
||||||
t.Errorf("cannot complete txs: %v", results)
|
t.Errorf("cannot complete txs: %v", results)
|
||||||
return
|
return
|
||||||
|
@ -619,8 +609,8 @@ func TestDiscardMultipleQueuedTransactions(t *testing.T) {
|
||||||
backend.TransactionQueue().Reset()
|
backend.TransactionQueue().Reset()
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,8 +668,8 @@ func TestDiscardMultipleQueuedTransactions(t *testing.T) {
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||||
From: geth.FromAddress(testAddress),
|
From: geth.FromAddress(testConfig.Account1.Address),
|
||||||
To: geth.ToAddress(testAddress1),
|
To: geth.ToAddress(testConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
})
|
})
|
||||||
if err != status.ErrQueuedTxDiscarded {
|
if err != status.ErrQueuedTxDiscarded {
|
||||||
|
@ -709,7 +699,7 @@ func TestDiscardMultipleQueuedTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
completeResults := geth.CompleteTransactions(string(updatedTxIdStrings), testAddressPassword)
|
completeResults := geth.CompleteTransactions(string(updatedTxIdStrings), testConfig.Account1.Password)
|
||||||
if len(completeResults) != (testTxCount + 1) {
|
if len(completeResults) != (testTxCount + 1) {
|
||||||
t.Error("unexpected number of errors (call to CompleteTransaction should not succeed)")
|
t.Error("unexpected number of errors (call to CompleteTransaction should not succeed)")
|
||||||
}
|
}
|
||||||
|
@ -769,8 +759,8 @@ func TestNonExistentQueuedTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,11 +778,10 @@ func TestNonExistentQueuedTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
t.Logf("Transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
// next call is the very same one, but with the correct password
|
// next call is the very same one, but with the correct password
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -803,7 +792,7 @@ func TestNonExistentQueuedTransactions(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// try completing non-existing transaction
|
// try completing non-existing transaction
|
||||||
if _, err = geth.CompleteTransaction("some-bad-transaction-id", testAddressPassword); err == nil {
|
if _, err = geth.CompleteTransaction("some-bad-transaction-id", testConfig.Account1.Password); err == nil {
|
||||||
t.Error("error expected and not recieved")
|
t.Error("error expected and not recieved")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -829,8 +818,8 @@ func TestEvictionOfQueuedTransactions(t *testing.T) {
|
||||||
backend := lightEthereum.StatusBackend
|
backend := lightEthereum.StatusBackend
|
||||||
|
|
||||||
// log into account from which transactions will be sent
|
// log into account from which transactions will be sent
|
||||||
if err := geth.SelectAccount(testAddress, testAddressPassword); err != nil {
|
if err := geth.SelectAccount(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot select account: %v", testAddress)
|
t.Errorf("cannot select account: %v", testConfig.Account1.Address)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,11 +837,10 @@ func TestEvictionOfQueuedTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
t.Logf("Transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
t.Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
// next call is the very same one, but with the correct password
|
// next call is the very same one, but with the correct password
|
||||||
if txHash, err = geth.CompleteTransaction(event["id"].(string), testAddressPassword); err != nil {
|
if txHash, err = geth.CompleteTransaction(event["id"].(string), testConfig.Account1.Password); err != nil {
|
||||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
144
geth/utils.go
144
geth/utils.go
|
@ -11,26 +11,43 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var muPrepareTestNode sync.Mutex
|
var (
|
||||||
|
muPrepareTestNode sync.Mutex
|
||||||
const (
|
RootDir string
|
||||||
TestDataDir = "../.ethereumtest"
|
DataDir string
|
||||||
TestNodeSyncSeconds = 60
|
TestDataDir string
|
||||||
TestNodeHTTPPort = 8645
|
|
||||||
TestNodeWSPort = 8646
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup root directory
|
||||||
|
RootDir = filepath.Dir(pwd)
|
||||||
|
if strings.HasSuffix(RootDir, "geth") || strings.HasSuffix(RootDir, "cmd") { // we need to hop one more level
|
||||||
|
RootDir = filepath.Join(RootDir, "..")
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup auxiliary directories
|
||||||
|
DataDir = filepath.Join(RootDir, "data")
|
||||||
|
TestDataDir = filepath.Join(RootDir, ".ethereumtest")
|
||||||
|
}
|
||||||
|
|
||||||
type NodeNotificationHandler func(jsonEvent string)
|
type NodeNotificationHandler func(jsonEvent string)
|
||||||
|
|
||||||
var notificationHandler NodeNotificationHandler = TriggerDefaultNodeNotificationHandler
|
var notificationHandler NodeNotificationHandler = TriggerDefaultNodeNotificationHandler
|
||||||
|
@ -61,6 +78,35 @@ func TriggerTestSignal() {
|
||||||
C.StatusServiceSignalEvent(C.CString(`{"answer": 42}`))
|
C.StatusServiceSignalEvent(C.CString(`{"answer": 42}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestConfig contains shared (among different test packages) parameters
|
||||||
|
type TestConfig struct {
|
||||||
|
Node struct {
|
||||||
|
SyncSeconds time.Duration
|
||||||
|
HTTPPort int
|
||||||
|
WSPort int
|
||||||
|
}
|
||||||
|
Account1 struct {
|
||||||
|
Address string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
Account2 struct {
|
||||||
|
Address string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadTestConfig loads test configuration values from disk
|
||||||
|
func LoadTestConfig() (*TestConfig, error) {
|
||||||
|
var testConfig TestConfig
|
||||||
|
|
||||||
|
configData := LoadFromFile(filepath.Join(DataDir, "test-data.json"))
|
||||||
|
if err := json.Unmarshal([]byte(configData), &testConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &testConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
func CopyFile(dst, src string) error {
|
func CopyFile(dst, src string) error {
|
||||||
s, err := os.Open(src)
|
s, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -106,37 +152,52 @@ func PrepareTestNode() (err error) {
|
||||||
|
|
||||||
defer HaltOnPanic()
|
defer HaltOnPanic()
|
||||||
|
|
||||||
|
testConfig, err := LoadTestConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
syncRequired := false
|
syncRequired := false
|
||||||
if _, err := os.Stat(filepath.Join(TestDataDir, "testnet")); os.IsNotExist(err) {
|
if _, err := os.Stat(TestDataDir); os.IsNotExist(err) {
|
||||||
syncRequired = true
|
syncRequired = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare node directory
|
// prepare node directory
|
||||||
dataDir, err := PreprocessDataDir(TestDataDir)
|
if err := os.MkdirAll(filepath.Join(TestDataDir, "keystore"), os.ModePerm); err != nil {
|
||||||
if err != nil {
|
|
||||||
glog.V(logger.Warn).Infoln("make node failed:", err)
|
glog.V(logger.Warn).Infoln("make node failed:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// import test account (with test ether on it)
|
// import test account (with test ether on it)
|
||||||
dst := filepath.Join(TestDataDir, "testnet", "keystore", "test-account.pk")
|
importTestAccount := func(accountFile string) error {
|
||||||
if _, err := os.Stat(dst); os.IsNotExist(err) {
|
dst := filepath.Join(TestDataDir, "keystore", accountFile)
|
||||||
err = CopyFile(dst, filepath.Join("../data", "test-account.pk"))
|
if _, err := os.Stat(dst); os.IsNotExist(err) {
|
||||||
if err != nil {
|
err = CopyFile(dst, filepath.Join(RootDir, "data", accountFile))
|
||||||
glog.V(logger.Warn).Infof("cannot copy test account PK: %v", err)
|
if err != nil {
|
||||||
return err
|
glog.V(logger.Warn).Infof("cannot copy test account PK: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := importTestAccount("test-account1.pk"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := importTestAccount("test-account2.pk"); err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start geth node and wait for it to initialize
|
// start geth node and wait for it to initialize
|
||||||
err = CreateAndRunNode(&NodeConfig{
|
config, err := params.NewNodeConfig(TestDataDir, params.TestNetworkId)
|
||||||
DataDir: dataDir,
|
if err != nil {
|
||||||
IPCEnabled: false,
|
return err
|
||||||
HTTPPort: TestNodeHTTPPort, // to avoid conflicts with running app, using different port in tests
|
}
|
||||||
WSEnabled: false,
|
config.HTTPPort = testConfig.Node.HTTPPort // to avoid conflicts with running app, using different port in tests
|
||||||
WSPort: TestNodeWSPort, // ditto
|
config.WSPort = testConfig.Node.WSPort // ditto
|
||||||
TLSEnabled: false,
|
config.LogEnabled = true
|
||||||
})
|
|
||||||
|
err = CreateAndRunNode(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -156,10 +217,8 @@ func PrepareTestNode() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if syncRequired {
|
if syncRequired {
|
||||||
glog.V(logger.Warn).Infof("Sync is required, it will take %d seconds", TestNodeSyncSeconds)
|
glog.V(logger.Warn).Infof("Sync is required, it will take %d seconds", testConfig.Node.SyncSeconds)
|
||||||
time.Sleep(TestNodeSyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done
|
time.Sleep(testConfig.Node.SyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done
|
||||||
} else {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -172,17 +231,6 @@ func RemoveTestNode() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreprocessDataDir(dataDir string) (string, error) {
|
|
||||||
testDataDir := path.Join(dataDir, "testnet", "keystore")
|
|
||||||
if _, err := os.Stat(testDataDir); os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(testDataDir, 0755); err != nil {
|
|
||||||
return dataDir, ErrDataDirPreprocessingFailed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataDir, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PanicAfter throws panic() after waitSeconds, unless abort channel receives notification
|
// PanicAfter throws panic() after waitSeconds, unless abort channel receives notification
|
||||||
func PanicAfter(waitSeconds time.Duration, abort chan struct{}, desc string) {
|
func PanicAfter(waitSeconds time.Duration, abort chan struct{}, desc string) {
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -222,3 +270,19 @@ func ParseAccountString(account string) (accounts.Account, error) {
|
||||||
|
|
||||||
return accounts.Account{}, ErrInvalidAccountAddressOrKey
|
return accounts.Account{}, ErrInvalidAccountAddressOrKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddressToDecryptedAccount tries to load and decrypt account with a given password
|
||||||
|
func AddressToDecryptedAccount(address, password string) (accounts.Account, *keystore.Key, error) {
|
||||||
|
nodeManager := NodeManagerInstance()
|
||||||
|
keyStore, err := nodeManager.AccountKeyStore()
|
||||||
|
if err != nil {
|
||||||
|
return accounts.Account{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := ParseAccountString(address)
|
||||||
|
if err != nil {
|
||||||
|
return accounts.Account{}, nil, ErrAddressToAccountMappingFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyStore.AccountDecryptedKey(account, password)
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,6 @@ import (
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
whisperFilters []int
|
|
||||||
)
|
|
||||||
|
|
||||||
func onWhisperMessage(message *whisper.Message) {
|
func onWhisperMessage(message *whisper.Message) {
|
||||||
SendSignal(SignalEnvelope{
|
SendSignal(SignalEnvelope{
|
||||||
Type: "whisper",
|
Type: "whisper",
|
||||||
|
@ -25,36 +21,3 @@ func onWhisperMessage(message *whisper.Message) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddWhisperFilter(args whisper.NewFilterArgs) int {
|
|
||||||
whisperService, err := NodeManagerInstance().WhisperService()
|
|
||||||
if err != nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := whisper.Filter{
|
|
||||||
To: crypto.ToECDSAPub(common.FromHex(args.To)),
|
|
||||||
From: crypto.ToECDSAPub(common.FromHex(args.From)),
|
|
||||||
Topics: whisper.NewFilterTopics(args.Topics...),
|
|
||||||
Fn: onWhisperMessage,
|
|
||||||
}
|
|
||||||
|
|
||||||
id := whisperService.Watch(filter)
|
|
||||||
whisperFilters = append(whisperFilters, id)
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveWhisperFilter(idFilter int) {
|
|
||||||
whisperService, err := NodeManagerInstance().WhisperService()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
whisperService.Unwatch(idFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClearWhisperFilters() {
|
|
||||||
for _, idFilter := range whisperFilters {
|
|
||||||
RemoveWhisperFilter(idFilter)
|
|
||||||
}
|
|
||||||
whisperFilters = nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
package geth_test
|
package geth_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||||
"github.com/status-im/status-go/geth"
|
"github.com/status-im/status-go/geth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWhisperMessaging(t *testing.T) {
|
func TestWhisperFilterRace(t *testing.T) {
|
||||||
err := geth.PrepareTestNode()
|
err := geth.PrepareTestNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -25,138 +23,58 @@ func TestWhisperMessaging(t *testing.T) {
|
||||||
|
|
||||||
whisperAPI := whisper.NewPublicWhisperAPI(whisperService)
|
whisperAPI := whisper.NewPublicWhisperAPI(whisperService)
|
||||||
|
|
||||||
// prepare message
|
// account1
|
||||||
postArgs := whisper.PostArgs{
|
_, accountKey1, err := geth.AddressToDecryptedAccount(testConfig.Account1.Address, testConfig.Account1.Password)
|
||||||
From: "",
|
|
||||||
To: "",
|
|
||||||
TTL: 10,
|
|
||||||
Topics: [][]byte{[]byte("test topic")},
|
|
||||||
Payload: "test message",
|
|
||||||
}
|
|
||||||
|
|
||||||
// create an accounts
|
|
||||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
t.Fatal(err)
|
||||||
t.Error("Test failed: could not create account")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
accountKey1Hex := common.ToHex(crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey))
|
||||||
|
|
||||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
whisperService.AddIdentity(accountKey1.PrivateKey)
|
||||||
|
if ok, err := whisperAPI.HasIdentity(accountKey1Hex); err != nil || !ok {
|
||||||
|
t.Fatalf("identity not injected: %v", accountKey1Hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// account2
|
||||||
|
_, accountKey2, err := geth.AddressToDecryptedAccount(testConfig.Account2.Address, testConfig.Account2.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
t.Fatal(err)
|
||||||
t.Error("Test failed: could not create account")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
accountKey2Hex := common.ToHex(crypto.FromECDSAPub(&accountKey2.PrivateKey.PublicKey))
|
||||||
|
|
||||||
// start watchers
|
whisperService.AddIdentity(accountKey2.PrivateKey)
|
||||||
var receivedMessages = map[string]bool{
|
if ok, err := whisperAPI.HasIdentity(accountKey2Hex); err != nil || !ok {
|
||||||
whisperMessage1: false,
|
t.Fatalf("identity not injected: %v", accountKey2Hex)
|
||||||
whisperMessage2: false,
|
|
||||||
whisperMessage3: false,
|
|
||||||
whisperMessage4: false,
|
|
||||||
whisperMessage5: false,
|
|
||||||
}
|
|
||||||
whisperService.Watch(whisper.Filter{
|
|
||||||
//From: crypto.ToECDSAPub(common.FromHex(pubKey1)),
|
|
||||||
//To: crypto.ToECDSAPub(common.FromHex(pubKey2)),
|
|
||||||
Fn: func(msg *whisper.Message) {
|
|
||||||
//t.Logf("Whisper message received: %s", msg.Payload)
|
|
||||||
receivedMessages[string(msg.Payload)] = true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// inject key of newly created account into Whisper, as identity
|
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
|
||||||
t.Error("identity already present in whisper")
|
|
||||||
}
|
|
||||||
err = geth.SelectAccount(address1, newAccountPassword)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
identitySucceess := whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1)))
|
|
||||||
if !identitySucceess || err != nil {
|
|
||||||
t.Errorf("identity not injected into whisper: %v", err)
|
|
||||||
}
|
|
||||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) { // ensure that second id is not injected
|
|
||||||
t.Error("identity already present in whisper")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// double selecting (shouldn't be a problem)
|
// race filter addition
|
||||||
err = geth.SelectAccount(address1, newAccountPassword)
|
filterAdded := make(chan struct{})
|
||||||
if err != nil {
|
allFiltersAdded := make(chan struct{})
|
||||||
t.Errorf("Test failed: could not select account: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST 0: From != nil && To != nil: encrypted signed message (but we cannot decrypt it - so watchers will not report this)
|
go func() {
|
||||||
postArgs.From = pubKey1
|
counter := 10
|
||||||
postArgs.To = pubKey2 // owner of that public key will be able to decrypt it
|
for range filterAdded {
|
||||||
postSuccess, err := whisperAPI.Post(postArgs)
|
counter--
|
||||||
if !postSuccess || err != nil {
|
if counter <= 0 {
|
||||||
t.Errorf("could not post to whisper: %v", err)
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST 1: From != nil && To != nil: encrypted signed message (to self)
|
|
||||||
postArgs.From = pubKey1
|
|
||||||
postArgs.To = pubKey1
|
|
||||||
postArgs.Payload = whisperMessage1
|
|
||||||
postSuccess, err = whisperAPI.Post(postArgs)
|
|
||||||
if !postSuccess || err != nil {
|
|
||||||
t.Errorf("could not post to whisper: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// send from account that is not in Whisper identity list
|
|
||||||
postArgs.From = pubKey2
|
|
||||||
postSuccess, err = whisperAPI.Post(postArgs)
|
|
||||||
if err == nil || err.Error() != fmt.Sprintf("unknown identity to send from: %s", pubKey2) {
|
|
||||||
t.Error("expected error not voiced: we are sending from non-injected whisper identity")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST 2: From != nil && To == nil: signed broadcast (known sender)
|
|
||||||
postArgs.From = pubKey1
|
|
||||||
postArgs.To = ""
|
|
||||||
postArgs.Payload = whisperMessage2
|
|
||||||
postSuccess, err = whisperAPI.Post(postArgs)
|
|
||||||
if !postSuccess || err != nil {
|
|
||||||
t.Errorf("could not post to whisper: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST 3: From == nil && To == nil: anonymous broadcast
|
|
||||||
postArgs.From = ""
|
|
||||||
postArgs.To = ""
|
|
||||||
postArgs.Payload = whisperMessage3
|
|
||||||
postSuccess, err = whisperAPI.Post(postArgs)
|
|
||||||
if !postSuccess || err != nil {
|
|
||||||
t.Errorf("could not post to whisper: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST 4: From == nil && To != nil: encrypted anonymous message
|
|
||||||
postArgs.From = ""
|
|
||||||
postArgs.To = pubKey1
|
|
||||||
postArgs.Payload = whisperMessage4
|
|
||||||
postSuccess, err = whisperAPI.Post(postArgs)
|
|
||||||
if !postSuccess || err != nil {
|
|
||||||
t.Errorf("could not post to whisper: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST 5: From != nil && To != nil: encrypted and signed response
|
|
||||||
postArgs.From = ""
|
|
||||||
postArgs.To = pubKey1
|
|
||||||
postArgs.Payload = whisperMessage5
|
|
||||||
postSuccess, err = whisperAPI.Post(postArgs)
|
|
||||||
if !postSuccess || err != nil {
|
|
||||||
t.Errorf("could not post to whisper: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second) // allow whisper to poll
|
|
||||||
for message, status := range receivedMessages {
|
|
||||||
if !status {
|
|
||||||
t.Errorf("Expected message not received: %s", message)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(allFiltersAdded)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
whisperAPI.NewFilter(whisper.WhisperFilterArgs{
|
||||||
|
From: accountKey1Hex,
|
||||||
|
To: accountKey2Hex,
|
||||||
|
Topics: []whisper.TopicType{
|
||||||
|
{0x4e, 0x03, 0x65, 0x7a}, {0x34, 0x60, 0x7c, 0x9b}, {0x21, 0x41, 0x7d, 0xf9},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
filterAdded <- struct{}{}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<-allFiltersAdded
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,8 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
|
||||||
if bc.genesisBlock.Hash() == (common.Hash{65, 148, 16, 35, 104, 9, 35, 224, 254, 77, 116, 163, 75, 218, 200, 20, 31, 37, 64, 227, 174, 144, 98, 55, 24, 228, 125, 102, 209, 202, 74, 45}) {
|
if bc.genesisBlock.Hash() == (common.Hash{65, 148, 16, 35, 104, 9, 35, 224, 254, 77, 116, 163, 75, 218, 200, 20, 31, 37, 64, 227, 174, 144, 98, 55, 24, 228, 125, 102, 209, 202, 74, 45}) {
|
||||||
// add trusted CHT for testnet
|
// add trusted CHT for testnet
|
||||||
WriteTrustedCht(bc.chainDb, TrustedCht{
|
WriteTrustedCht(bc.chainDb, TrustedCht{
|
||||||
Number: 161,
|
Number: 186,
|
||||||
Root: common.HexToHash("0xd45125a3a51137fc26f41aa1c7face4d1218b6d56cfb0b0b9ab7e2150e0d7c75"),
|
Root: common.HexToHash("0x06a7857c0f38f7a4c8eb282fa0f202c6ee5b6007fccb95ee72444c586b8d80df"),
|
||||||
})
|
})
|
||||||
glog.V(logger.Info).Infoln("Added trusted CHT for testnet")
|
glog.V(logger.Info).Infoln("Added trusted CHT for testnet")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -137,6 +137,13 @@ func (self *Whisper) NewIdentity() *ecdsa.PrivateKey {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddIdentity adds identity into the known identities list (for message decryption).
|
||||||
|
func (self *Whisper) AddIdentity(key *ecdsa.PrivateKey) {
|
||||||
|
self.keysMu.Lock()
|
||||||
|
self.keys[string(crypto.FromECDSAPub(&key.PublicKey))] = key
|
||||||
|
self.keysMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// HasIdentity checks if the the whisper node is configured with the private key
|
// HasIdentity checks if the the whisper node is configured with the private key
|
||||||
// of the specified public pair.
|
// of the specified public pair.
|
||||||
func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool {
|
func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool {
|
||||||
|
|
|
@ -377,6 +377,42 @@ type PostArgs struct {
|
||||||
PeerID hexutil.Bytes `json:"peerID"`
|
PeerID hexutil.Bytes `json:"peerID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (args *PostArgs) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
var obj struct {
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Topics []string `json:"topics"`
|
||||||
|
Payload string `json:"payload"`
|
||||||
|
Priority hexutil.Uint64 `json:"priority"`
|
||||||
|
TTL hexutil.Uint64 `json:"ttl"`
|
||||||
|
KeyName string `json:"keyname"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &obj); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
args.From = obj.From
|
||||||
|
args.To = obj.To
|
||||||
|
args.Payload = []byte(obj.Payload)
|
||||||
|
args.WorkTime = 2
|
||||||
|
args.PoW = MinimumPoW
|
||||||
|
args.TTL = uint32(obj.TTL)
|
||||||
|
args.KeyName = obj.KeyName
|
||||||
|
for j, topic := range obj.Topics {
|
||||||
|
x := common.FromHex(topic)
|
||||||
|
if x == nil {
|
||||||
|
return fmt.Errorf("topic[%d] is invalid", j)
|
||||||
|
}
|
||||||
|
args.Topic = BytesToTopic(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
if objJSON, err := json.Marshal(&obj); err == nil {
|
||||||
|
glog.V(logger.Info).Infoln("shh message posted: ", string(objJSON))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type WhisperFilterArgs struct {
|
type WhisperFilterArgs struct {
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
|
@ -424,7 +460,7 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
|
||||||
topicsDecoded := make([]TopicType, len(topics))
|
topicsDecoded := make([]TopicType, len(topics))
|
||||||
for j, s := range topics {
|
for j, s := range topics {
|
||||||
x := common.FromHex(s)
|
x := common.FromHex(s)
|
||||||
if x == nil || len(x) != TopicLength {
|
if x == nil {
|
||||||
return fmt.Errorf("topic[%d] is invalid", j)
|
return fmt.Errorf("topic[%d] is invalid", j)
|
||||||
}
|
}
|
||||||
topicsDecoded[j] = BytesToTopic(x)
|
topicsDecoded[j] = BytesToTopic(x)
|
||||||
|
|
|
@ -56,7 +56,7 @@ const (
|
||||||
AESNonceMaxLength = 12
|
AESNonceMaxLength = 12
|
||||||
|
|
||||||
MaxMessageLength = 0x0FFFFF // todo: remove this restriction after testing. this should be regulated by PoW.
|
MaxMessageLength = 0x0FFFFF // todo: remove this restriction after testing. this should be regulated by PoW.
|
||||||
MinimumPoW = 10.0 // todo: review after testing.
|
MinimumPoW = 0.001 // todo: review after testing.
|
||||||
|
|
||||||
padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
|
padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
|
||||||
padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
|
padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
|
||||||
|
|
|
@ -21,7 +21,6 @@ package whisperv5
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
@ -116,7 +115,7 @@ func (e *Envelope) Seal(options *MessageParams) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if target > 0 && bestBit < target {
|
if target > 0 && bestBit < target {
|
||||||
return errors.New("Failed to reach the PoW target, insufficient work time")
|
return fmt.Errorf("Failed to reach the PoW target, insufficient work time. Expected: %v, got: %v", target, bestBit)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -202,6 +202,38 @@ func (w *Whisper) GetIdentity(pubKey string) *ecdsa.PrivateKey {
|
||||||
return w.privateKeys[pubKey]
|
return w.privateKeys[pubKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddIdentity adds identity into the known identities list (for message decryption).
|
||||||
|
func (w *Whisper) AddIdentity(key *ecdsa.PrivateKey) {
|
||||||
|
w.keyMu.Lock()
|
||||||
|
defer w.keyMu.Unlock()
|
||||||
|
w.privateKeys[common.ToHex(crypto.FromECDSAPub(&key.PublicKey))] = key
|
||||||
|
}
|
||||||
|
|
||||||
|
// InjectIdentity injects a manually added identity/key pair into the whisper keys
|
||||||
|
func (w *Whisper) InjectIdentity(key *ecdsa.PrivateKey) error {
|
||||||
|
if w.HasIdentity(common.ToHex(crypto.FromECDSAPub(&key.PublicKey))) { // no need to re-inject
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.keyMu.Lock()
|
||||||
|
defer w.keyMu.Unlock()
|
||||||
|
|
||||||
|
w.privateKeys = make(map[string]*ecdsa.PrivateKey) // reset key store
|
||||||
|
w.privateKeys[common.ToHex(crypto.FromECDSAPub(&key.PublicKey))] = key
|
||||||
|
|
||||||
|
glog.V(logger.Info).Infof("Injected identity into whisper: %s\n", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearIdentities clears the current whisper identities in memory
|
||||||
|
func (w *Whisper) ClearIdentities() error {
|
||||||
|
w.keyMu.Lock()
|
||||||
|
defer w.keyMu.Unlock()
|
||||||
|
|
||||||
|
w.privateKeys = make(map[string]*ecdsa.PrivateKey)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Whisper) GenerateSymKey(name string) error {
|
func (w *Whisper) GenerateSymKey(name string) error {
|
||||||
const size = aesKeyLength * 2
|
const size = aesKeyLength * 2
|
||||||
buf := make([]byte, size)
|
buf := make([]byte, size)
|
||||||
|
|
Loading…
Reference in New Issue