diff options
34 files changed, 766 insertions, 343 deletions
diff --git a/.travis.yml b/.travis.yml index 13211f736..c1d545c54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,10 +20,6 @@ env: global: - secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64=" sudo: false -addons: - apt: - packages: - - libgmp3-dev notifications: webhooks: urls: @@ -3,15 +3,13 @@ # don't need to bother with make. .PHONY: geth geth-cross evm all test travis-test-with-coverage xgo clean -.PHONY: geth-linux geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-386 geth-linux-amd64 +.PHONY: geth-linux geth-linux-386 geth-linux-amd64 +.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 .PHONY: geth-windows geth-windows-386 geth-windows-amd64 -.PHONY: geth-android geth-ios +.PHONY: geth-android geth-ios geth-ios-sim GOBIN = build/bin - -CROSSDEPS = https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2 -MODE ?= default GO ?= latest geth: @@ -28,45 +26,50 @@ geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm @ls -l $(GOBIN)/geth-linux-* geth-linux-386: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux 386 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep 386 geth-linux-amd64: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/amd64 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/amd64 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux amd64 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep amd64 -geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 +geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 @echo "Linux ARM cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm geth-linux-arm-5: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-5 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-5 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux ARMv5 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm-5 geth-linux-arm-6: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-6 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-6 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux ARMv6 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm-6 geth-linux-arm-7: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-7 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-7 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux ARMv7 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm-7 +geth-linux-arm64: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm64 -v $(shell build/flags.sh) ./cmd/geth + @echo "Linux ARM64 cross compilation done:" + @ls -l $(GOBIN)/geth-linux-* | grep arm64 + geth-darwin: geth-darwin-386 geth-darwin-amd64 @echo "Darwin cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* geth-darwin-386: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/386 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=darwin/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Darwin 386 cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* | grep 386 geth-darwin-amd64: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/amd64 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=darwin/amd64 -v $(shell build/flags.sh) ./cmd/geth @echo "Darwin amd64 cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* | grep amd64 @@ -75,23 +78,28 @@ geth-windows: geth-windows-386 geth-windows-amd64 @ls -l $(GOBIN)/geth-windows-* geth-windows-386: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/386 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=windows/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Windows 386 cross compilation done:" @ls -l $(GOBIN)/geth-windows-* | grep 386 geth-windows-amd64: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/amd64 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=windows/amd64 -v $(shell build/flags.sh) ./cmd/geth @echo "Windows amd64 cross compilation done:" @ls -l $(GOBIN)/geth-windows-* | grep amd64 geth-android: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android/* -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=android/* -v $(shell build/flags.sh) ./cmd/geth @echo "Android cross compilation done:" @ls -l $(GOBIN)/geth-android-* geth-ios: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios/* -v $(shell build/flags.sh) ./cmd/geth - @echo "iOS cross compilation done:" + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/* -v $(shell build/flags.sh) ./cmd/geth + @echo "iOS framework cross compilation done:" + @ls -l $(GOBIN)/geth-ios-* + +geth-ios-sim: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/amd64 -v $(shell build/flags.sh) ./cmd/geth + @echo "iOS framework simulator-only cross compilation done:" @ls -l $(GOBIN)/geth-ios-* evm: @@ -30,7 +30,7 @@ For prerequisites and detailed build instructions please read the [Installation Instructions](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum) on the wiki. -Building geth requires two external dependencies, Go and GMP. +Building geth requires both a Go and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 3f05bfe2d..635dc43fe 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -20,75 +20,17 @@ import ( "encoding/json" "fmt" "io" - "strings" + "math" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" ) -// Callable method given a `Name` and whether the method is a constant. -// If the method is `Const` no transaction needs to be created for this -// particular Method call. It can easily be simulated using a local VM. -// For example a `Balance()` method only needs to retrieve something -// from the storage and therefor requires no Tx to be send to the -// network. A method such as `Transact` does require a Tx and thus will -// be flagged `true`. -// Input specifies the required input parameters for this gives method. -type Method struct { - Name string - Const bool - Inputs []Argument - Return Type // not yet implemented -} - -// Returns the methods string signature according to the ABI spec. -// -// Example -// -// function foo(uint32 a, int b) = "foo(uint32,int256)" -// -// Please note that "int" is substitute for its canonical representation "int256" -func (m Method) String() (out string) { - out += m.Name - types := make([]string, len(m.Inputs)) - i := 0 - for _, input := range m.Inputs { - types[i] = input.Type.String() - i++ - } - out += "(" + strings.Join(types, ",") + ")" - - return -} - -func (m Method) Id() []byte { - return crypto.Sha3([]byte(m.String()))[:4] -} - -// Argument holds the name of the argument and the corresponding type. -// Types are used when packing and testing arguments. -type Argument struct { - Name string - Type Type -} - -func (a *Argument) UnmarshalJSON(data []byte) error { - var extarg struct { - Name string - Type string - } - err := json.Unmarshal(data, &extarg) - if err != nil { - return fmt.Errorf("argument json err: %v", err) - } - - a.Type, err = NewType(extarg.Type) - if err != nil { - return err - } - a.Name = extarg.Name - - return nil -} +// Executer is an executer method for performing state executions. It takes one +// argument which is the input data and expects output data to be returned as +// multiple 32 byte word length concatenated slice +type Executer func(datain []byte) []byte // The ABI holds information about a contract's context and available // invokable methods. It will allow you to type check function calls and @@ -97,6 +39,18 @@ type ABI struct { Methods map[string]Method } +// JSON returns a parsed ABI interface and error if it failed. +func JSON(reader io.Reader) (ABI, error) { + dec := json.NewDecoder(reader) + + var abi ABI + if err := dec.Decode(&abi); err != nil { + return ABI{}, err + } + + return abi, nil +} + // tests, tests whether the given input would result in a successful // call. Checks argument list count and matches input to `input`. func (abi ABI) pack(name string, args ...interface{}) ([]byte, error) { @@ -145,6 +99,55 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { return packed, nil } +// toGoType parses the input and casts it to the proper type defined by the ABI +// argument in t. +func toGoType(t Argument, input []byte) interface{} { + switch t.Type.T { + case IntTy: + return common.BytesToBig(input) + case UintTy: + return common.BytesToBig(input) + case BoolTy: + return common.BytesToBig(input).Uint64() > 0 + case AddressTy: + return common.BytesToAddress(input) + case HashTy: + return common.BytesToHash(input) + } + return nil +} + +// Call executes a call and attemps to parse the return values and returns it as +// an interface. It uses the executer method to perform the actual call since +// the abi knows nothing of the lower level calling mechanism. +// +// Call supports all abi types and includes multiple return values. When only +// one item is returned a single interface{} will be returned, if a contract +// method returns multiple values an []interface{} slice is returned. +func (abi ABI) Call(executer Executer, name string, args ...interface{}) interface{} { + callData, err := abi.Pack(name, args...) + if err != nil { + glog.V(logger.Debug).Infoln("pack error:", err) + return nil + } + + output := executer(callData) + + method := abi.Methods[name] + ret := make([]interface{}, int(math.Max(float64(len(method.Outputs)), float64(len(output)/32)))) + for i := 0; i < len(ret); i += 32 { + index := i / 32 + ret[index] = toGoType(method.Outputs[index], output[i:i+32]) + } + + // return single interface + if len(ret) == 1 { + return ret[0] + } + + return ret +} + func (abi *ABI) UnmarshalJSON(data []byte) error { var methods []Method if err := json.Unmarshal(data, &methods); err != nil { @@ -158,14 +161,3 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { return nil } - -func JSON(reader io.Reader) (ABI, error) { - dec := json.NewDecoder(reader) - - var abi ABI - if err := dec.Decode(&abi); err != nil { - return ABI{}, err - } - - return abi, nil -} diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 96dd3ee62..d514fb8c7 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -92,12 +92,12 @@ func TestReader(t *testing.T) { exp := ABI{ Methods: map[string]Method{ "balance": Method{ - "balance", true, nil, Type{}, + "balance", true, nil, nil, }, "send": Method{ "send", false, []Argument{ Argument{"amount", Uint256}, - }, Type{}, + }, nil, }, }, } @@ -238,10 +238,10 @@ func TestTestAddress(t *testing.T) { func TestMethodSignature(t *testing.T) { String, _ := NewType("string") String32, _ := NewType("string32") - m := Method{"foo", false, []Argument{Argument{"bar", String32}, Argument{"baz", String}}, Type{}} + m := Method{"foo", false, []Argument{Argument{"bar", String32}, Argument{"baz", String}}, nil} exp := "foo(string32,string)" - if m.String() != exp { - t.Error("signature mismatch", exp, "!=", m.String()) + if m.Sig() != exp { + t.Error("signature mismatch", exp, "!=", m.Sig()) } idexp := crypto.Sha3([]byte(exp))[:4] @@ -250,10 +250,10 @@ func TestMethodSignature(t *testing.T) { } uintt, _ := NewType("uint") - m = Method{"foo", false, []Argument{Argument{"bar", uintt}}, Type{}} + m = Method{"foo", false, []Argument{Argument{"bar", uintt}}, nil} exp = "foo(uint256)" - if m.String() != exp { - t.Error("signature mismatch", exp, "!=", m.String()) + if m.Sig() != exp { + t.Error("signature mismatch", exp, "!=", m.Sig()) } } @@ -393,3 +393,34 @@ func TestBytes(t *testing.T) { t.Error("expected error") } } + +func TestReturn(t *testing.T) { + const definition = `[ + { "name" : "balance", "const" : true, "inputs" : [], "outputs" : [ { "name": "", "type": "hash" } ] }, + { "name" : "name", "const" : true, "inputs" : [], "outputs" : [ { "name": "", "type": "address" } ] } + +]` + + abi, err := JSON(strings.NewReader(definition)) + if err != nil { + t.Fatal(err) + } + + r := abi.Call(func([]byte) []byte { + t := make([]byte, 32) + t[0] = 1 + return t + }, "balance") + if _, ok := r.(common.Hash); !ok { + t.Errorf("expected type common.Hash, got %T", r) + } + + r = abi.Call(func([]byte) []byte { + t := make([]byte, 32) + t[0] = 1 + return t + }, "name") + if _, ok := r.(common.Address); !ok { + t.Errorf("expected type common.Address, got %T", r) + } +} diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go new file mode 100644 index 000000000..8907b2979 --- /dev/null +++ b/accounts/abi/argument.go @@ -0,0 +1,48 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package abi + +import ( + "encoding/json" + "fmt" +) + +// Argument holds the name of the argument and the corresponding type. +// Types are used when packing and testing arguments. +type Argument struct { + Name string + Type Type +} + +func (a *Argument) UnmarshalJSON(data []byte) error { + var extarg struct { + Name string + Type string + } + err := json.Unmarshal(data, &extarg) + if err != nil { + return fmt.Errorf("argument json err: %v", err) + } + + a.Type, err = NewType(extarg.Type) + if err != nil { + return err + } + a.Name = extarg.Name + + return nil +} diff --git a/accounts/abi/method.go b/accounts/abi/method.go new file mode 100644 index 000000000..63194e788 --- /dev/null +++ b/accounts/abi/method.go @@ -0,0 +1,76 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package abi + +import ( + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/crypto" +) + +// Callable method given a `Name` and whether the method is a constant. +// If the method is `Const` no transaction needs to be created for this +// particular Method call. It can easily be simulated using a local VM. +// For example a `Balance()` method only needs to retrieve something +// from the storage and therefor requires no Tx to be send to the +// network. A method such as `Transact` does require a Tx and thus will +// be flagged `true`. +// Input specifies the required input parameters for this gives method. +type Method struct { + Name string + Const bool + Inputs []Argument + Outputs []Argument +} + +// Sig returns the methods string signature according to the ABI spec. +// +// Example +// +// function foo(uint32 a, int b) = "foo(uint32,int256)" +// +// Please note that "int" is substitute for its canonical representation "int256" +func (m Method) Sig() string { + types := make([]string, len(m.Inputs)) + i := 0 + for _, input := range m.Inputs { + types[i] = input.Type.String() + i++ + } + return fmt.Sprintf("%v(%v)", m.Name, strings.Join(types, ",")) +} + +func (m Method) String() string { + inputs := make([]string, len(m.Inputs)) + for i, input := range m.Inputs { + inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) + } + outputs := make([]string, len(m.Outputs)) + for i, output := range m.Outputs { + if len(output.Name) > 0 { + outputs[i] = fmt.Sprintf("%v ", output.Name) + } + outputs[i] += output.Type.String() + } + + return fmt.Sprintf("function %v(%v) returns(%v)", m.Name, strings.Join(inputs, ", "), strings.Join(outputs, ", ")) +} + +func (m Method) Id() []byte { + return crypto.Sha3([]byte(m.Sig()))[:4] +} diff --git a/accounts/abi/numbers.go b/accounts/abi/numbers.go index 2a7049425..c37cd5f68 100644 --- a/accounts/abi/numbers.go +++ b/accounts/abi/numbers.go @@ -37,6 +37,8 @@ var int8_t = reflect.TypeOf(int8(0)) var int16_t = reflect.TypeOf(int16(0)) var int32_t = reflect.TypeOf(int32(0)) var int64_t = reflect.TypeOf(int64(0)) +var hash_t = reflect.TypeOf(common.Hash{}) +var address_t = reflect.TypeOf(common.Address{}) var uint_ts = reflect.TypeOf([]uint(nil)) var uint8_ts = reflect.TypeOf([]uint8(nil)) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 16d7491e7..8f0238fc9 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -31,6 +31,7 @@ const ( BoolTy SliceTy AddressTy + HashTy RealTy ) @@ -121,7 +122,7 @@ func NewType(t string) (typ Type, err error) { typ.Kind = reflect.Invalid case "address": typ.Kind = reflect.Slice - typ.Type = byte_ts + typ.Type = address_t typ.Size = 20 typ.T = AddressTy case "string": @@ -130,6 +131,11 @@ func NewType(t string) (typ Type, err error) { if vsize > 0 { typ.Size = 32 } + case "hash": + typ.Kind = reflect.Slice + typ.Size = 32 + typ.Type = hash_t + typ.T = HashTy case "bytes": typ.Kind = reflect.Slice typ.Type = byte_ts @@ -206,9 +212,9 @@ func (t Type) pack(v interface{}) ([]byte, error) { } case reflect.Array: if v, ok := value.Interface().(common.Address); ok { - return t.pack(v[:]) + return common.LeftPadBytes(v[:], 32), nil } else if v, ok := value.Interface().(common.Hash); ok { - return t.pack(v[:]) + return v[:], nil } } diff --git a/cmd/geth/library.c b/cmd/geth/library.c new file mode 100644 index 000000000..f738621a8 --- /dev/null +++ b/cmd/geth/library.c @@ -0,0 +1,24 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. + +// Simple wrapper to translate the API exposed methods and types to inthernal +// Go versions of the same types. + +#include "_cgo_export.h" + +int run(const char* args) { + return doRun((char*)args); +} diff --git a/cmd/geth/library.go b/cmd/geth/library.go new file mode 100644 index 000000000..b8ffaaed7 --- /dev/null +++ b/cmd/geth/library.go @@ -0,0 +1,46 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. + +// Contains a simple library definition to allow creating a Geth instance from +// straight C code. + +package main + +// #ifdef __cplusplus +// extern "C" { +// #endif +// +// extern int run(const char*); +// +// #ifdef __cplusplus +// } +// #endif +import "C" +import ( + "fmt" + "os" + "strings" +) + +//export doRun +func doRun(args *C.char) C.int { + // This is equivalent to geth.main, just modified to handle the function arg passing + if err := app.Run(strings.Split("geth "+C.GoString(args), " ")); err != nil { + fmt.Fprintln(os.Stderr, err) + return -1 + } + return 0 +} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index bb291ccde..f2bb27552 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -341,6 +341,8 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.ExtraDataFlag, } app.Before = func(ctx *cli.Context) error { + runtime.GOMAXPROCS(runtime.NumCPU()) + utils.SetupLogger(ctx) utils.SetupNetwork(ctx) utils.SetupVM(ctx) @@ -354,7 +356,6 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso } func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) defer logger.Flush() if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/core/blockchain.go b/core/blockchain.go index 5a6795b3e..9d526e352 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -980,6 +980,18 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain glog.Fatal(errs[index]) return } + if err := WriteTransactions(self.chainDb, block); err != nil { + errs[index] = fmt.Errorf("failed to write individual transactions: %v", err) + atomic.AddInt32(&failed, 1) + glog.Fatal(errs[index]) + return + } + if err := WriteReceipts(self.chainDb, receipts); err != nil { + errs[index] = fmt.Errorf("failed to write individual receipts: %v", err) + atomic.AddInt32(&failed, 1) + glog.Fatal(errs[index]) + return + } atomic.AddInt32(&stats.processed, 1) } } @@ -1240,6 +1252,17 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { oldStart = oldBlock newStart = newBlock deletedTxs types.Transactions + deletedLogs vm.Logs + // collectLogs collects the logs that were generated during the + // processing of the block that corresponds with the given hash. + // These logs are later announced as deleted. + collectLogs = func(h common.Hash) { + // Coalesce logs + receipts := GetBlockReceipts(self.chainDb, h) + for _, receipt := range receipts { + deletedLogs = append(deletedLogs, receipt.Logs...) + } + } ) // first reduce whoever is higher bound @@ -1247,6 +1270,8 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // reduce old chain for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) { deletedTxs = append(deletedTxs, oldBlock.Transactions()...) + + collectLogs(oldBlock.Hash()) } } else { // reduce new chain and append new chain blocks for inserting later on @@ -1269,6 +1294,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } newChain = append(newChain, newBlock) deletedTxs = append(deletedTxs, oldBlock.Transactions()...) + collectLogs(oldBlock.Hash()) oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) if oldBlock == nil { @@ -1302,7 +1328,6 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil { return err } - addedTxs = append(addedTxs, block.Transactions()...) } @@ -1316,7 +1341,12 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } // Must be posted in a goroutine because of the transaction pool trying // to acquire the chain manager lock - go self.eventMux.Post(RemovedTransactionEvent{diff}) + if len(diff) > 0 { + go self.eventMux.Post(RemovedTransactionEvent{diff}) + } + if len(deletedLogs) > 0 { + go self.eventMux.Post(RemovedLogEvent{deletedLogs}) + } return nil } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 6e1c5fdc7..b4ac1696a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -963,3 +963,46 @@ func TestChainTxReorgs(t *testing.T) { } } } + +func TestLogReorgs(t *testing.T) { + params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be. + params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block. + + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + db, _ = ethdb.NewMemDatabase() + // this code generates a log + code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") + ) + genesis := WriteGenesisBlockForTesting(db, + GenesisAccount{addr1, big.NewInt(10000000000000)}, + ) + + evmux := &event.TypeMux{} + blockchain, _ := NewBlockChain(db, FakePow{}, evmux) + + subs := evmux.Subscribe(RemovedLogEvent{}) + chain, _ := GenerateChain(genesis, db, 2, func(i int, gen *BlockGen) { + if i == 1 { + tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1) + if err != nil { + t.Fatalf("failed to create tx: %v", err) + } + gen.AddTx(tx) + } + }) + if _, err := blockchain.InsertChain(chain); err != nil { + t.Fatalf("failed to insert chain: %v", err) + } + + chain, _ = GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) {}) + if _, err := blockchain.InsertChain(chain); err != nil { + t.Fatalf("failed to insert forked chain: %v", err) + } + + ev := <-subs.Chan() + if len(ev.Data.(RemovedLogEvent).Logs) == 0 { + t.Error("expected logs") + } +} diff --git a/core/chain_makers.go b/core/chain_makers.go index 6d3152d97..4f6fa3989 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -90,6 +90,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } + b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) _, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.gasPool) if err != nil { panic(err) @@ -97,8 +98,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { root := b.statedb.IntermediateRoot() b.header.GasUsed.Add(b.header.GasUsed, gas) receipt := types.NewReceipt(root.Bytes(), b.header.GasUsed) - logs := b.statedb.GetLogs(tx.Hash()) - receipt.Logs = logs + receipt.Logs = b.statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) b.txs = append(b.txs, tx) b.receipts = append(b.receipts, receipt) diff --git a/core/events.go b/core/events.go index 8cf230dda..1a760c71c 100644 --- a/core/events.go +++ b/core/events.go @@ -39,6 +39,9 @@ type NewMinedBlockEvent struct{ Block *types.Block } // RemovedTransactionEvent is posted when a reorg happens type RemovedTransactionEvent struct{ Txs types.Transactions } +// RemovedLogEvent is posted when a reorg happens +type RemovedLogEvent struct{ Logs vm.Logs } + // ChainSplit is posted when a new head is detected type ChainSplitEvent struct { Block *types.Block diff --git a/crypto/crypto.go b/crypto/crypto.go index 8685d62d3..7d7623753 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -43,14 +43,6 @@ import ( "golang.org/x/crypto/ripemd160" ) -var secp256k1n *big.Int - -func init() { - // specify the params for the s256 curve - ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256) - secp256k1n = common.String2Big("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") -} - func Sha3(data ...[]byte) []byte { d := sha3.NewKeccak256() for _, b := range data { @@ -99,9 +91,9 @@ func ToECDSA(prv []byte) *ecdsa.PrivateKey { } priv := new(ecdsa.PrivateKey) - priv.PublicKey.Curve = S256() + priv.PublicKey.Curve = secp256k1.S256() priv.D = common.BigD(prv) - priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv) + priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv) return priv } @@ -116,15 +108,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey { if len(pub) == 0 { return nil } - x, y := elliptic.Unmarshal(S256(), pub) - return &ecdsa.PublicKey{S256(), x, y} + x, y := elliptic.Unmarshal(secp256k1.S256(), pub) + return &ecdsa.PublicKey{secp256k1.S256(), x, y} } func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil } - return elliptic.Marshal(S256(), pub.X, pub.Y) + return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y) } // HexToECDSA parses a secp256k1 private key. @@ -168,7 +160,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error { } func GenerateKey() (*ecdsa.PrivateKey, error) { - return ecdsa.GenerateKey(S256(), rand.Reader) + return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) } func ValidateSignatureValues(v byte, r, s *big.Int) bool { @@ -176,7 +168,7 @@ func ValidateSignatureValues(v byte, r, s *big.Int) bool { return false } vint := uint32(v) - if r.Cmp(secp256k1n) < 0 && s.Cmp(secp256k1n) < 0 && (vint == 27 || vint == 28) { + if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { return true } else { return false @@ -189,8 +181,8 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { return nil, err } - x, y := elliptic.Unmarshal(S256(), s) - return &ecdsa.PublicKey{S256(), x, y}, nil + x, y := elliptic.Unmarshal(secp256k1.S256(), s) + return &ecdsa.PublicKey{secp256k1.S256(), x, y}, nil } func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index fdd9c1ee8..d5e19a4bb 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -181,7 +181,7 @@ func TestValidateSignatureValues(t *testing.T) { minusOne := big.NewInt(-1) one := common.Big1 zero := common.Big0 - secp256k1nMinus1 := new(big.Int).Sub(secp256k1n, common.Big1) + secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1) // correct v,r,s check(true, 27, one, one) @@ -208,9 +208,9 @@ func TestValidateSignatureValues(t *testing.T) { // correct sig with max r,s check(true, 27, secp256k1nMinus1, secp256k1nMinus1) // correct v, combinations of incorrect r,s at upper limit - check(false, 27, secp256k1n, secp256k1nMinus1) - check(false, 27, secp256k1nMinus1, secp256k1n) - check(false, 27, secp256k1n, secp256k1n) + check(false, 27, secp256k1.N, secp256k1nMinus1) + check(false, 27, secp256k1nMinus1, secp256k1.N) + check(false, 27, secp256k1.N, secp256k1.N) // current callers ensures r,s cannot be negative, but let's test for that too // as crypto package could be used stand-alone diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go index 6eaf3d2ca..40dabd329 100644 --- a/crypto/ecies/asn1.go +++ b/crypto/ecies/asn1.go @@ -41,6 +41,8 @@ import ( "fmt" "hash" "math/big" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) var ( @@ -81,6 +83,7 @@ func doScheme(base, v []int) asn1.ObjectIdentifier { type secgNamedCurve asn1.ObjectIdentifier var ( + secgNamedCurveS256 = secgNamedCurve{1, 3, 132, 0, 10} secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7} secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34} secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35} @@ -116,6 +119,8 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool { func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve { switch { + case curve.Equal(secgNamedCurveS256): + return secp256k1.S256() case curve.Equal(secgNamedCurveP256): return elliptic.P256() case curve.Equal(secgNamedCurveP384): @@ -134,6 +139,8 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) { return secgNamedCurveP384, true case elliptic.P521(): return secgNamedCurveP521, true + case secp256k1.S256(): + return secgNamedCurveS256, true } return nil, false diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index a3b520dd5..65dc5b38b 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -125,6 +125,7 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b if skLen+macLen > MaxSharedKeyLength(pub) { return nil, ErrSharedKeyTooBig } + x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) if x == nil { return nil, ErrSharedKeyIsPointAtInfinity diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 1c391f938..6a0ea3f02 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -31,13 +31,18 @@ package ecies import ( "bytes" + "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" + "encoding/hex" "flag" "fmt" "io/ioutil" + "math/big" "testing" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) var dumpEnc bool @@ -65,7 +70,6 @@ func TestKDF(t *testing.T) { } } -var skLen int var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match") // cmpParams compares a set of ECIES parameters. We assume, as per the @@ -117,7 +121,7 @@ func TestSharedKey(t *testing.T) { fmt.Println(err.Error()) t.FailNow() } - skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2 + skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { @@ -143,6 +147,44 @@ func TestSharedKey(t *testing.T) { } } +func TestSharedKeyPadding(t *testing.T) { + // sanity checks + prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9") + prv1 := hexKey("97a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a") + x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16) + x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16) + y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16) + y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16) + + if prv0.PublicKey.X.Cmp(x0) != 0 { + t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes()) + } + if prv0.PublicKey.Y.Cmp(y0) != 0 { + t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes()) + } + if prv1.PublicKey.X.Cmp(x1) != 0 { + t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes()) + } + if prv1.PublicKey.Y.Cmp(y1) != 0 { + t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes()) + } + + // test shared secret generation + sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16) + if err != nil { + fmt.Println(err.Error()) + } + + sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16) + if err != nil { + t.Fatal(err.Error()) + } + + if !bytes.Equal(sk1, sk2) { + t.Fatal(ErrBadSharedKeys.Error()) + } +} + // Verify that the key generation code fails when too much key data is // requested. func TestTooBigSharedKey(t *testing.T) { @@ -158,13 +200,13 @@ func TestTooBigSharedKey(t *testing.T) { t.FailNow() } - _, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2) + _, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32) if err != ErrSharedKeyTooBig { fmt.Println("ecdh: shared key should be too large for curve") t.FailNow() } - _, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2) + _, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32) if err != ErrSharedKeyTooBig { fmt.Println("ecdh: shared key should be too large for curve") t.FailNow() @@ -176,25 +218,21 @@ func TestTooBigSharedKey(t *testing.T) { func TestMarshalPublic(t *testing.T) { prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatalf("GenerateKey error: %s", err) } out, err := MarshalPublic(&prv.PublicKey) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatalf("MarshalPublic error: %s", err) } pub, err := UnmarshalPublic(out) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatalf("UnmarshalPublic error: %s", err) } if !cmpPublic(prv.PublicKey, *pub) { - fmt.Println("ecies: failed to unmarshal public key") - t.FailNow() + t.Fatal("ecies: failed to unmarshal public key") } } @@ -304,9 +342,26 @@ func BenchmarkGenSharedKeyP256(b *testing.B) { fmt.Println(err.Error()) b.FailNow() } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := prv.GenerateShared(&prv.PublicKey, 16, 16) + if err != nil { + fmt.Println(err.Error()) + b.FailNow() + } + } +} +// Benchmark the generation of S256 shared keys. +func BenchmarkGenSharedKeyS256(b *testing.B) { + prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil) + if err != nil { + fmt.Println(err.Error()) + b.FailNow() + } + b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen) + _, err := prv.GenerateShared(&prv.PublicKey, 16, 16) if err != nil { fmt.Println(err.Error()) b.FailNow() @@ -511,3 +566,43 @@ func TestBasicKeyValidation(t *testing.T) { } } } + +// Verify GenerateShared against static values - useful when +// debugging changes in underlying libs +func TestSharedKeyStatic(t *testing.T) { + prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad") + prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9") + + skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2 + + sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen) + if err != nil { + fmt.Println(err.Error()) + t.FailNow() + } + + sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen) + if err != nil { + fmt.Println(err.Error()) + t.FailNow() + } + + if !bytes.Equal(sk1, sk2) { + fmt.Println(ErrBadSharedKeys.Error()) + t.FailNow() + } + + sk, _ := hex.DecodeString("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62") + if !bytes.Equal(sk1, sk) { + t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1) + } +} + +// TODO: remove after refactoring packages crypto and crypto/ecies +func hexKey(prv string) *PrivateKey { + priv := new(ecdsa.PrivateKey) + priv.PublicKey.Curve = secp256k1.S256() + priv.D, _ = new(big.Int).SetString(prv, 16) + priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes()) + return ImportECDSA(priv) +} diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go index 97ddb0973..511c53ebc 100644 --- a/crypto/ecies/params.go +++ b/crypto/ecies/params.go @@ -41,13 +41,12 @@ import ( "crypto/sha512" "fmt" "hash" -) -// The default curve for this package is the NIST P256 curve, which -// provides security equivalent to AES-128. -var DefaultCurve = elliptic.P256() + "github.com/ethereum/go-ethereum/crypto/secp256k1" +) var ( + DefaultCurve = secp256k1.S256() ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm") ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters") ) @@ -101,9 +100,10 @@ var ( ) var paramsFromCurve = map[elliptic.Curve]*ECIESParams{ - elliptic.P256(): ECIES_AES128_SHA256, - elliptic.P384(): ECIES_AES256_SHA384, - elliptic.P521(): ECIES_AES256_SHA512, + secp256k1.S256(): ECIES_AES128_SHA256, + elliptic.P256(): ECIES_AES128_SHA256, + elliptic.P384(): ECIES_AES256_SHA384, + elliptic.P521(): ECIES_AES256_SHA512, } func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) { diff --git a/crypto/key.go b/crypto/key.go index 4ec43dfd7..8e2d8553b 100644 --- a/crypto/key.go +++ b/crypto/key.go @@ -25,6 +25,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/pborman/uuid" ) @@ -49,17 +50,17 @@ type plainKeyJSON struct { } type encryptedKeyJSONV3 struct { - Address string `json:"address"` - Crypto cryptoJSON - Id string `json:"id"` - Version int `json:"version"` + Address string `json:"address"` + Crypto cryptoJSON `json:"crypto"` + Id string `json:"id"` + Version int `json:"version"` } type encryptedKeyJSONV1 struct { - Address string `json:"address"` - Crypto cryptoJSON - Id string `json:"id"` - Version string `json:"version"` + Address string `json:"address"` + Crypto cryptoJSON `json:"crypto"` + Id string `json:"id"` + Version string `json:"version"` } type cryptoJSON struct { @@ -137,7 +138,7 @@ func NewKey(rand io.Reader) *Key { panic("key generation: could not read from random source: " + err.Error()) } reader := bytes.NewReader(randBytes) - privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader) + privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader) if err != nil { panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) } @@ -155,7 +156,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key { panic("key generation: could not read from random source: " + err.Error()) } reader := bytes.NewReader(randBytes) - privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader) + privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader) if err != nil { panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) } diff --git a/crypto/secp256k1/README.md b/crypto/secp256k1/README.md deleted file mode 100644 index 5a86147d4..000000000 --- a/crypto/secp256k1/README.md +++ /dev/null @@ -1,25 +0,0 @@ -secp256k1-go -======= - -golang secp256k1 library - -Implements cryptographic operations for the secp256k1 ECDSA curve used by Bitcoin. - -Installing -=== - -GMP library headers are required to build. On Debian-based systems, the package is called `libgmp-dev`. - -``` -sudo apt-get install libgmp-dev -``` - -Now compiles with cgo! - -Test -=== - -To run tests do -``` -go tests -```
\ No newline at end of file diff --git a/crypto/curve.go b/crypto/secp256k1/curve.go index 48f3f5e9c..6e44a6771 100644 --- a/crypto/curve.go +++ b/crypto/secp256k1/curve.go @@ -29,15 +29,22 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -package crypto +package secp256k1 import ( "crypto/elliptic" "io" "math/big" "sync" + "unsafe" ) +/* +#include "libsecp256k1/include/secp256k1.h" +extern int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar); +*/ +import "C" + // This code is from https://github.com/ThePiachu/GoBit and implements // several Koblitz elliptic curves over prime fields. // @@ -211,44 +218,37 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, return x3, y3, z3 } -//TODO: double check if it is okay -// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { - // We have a slight problem in that the identity of the group (the - // point at infinity) cannot be represented in (x, y) form on a finite - // machine. Thus the standard add/double algorithm has to be tweaked - // slightly: our initial state is not the identity, but x, and we - // ignore the first true bit in |k|. If we don't find any true bits in - // |k|, then we return nil, nil, because we cannot return the identity - // element. - - Bz := new(big.Int).SetInt64(1) - x := Bx - y := By - z := Bz - - seenFirstTrue := false - for _, byte := range k { - for bitNum := 0; bitNum < 8; bitNum++ { - if seenFirstTrue { - x, y, z = BitCurve.doubleJacobian(x, y, z) - } - if byte&0x80 == 0x80 { - if !seenFirstTrue { - seenFirstTrue = true - } else { - x, y, z = BitCurve.addJacobian(Bx, By, Bz, x, y, z) - } - } - byte <<= 1 - } +func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { + // Ensure scalar is exactly 32 bytes. We pad always, even if + // scalar is 32 bytes long, to avoid a timing side channel. + if len(scalar) > 32 { + panic("can't handle scalars > 256 bits") } - - if !seenFirstTrue { + padded := make([]byte, 32) + copy(padded[32-len(scalar):], scalar) + scalar = padded + + // Do the multiplication in C, updating point. + point := make([]byte, 64) + readBits(point[:32], Bx) + readBits(point[32:], By) + pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) + scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) + res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr) + + // Unpack the result and clear temporaries. + x := new(big.Int).SetBytes(point[:32]) + y := new(big.Int).SetBytes(point[32:]) + for i := range point { + point[i] = 0 + } + for i := range padded { + scalar[i] = 0 + } + if res != 1 { return nil, nil } - - return BitCurve.affineFromJacobian(x, y, z) + return x, y } // ScalarBaseMult returns k*G, where G is the base point of the group and k is @@ -312,86 +312,24 @@ func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { return } -//curve parameters taken from: -//http://www.secg.org/collateral/sec2_final.pdf - -var initonce sync.Once -var ecp160k1 *BitCurve -var ecp192k1 *BitCurve -var ecp224k1 *BitCurve -var ecp256k1 *BitCurve - -func initAll() { - initS160() - initS192() - initS224() - initS256() -} - -func initS160() { - // See SEC 2 section 2.4.1 - ecp160k1 = new(BitCurve) - ecp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16) - ecp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16) - ecp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16) - ecp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16) - ecp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16) - ecp160k1.BitSize = 160 -} - -func initS192() { - // See SEC 2 section 2.5.1 - ecp192k1 = new(BitCurve) - ecp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16) - ecp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16) - ecp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16) - ecp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16) - ecp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16) - ecp192k1.BitSize = 192 -} - -func initS224() { - // See SEC 2 section 2.6.1 - ecp224k1 = new(BitCurve) - ecp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16) - ecp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16) - ecp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16) - ecp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16) - ecp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16) - ecp224k1.BitSize = 224 -} - -func initS256() { - // See SEC 2 section 2.7.1 - ecp256k1 = new(BitCurve) - ecp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) - ecp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) - ecp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) - ecp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) - ecp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) - ecp256k1.BitSize = 256 -} - -// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1) -func S160() *BitCurve { - initonce.Do(initAll) - return ecp160k1 -} - -// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1) -func S192() *BitCurve { - initonce.Do(initAll) - return ecp192k1 -} - -// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1) -func S224() *BitCurve { - initonce.Do(initAll) - return ecp224k1 -} +var ( + initonce sync.Once + theCurve *BitCurve +) // S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1) func S256() *BitCurve { - initonce.Do(initAll) - return ecp256k1 + initonce.Do(func() { + // See SEC 2 section 2.7.1 + // curve parameters taken from: + // http://www.secg.org/collateral/sec2_final.pdf + theCurve = new(BitCurve) + theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) + theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) + theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) + theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) + theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) + theCurve.BitSize = 256 + }) + return theCurve } diff --git a/crypto/secp256k1/curve_test.go b/crypto/secp256k1/curve_test.go new file mode 100644 index 000000000..d915ee852 --- /dev/null +++ b/crypto/secp256k1/curve_test.go @@ -0,0 +1,39 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package secp256k1 + +import ( + "bytes" + "encoding/hex" + "math/big" + "testing" +) + +func TestReadBits(t *testing.T) { + check := func(input string) { + want, _ := hex.DecodeString(input) + int, _ := new(big.Int).SetString(input, 16) + buf := make([]byte, len(want)) + readBits(buf, int) + if !bytes.Equal(buf, want) { + t.Errorf("have: %x\nwant: %x", buf, want) + } + } + check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0") + check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0") + check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0") +} diff --git a/crypto/secp256k1/pubkey_scalar_mul.h b/crypto/secp256k1/pubkey_scalar_mul.h new file mode 100644 index 000000000..0511545ec --- /dev/null +++ b/crypto/secp256k1/pubkey_scalar_mul.h @@ -0,0 +1,56 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +/** Multiply point by scalar in constant time. + * Returns: 1: multiplication was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: point: the multiplied point (usually secret) + * In: point: pointer to a 64-byte bytepublic point, + encoded as two 256bit big-endian numbers. + * scalar: a 32-byte scalar with which to multiply the point + */ +int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_fe feX, feY; + secp256k1_gej res; + secp256k1_ge ge; + secp256k1_scalar s; + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + secp256k1_fe_set_b32(&feX, point); + secp256k1_fe_set_b32(&feY, point+32); + secp256k1_ge_set_xy(&ge, &feX, &feY); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + secp256k1_ecmult_const(&res, &ge, &s); + secp256k1_ge_set_gej(&ge, &res); + /* Note: can't use secp256k1_pubkey_save here because it is not constant time. */ + secp256k1_fe_normalize(&ge.x); + secp256k1_fe_normalize(&ge.y); + secp256k1_fe_get_b32(point, &ge.x); + secp256k1_fe_get_b32(point+32, &ge.y); + ret = 1; + } + secp256k1_scalar_clear(&s); + return ret; +} + diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 41a5608a5..97b4bd8da 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -20,14 +20,8 @@ package secp256k1 /* #cgo CFLAGS: -I./libsecp256k1 -#cgo darwin CFLAGS: -I/usr/local/include -#cgo freebsd CFLAGS: -I/usr/local/include -#cgo linux,arm CFLAGS: -I/usr/local/arm/include -#cgo LDFLAGS: -lgmp -#cgo darwin LDFLAGS: -L/usr/local/lib -#cgo freebsd LDFLAGS: -L/usr/local/lib -#cgo linux,arm LDFLAGS: -L/usr/local/arm/lib -#define USE_NUM_GMP +#cgo CFLAGS: -I./libsecp256k1/src/ +#define USE_NUM_NONE #define USE_FIELD_10X26 #define USE_FIELD_INV_BUILTIN #define USE_SCALAR_8X32 @@ -35,6 +29,7 @@ package secp256k1 #define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" +#include "pubkey_scalar_mul.h" typedef void (*callbackFunc) (const char* msg, void* data); extern void secp256k1GoPanicIllegal(const char* msg, void* data); @@ -44,6 +39,7 @@ import "C" import ( "errors" + "math/big" "unsafe" "github.com/ethereum/go-ethereum/crypto/randentropy" @@ -56,13 +52,16 @@ import ( > store private keys in buffer and shuffle (deters persistance on swap disc) > byte permutation (changing) > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?) - > on disk: store keys in wallets */ // holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h) -var context *C.secp256k1_context +var ( + context *C.secp256k1_context + N *big.Int +) func init() { + N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) // around 20 ms on a modern CPU. context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) @@ -78,7 +77,6 @@ var ( func GenerateKeyPair() ([]byte, []byte) { var seckey []byte = randentropy.GetEntropyCSPRNG(32) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) - var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0])) @@ -254,3 +252,16 @@ func checkSignature(sig []byte) error { } return nil } + +// reads num into buf as big-endian bytes. +func readBits(buf []byte, num *big.Int) { + const wordLen = int(unsafe.Sizeof(big.Word(0))) + i := len(buf) + for _, d := range num.Bits() { + for j := 0; j < wordLen && i > 0; j++ { + i-- + buf[i] = byte(d) + d >>= 8 + } + } +} diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index cb71ea5e7..fc6fc9b32 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -24,7 +24,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/randentropy" ) -const TestCount = 10000 +const TestCount = 1000 func TestPrivkeyGenerate(t *testing.T) { _, seckey := GenerateKeyPair() @@ -86,10 +86,7 @@ func TestSignAndRecover(t *testing.T) { func TestRandomMessagesWithSameKey(t *testing.T) { pubkey, seckey := GenerateKeyPair() keys := func() ([]byte, []byte) { - // Sign function zeroes the privkey so we need a new one in each call - newkey := make([]byte, len(seckey)) - copy(newkey, seckey) - return pubkey, newkey + return pubkey, seckey } signAndRecoverWithRandomMessages(t, keys) } @@ -209,30 +206,32 @@ func compactSigCheck(t *testing.T, sig []byte) { } } -// godep go test -v -run=XXX -bench=BenchmarkSignRandomInputEachRound +// godep go test -v -run=XXX -bench=BenchmarkSign // add -benchtime=10s to benchmark longer for more accurate average -func BenchmarkSignRandomInputEachRound(b *testing.B) { + +// to avoid compiler optimizing the benchmarked function call +var err error + +func BenchmarkSign(b *testing.B) { for i := 0; i < b.N; i++ { - b.StopTimer() _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) b.StartTimer() - if _, err := Sign(msg, seckey); err != nil { - b.Fatal(err) - } + _, e := Sign(msg, seckey) + err = e + b.StopTimer() } } -//godep go test -v -run=XXX -bench=BenchmarkRecoverRandomInputEachRound -func BenchmarkRecoverRandomInputEachRound(b *testing.B) { +//godep go test -v -run=XXX -bench=BenchmarkECRec +func BenchmarkRecover(b *testing.B) { for i := 0; i < b.N; i++ { - b.StopTimer() _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) b.StartTimer() - if _, err := RecoverPubkey(msg, sig); err != nil { - b.Fatal(err) - } + _, e := RecoverPubkey(msg, sig) + err = e + b.StopTimer() } } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index a14f29424..dd19df3a2 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -210,7 +210,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID { // Pubkey returns the public key represented by the node ID. // It returns an error if the ID is not a point on the curve. func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { - p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} + p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)} half := len(id) / 2 p.X.SetBytes(id[:half]) p.Y.SetBytes(id[half:]) diff --git a/p2p/rlpx.go b/p2p/rlpx.go index aaa733854..8f429d6ec 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -277,7 +277,7 @@ func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) { return nil, err } // generate random keypair to use for signing - randpriv, err := ecies.GenerateKey(rand.Reader, crypto.S256(), nil) + randpriv, err := ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return nil, err } @@ -376,7 +376,7 @@ func decodeAuthMsg(prv *ecdsa.PrivateKey, token []byte, auth []byte) (*encHandsh var err error h := new(encHandshake) // generate random keypair for session - h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil) + h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return nil, err } diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go index 900353f0e..7cc7548e2 100644 --- a/p2p/rlpx_test.go +++ b/p2p/rlpx_test.go @@ -93,6 +93,7 @@ func testEncHandshake(token []byte) error { go func() { r := result{side: "initiator"} defer func() { output <- r }() + defer fd0.Close() dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)} r.id, r.err = c0.doEncHandshake(prv0, dest) @@ -107,6 +108,7 @@ func testEncHandshake(token []byte) error { go func() { r := result{side: "receiver"} defer func() { output <- r }() + defer fd1.Close() r.id, r.err = c1.doEncHandshake(prv1, nil) if r.err != nil { diff --git a/p2p/server.go b/p2p/server.go index ee670b10e..7991585f1 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -337,7 +337,7 @@ func (srv *Server) Start() (err error) { srv.ntab = ntab } - dynPeers := srv.MaxPeers / 2 + dynPeers := (srv.MaxPeers + 1) / 2 if !srv.Discovery { dynPeers = 0 } diff --git a/whisper/message_test.go b/whisper/message_test.go index 6ff95efff..d70da40a4 100644 --- a/whisper/message_test.go +++ b/whisper/message_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) // Tests whether a message can be wrapped without any identity or encryption. @@ -72,8 +73,8 @@ func TestMessageCleartextSignRecover(t *testing.T) { if pubKey == nil { t.Fatalf("failed to recover public key") } - p1 := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y) - p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) + p1 := elliptic.Marshal(secp256k1.S256(), key.PublicKey.X, key.PublicKey.Y) + p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) if !bytes.Equal(p1, p2) { t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) } @@ -150,8 +151,8 @@ func TestMessageFullCrypto(t *testing.T) { if pubKey == nil { t.Fatalf("failed to recover public key") } - p1 := elliptic.Marshal(crypto.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y) - p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) + p1 := elliptic.Marshal(secp256k1.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y) + p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) if !bytes.Equal(p1, p2) { t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) } |