aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--accounts/abi/bind/backend.go10
-rw-r--r--accounts/abi/bind/backends/remote.go15
-rw-r--r--accounts/abi/bind/backends/simulated.go11
-rw-r--r--accounts/abi/bind/bind_test.go28
-rw-r--r--accounts/watch.go2
-rw-r--r--accounts/watch_fallback.go2
-rw-r--r--cmd/bootnode/main.go46
-rw-r--r--cmd/geth/js.go16
-rw-r--r--cmd/geth/main.go22
-rw-r--r--common/types.go2
-rw-r--r--common/types_test.go38
-rw-r--r--core/genesis.go2
-rw-r--r--eth/api.go15
-rw-r--r--eth/filters/filter_system.go2
-rw-r--r--jsre/jsre.go9
15 files changed, 168 insertions, 52 deletions
diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/backend.go
index 328f9f3b7..7442557cc 100644
--- a/accounts/abi/bind/backend.go
+++ b/accounts/abi/bind/backend.go
@@ -17,12 +17,22 @@
package bind
import (
+ "errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
+// ErrNoCode is returned by call and transact operations for which the requested
+// recipient contract to operate on does not exist in the state db or does not
+// have any code associated with it (i.e. suicided).
+//
+// Please note, this error string is part of the RPC API and is expected by the
+// native contract bindings to signal this particular error. Do not change this
+// as it will break all dependent code!
+var ErrNoCode = errors.New("no contract code at given address")
+
// ContractCaller defines the methods needed to allow operating with contract on a read
// only basis.
type ContractCaller interface {
diff --git a/accounts/abi/bind/backends/remote.go b/accounts/abi/bind/backends/remote.go
index 8e990f076..9b3647192 100644
--- a/accounts/abi/bind/backends/remote.go
+++ b/accounts/abi/bind/backends/remote.go
@@ -66,10 +66,16 @@ type request struct {
type response struct {
JSONRPC string `json:"jsonrpc"` // Version of the JSON RPC protocol, always set to 2.0
ID int `json:"id"` // Auto incrementing ID number for this request
- Error json.RawMessage `json:"error"` // Any error returned by the remote side
+ Error *failure `json:"error"` // Any error returned by the remote side
Result json.RawMessage `json:"result"` // Whatever the remote side sends us in reply
}
+// failure is a JSON RPC response error field sent back from the API server.
+type failure struct {
+ Code int `json:"code"` // JSON RPC error code associated with the failure
+ Message string `json:"message"` // Specific error message of the failure
+}
+
// request forwards an API request to the RPC server, and parses the response.
//
// This is currently painfully non-concurrent, but it will have to do until we
@@ -96,8 +102,11 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
if err := b.client.Recv(res); err != nil {
return nil, err
}
- if len(res.Error) > 0 {
- return nil, fmt.Errorf("remote error: %s", string(res.Error))
+ if res.Error != nil {
+ if res.Error.Message == bind.ErrNoCode.Error() {
+ return nil, bind.ErrNoCode
+ }
+ return nil, fmt.Errorf("remote error: %s", res.Error.Message)
}
return res.Result, nil
}
diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 6cdb9a0cc..4866c4f58 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -92,6 +92,10 @@ func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pe
block = b.blockchain.CurrentBlock()
statedb, _ = b.blockchain.State()
}
+ // If there's no code to interact with, respond with an appropriate error
+ if code := statedb.GetCode(contract); len(code) == 0 {
+ return nil, bind.ErrNoCode
+ }
// Set infinite balance to the a fake caller account
from := statedb.GetOrNewStateObject(common.Address{})
from.SetBalance(common.MaxBig)
@@ -134,7 +138,12 @@ func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *com
block = b.pendingBlock
statedb = b.pendingState.Copy()
)
-
+ // If there's no code to interact with, respond with an appropriate error
+ if contract != nil {
+ if code := statedb.GetCode(*contract); len(code) == 0 {
+ return nil, bind.ErrNoCode
+ }
+ }
// Set infinite balance to the a fake caller account
from := statedb.GetOrNewStateObject(sender)
from.SetBalance(common.MaxBig)
diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go
index 5c36bc48f..f9cc8aba4 100644
--- a/accounts/abi/bind/bind_test.go
+++ b/accounts/abi/bind/bind_test.go
@@ -303,6 +303,34 @@ var bindTests = []struct {
}
`,
},
+ // Tests that non-existent contracts are reported as such (though only simulator test)
+ {
+ `NonExistent`,
+ `
+ contract NonExistent {
+ function String() constant returns(string) {
+ return "I don't exist";
+ }
+ }
+ `,
+ `6060604052609f8060106000396000f3606060405260e060020a6000350463f97a60058114601a575b005b600060605260c0604052600d60809081527f4920646f6e27742065786973740000000000000000000000000000000000000060a052602060c0908152600d60e081905281906101009060a09080838184600060046012f15050815172ffffffffffffffffffffffffffffffffffffff1916909152505060405161012081900392509050f3`,
+ `[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
+ `
+ // Create a simulator and wrap a non-deployed contract
+ sim := backends.NewSimulatedBackend()
+
+ nonexistent, err := NewNonExistent(common.Address{}, sim)
+ if err != nil {
+ t.Fatalf("Failed to access non-existent contract: %v", err)
+ }
+ // Ensure that contract calls fail with the appropriate error
+ if res, err := nonexistent.String(nil); err == nil {
+ t.Fatalf("Call succeeded on non-existent contract: %v", res)
+ } else if (err != bind.ErrNoCode) {
+ t.Fatalf("Error mismatch: have %v, want %v", err, bind.ErrNoCode)
+ }
+ `,
+ },
}
// Tests that packages generated by the binder can be successfully compiled and
diff --git a/accounts/watch.go b/accounts/watch.go
index 19d304fcc..309e4d458 100644
--- a/accounts/watch.go
+++ b/accounts/watch.go
@@ -14,7 +14,7 @@
// 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/>.
-// +build darwin,!ios freebsd linux netbsd solaris windows
+// +build darwin,!ios freebsd linux,!arm64 netbsd solaris windows
package accounts
diff --git a/accounts/watch_fallback.go b/accounts/watch_fallback.go
index 0b7016167..7b5e221df 100644
--- a/accounts/watch_fallback.go
+++ b/accounts/watch_fallback.go
@@ -14,7 +14,7 @@
// 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/>.
-// +build ios !darwin,!freebsd,!linux,!netbsd,!solaris,!windows
+// +build ios linux,arm64 !darwin,!freebsd,!linux,!netbsd,!solaris,!windows
// This is the fallback implementation of directory watching.
// It is used on unsupported platforms.
diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go
index 7f74e9c70..7d3f9fdb3 100644
--- a/cmd/bootnode/main.go
+++ b/cmd/bootnode/main.go
@@ -19,15 +19,12 @@ package main
import (
"crypto/ecdsa"
- "encoding/hex"
"flag"
- "fmt"
- "io/ioutil"
- "log"
"os"
+ "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/nat"
)
@@ -43,50 +40,43 @@ func main() {
nodeKey *ecdsa.PrivateKey
err error
)
+ flag.Var(glog.GetVerbosity(), "verbosity", "log verbosity (0-9)")
+ flag.Var(glog.GetVModule(), "vmodule", "log verbosity pattern")
+ glog.SetToStderr(true)
flag.Parse()
- logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.DebugLevel))
if *genKey != "" {
- writeKey(*genKey)
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ utils.Fatalf("could not generate key: %v", err)
+ }
+ if err := crypto.SaveECDSA(*genKey, key); err != nil {
+ utils.Fatalf("%v", err)
+ }
os.Exit(0)
}
natm, err := nat.Parse(*natdesc)
if err != nil {
- log.Fatalf("-nat: %v", err)
+ utils.Fatalf("-nat: %v", err)
}
switch {
case *nodeKeyFile == "" && *nodeKeyHex == "":
- log.Fatal("Use -nodekey or -nodekeyhex to specify a private key")
+ utils.Fatalf("Use -nodekey or -nodekeyhex to specify a private key")
case *nodeKeyFile != "" && *nodeKeyHex != "":
- log.Fatal("Options -nodekey and -nodekeyhex are mutually exclusive")
+ utils.Fatalf("Options -nodekey and -nodekeyhex are mutually exclusive")
case *nodeKeyFile != "":
if nodeKey, err = crypto.LoadECDSA(*nodeKeyFile); err != nil {
- log.Fatalf("-nodekey: %v", err)
+ utils.Fatalf("-nodekey: %v", err)
}
case *nodeKeyHex != "":
if nodeKey, err = crypto.HexToECDSA(*nodeKeyHex); err != nil {
- log.Fatalf("-nodekeyhex: %v", err)
+ utils.Fatalf("-nodekeyhex: %v", err)
}
}
if _, err := discover.ListenUDP(nodeKey, *listenAddr, natm, ""); err != nil {
- log.Fatal(err)
+ utils.Fatalf("%v", err)
}
select {}
}
-
-func writeKey(target string) {
- key, err := crypto.GenerateKey()
- if err != nil {
- log.Fatalf("could not generate key: %v", err)
- }
- b := crypto.FromECDSA(key)
- if target == "-" {
- fmt.Println(hex.EncodeToString(b))
- } else {
- if err := ioutil.WriteFile(target, b, 0600); err != nil {
- log.Fatal("write error: ", err)
- }
- }
-}
diff --git a/cmd/geth/js.go b/cmd/geth/js.go
index 767b513c1..2b64303b2 100644
--- a/cmd/geth/js.go
+++ b/cmd/geth/js.go
@@ -123,7 +123,7 @@ func (self *jsre) batch(statement string) {
err := self.re.EvalAndPrettyPrint(statement)
if err != nil {
- fmt.Printf("error: %v", err)
+ fmt.Printf("%v", jsErrorString(err))
}
if self.atexit != nil {
@@ -301,21 +301,19 @@ func (self *jsre) preloadJSFiles(ctx *cli.Context) error {
for _, file := range jsFiles {
filename := common.AbsolutePath(assetPath, strings.TrimSpace(file))
if err := self.re.Exec(filename); err != nil {
- return fmt.Errorf("%s: %v", file, err)
+ return fmt.Errorf("%s: %v", file, jsErrorString(err))
}
}
}
return nil
}
-// exec executes the JS file with the given filename and stops the JSRE
-func (self *jsre) exec(filename string) error {
- if err := self.re.Exec(filename); err != nil {
- self.re.Stop(false)
- return fmt.Errorf("Javascript Error: %v", err)
+// jsErrorString adds a backtrace to errors generated by otto.
+func jsErrorString(err error) string {
+ if ottoErr, ok := err.(*otto.Error); ok {
+ return ottoErr.String()
}
- self.re.Stop(true)
- return nil
+ return err.Error()
}
func (self *jsre) interactive() {
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 6ab4ed45b..a43daba2f 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -21,6 +21,7 @@ import (
"fmt"
"io/ioutil"
"os"
+ "os/signal"
"path/filepath"
"runtime"
"strconv"
@@ -353,7 +354,7 @@ func console(ctx *cli.Context) {
// preload user defined JS files into the console
err = repl.preloadJSFiles(ctx)
if err != nil {
- utils.Fatalf("unable to preload JS file %v", err)
+ utils.Fatalf("%v", err)
}
// in case the exec flag holds a JS statement execute it and return
@@ -372,6 +373,7 @@ func execScripts(ctx *cli.Context) {
// Create and start the node based on the CLI flags
node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx)
startNode(ctx, node)
+ defer node.Stop()
// Attach to the newly started node and execute the given scripts
client, err := node.Attach()
@@ -383,10 +385,24 @@ func execScripts(ctx *cli.Context) {
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
client, false)
+ // Run all given files.
for _, file := range ctx.Args() {
- repl.exec(file)
+ if err = repl.re.Exec(file); err != nil {
+ break
+ }
}
- node.Stop()
+ if err != nil {
+ utils.Fatalf("JavaScript Error: %v", jsErrorString(err))
+ }
+ // JS files loaded successfully.
+ // Wait for pending callbacks, but stop for Ctrl-C.
+ abort := make(chan os.Signal, 1)
+ signal.Notify(abort, os.Interrupt)
+ go func() {
+ <-abort
+ repl.re.Stop(false)
+ }()
+ repl.re.Stop(true)
}
// startNode boots up the system node and all registered protocols, after which
diff --git a/common/types.go b/common/types.go
index fec986164..d00884484 100644
--- a/common/types.go
+++ b/common/types.go
@@ -167,7 +167,7 @@ func (a Address) MarshalJSON() ([]byte, error) {
// Parse address from raw json data
func (a *Address) UnmarshalJSON(data []byte) error {
if len(data) > 2 && data[0] == '"' && data[len(data)-1] == '"' {
- data = data[:len(data)-1][1:]
+ data = data[1 : len(data)-1]
}
if len(data) > 2 && data[0] == '0' && data[1] == 'x' {
diff --git a/common/types_test.go b/common/types_test.go
index f2dfbf0c9..de67cfcb5 100644
--- a/common/types_test.go
+++ b/common/types_test.go
@@ -16,7 +16,10 @@
package common
-import "testing"
+import (
+ "math/big"
+ "testing"
+)
func TestBytesConversion(t *testing.T) {
bytes := []byte{5}
@@ -47,7 +50,38 @@ func TestHashJsonValidation(t *testing.T) {
}
for i, test := range tests {
if err := h.UnmarshalJSON(append([]byte(test.Prefix), make([]byte, test.Size)...)); err != test.Error {
- t.Error(i, "expected", test.Error, "got", err)
+ t.Errorf("test #%d: error mismatch: have %v, want %v", i, err, test.Error)
+ }
+ }
+}
+
+func TestAddressUnmarshalJSON(t *testing.T) {
+ var a Address
+ var tests = []struct {
+ Input string
+ ShouldErr bool
+ Output *big.Int
+ }{
+ {"", true, nil},
+ {`""`, true, nil},
+ {`"0x"`, true, nil},
+ {`"0x00"`, true, nil},
+ {`"0xG000000000000000000000000000000000000000"`, true, nil},
+ {`"0x0000000000000000000000000000000000000000"`, false, big.NewInt(0)},
+ {`"0x0000000000000000000000000000000000000010"`, false, big.NewInt(16)},
+ }
+ for i, test := range tests {
+ err := a.UnmarshalJSON([]byte(test.Input))
+ if err != nil && !test.ShouldErr {
+ t.Errorf("test #%d: unexpected error: %v", i, err)
+ }
+ if err == nil {
+ if test.ShouldErr {
+ t.Errorf("test #%d: expected error, got none", i)
+ }
+ if a.Big().Cmp(test.Output) != 0 {
+ t.Errorf("test #%d: address mismatch: have %v, want %v", i, a.Big(), test.Output)
+ }
}
}
}
diff --git a/core/genesis.go b/core/genesis.go
index 5c69b216c..40d799621 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -43,7 +43,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
}
var genesis struct {
- ChainConfig *ChainConfig
+ ChainConfig *ChainConfig `json:"config"`
Nonce string
Timestamp string
ParentHash string
diff --git a/eth/api.go b/eth/api.go
index a0b1f8ac2..02b34541f 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -51,6 +51,15 @@ import (
"golang.org/x/net/context"
)
+// ErrNoCode is returned by call and transact operations for which the requested
+// recipient contract to operate on does not exist in the state db or does not
+// have any code associated with it (i.e. suicided).
+//
+// Please note, this error string is part of the RPC API and is expected by the
+// native contract bindings to signal this particular error. Do not change this
+// as it will break all dependent code!
+var ErrNoCode = errors.New("no contract code at given address")
+
const defaultGas = uint64(90000)
// blockByNumber is a commonly used helper function which retrieves and returns
@@ -694,6 +703,12 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st
}
stateDb = stateDb.Copy()
+ // If there's no code to interact with, respond with an appropriate error
+ if args.To != nil {
+ if code := stateDb.GetCode(*args.To); len(code) == 0 {
+ return "0x", nil, ErrNoCode
+ }
+ }
// Retrieve the account state object to interact with
var from *state.StateObject
if args.From == (common.Address{}) {
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index 29968530a..4343dfa21 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -164,7 +164,7 @@ func (fs *FilterSystem) filterLoop() {
fs.filterMu.RLock()
for _, filter := range fs.logFilters {
if filter.LogCallback != nil && !filter.created.After(event.Time) {
- for _, removedLog := range ev.Logs {
+ for _, removedLog := range filter.FilterLogs(ev.Logs) {
filter.LogCallback(removedLog, true)
}
}
diff --git a/jsre/jsre.go b/jsre/jsre.go
index 7df022cb1..59730bc0d 100644
--- a/jsre/jsre.go
+++ b/jsre/jsre.go
@@ -235,7 +235,14 @@ func (self *JSRE) Exec(file string) error {
if err != nil {
return err
}
- self.Do(func(vm *otto.Otto) { _, err = vm.Run(code) })
+ var script *otto.Script
+ self.Do(func(vm *otto.Otto) {
+ script, err = vm.Compile(file, code)
+ if err != nil {
+ return
+ }
+ _, err = vm.Run(script)
+ })
return err
}