Преглед на файлове

Merge remote-tracking branch 'ethereum/conversion' into conversion

Felix Lange преди 10 години
родител
ревизия
d15f90645d

+ 259 - 0
cmd/ethereum/admin.go

@@ -0,0 +1,259 @@
+package main
+
+import (
+	"fmt"
+	"net"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/rlp"
+	"github.com/ethereum/go-ethereum/rpc"
+	"github.com/ethereum/go-ethereum/state"
+	"github.com/ethereum/go-ethereum/xeth"
+	"github.com/obscuren/otto"
+)
+
+/*
+node admin bindings
+*/
+
+func (js *jsre) adminBindings() {
+	js.re.Set("admin", struct{}{})
+	t, _ := js.re.Get("admin")
+	admin := t.Object()
+	admin.Set("suggestPeer", js.suggestPeer)
+	admin.Set("startRPC", js.startRPC)
+	admin.Set("startMining", js.startMining)
+	admin.Set("stopMining", js.stopMining)
+	admin.Set("nodeInfo", js.nodeInfo)
+	admin.Set("peers", js.peers)
+	admin.Set("newAccount", js.newAccount)
+	admin.Set("unlock", js.unlock)
+	admin.Set("import", js.importChain)
+	admin.Set("export", js.exportChain)
+	admin.Set("dumpBlock", js.dumpBlock)
+}
+
+func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
+	_, err := call.Argument(0).ToInteger()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	// threads now ignored
+	err = js.ethereum.StartMining()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	return otto.TrueValue()
+}
+
+func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
+	js.ethereum.StopMining()
+	return otto.TrueValue()
+}
+
+func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
+	addr, err := call.Argument(0).ToString()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	port, err := call.Argument(1).ToInteger()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	dataDir := js.ethereum.DataDir
+
+	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
+	if err != nil {
+		fmt.Printf("Can't listen on %s:%d: %v", addr, port, err)
+		return otto.FalseValue()
+	}
+	go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil), dataDir))
+	return otto.TrueValue()
+}
+
+func (js *jsre) suggestPeer(call otto.FunctionCall) otto.Value {
+	nodeURL, err := call.Argument(0).ToString()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	err = js.ethereum.SuggestPeer(nodeURL)
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	return otto.TrueValue()
+}
+
+func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
+	addr, err := call.Argument(0).ToString()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	seconds, err := call.Argument(2).ToInteger()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	arg := call.Argument(1)
+	var passphrase string
+	if arg.IsUndefined() {
+		fmt.Println("Please enter a passphrase now.")
+		passphrase, err = readPassword("Passphrase: ", true)
+		if err != nil {
+			utils.Fatalf("%v", err)
+		}
+	} else {
+		passphrase, err = arg.ToString()
+		if err != nil {
+			fmt.Println(err)
+			return otto.FalseValue()
+		}
+	}
+	am := js.ethereum.AccountManager()
+	// err := am.Unlock(common.FromHex(split[0]), split[1])
+	// if err != nil {
+	// 	utils.Fatalf("Unlock account failed '%v'", err)
+	// }
+	err = am.TimedUnlock(common.FromHex(addr), passphrase, time.Duration(seconds)*time.Second)
+	if err != nil {
+		fmt.Printf("Unlock account failed '%v'\n", err)
+		return otto.FalseValue()
+	}
+	return otto.TrueValue()
+}
+
+func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
+	arg := call.Argument(0)
+	var passphrase string
+	if arg.IsUndefined() {
+		fmt.Println("The new account will be encrypted with a passphrase.")
+		fmt.Println("Please enter a passphrase now.")
+		auth, err := readPassword("Passphrase: ", true)
+		if err != nil {
+			utils.Fatalf("%v", err)
+		}
+		confirm, err := readPassword("Repeat Passphrase: ", false)
+		if err != nil {
+			utils.Fatalf("%v", err)
+		}
+		if auth != confirm {
+			utils.Fatalf("Passphrases did not match.")
+		}
+		passphrase = auth
+	} else {
+		var err error
+		passphrase, err = arg.ToString()
+		if err != nil {
+			fmt.Println(err)
+			return otto.FalseValue()
+		}
+	}
+	acct, err := js.ethereum.AccountManager().NewAccount(passphrase)
+	if err != nil {
+		fmt.Printf("Could not create the account: %v", err)
+		return otto.UndefinedValue()
+	}
+	return js.re.ToVal(common.Bytes2Hex(acct.Address))
+}
+
+func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
+	return js.re.ToVal(js.ethereum.NodeInfo())
+}
+
+func (js *jsre) peers(call otto.FunctionCall) otto.Value {
+	return js.re.ToVal(js.ethereum.PeersInfo())
+}
+
+func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
+	if len(call.ArgumentList) == 0 {
+		fmt.Println("err: require file name")
+		return otto.FalseValue()
+	}
+
+	fn, err := call.Argument(0).ToString()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	var fh *os.File
+	fh, err = os.OpenFile(fn, os.O_RDONLY, os.ModePerm)
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+	defer fh.Close()
+
+	var blocks types.Blocks
+	if err = rlp.Decode(fh, &blocks); err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	js.ethereum.ChainManager().Reset()
+	if err = js.ethereum.ChainManager().InsertChain(blocks); err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	return otto.TrueValue()
+}
+
+func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
+	if len(call.ArgumentList) == 0 {
+		fmt.Println("err: require file name")
+		return otto.FalseValue()
+	}
+
+	fn, err := call.Argument(0).ToString()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	data := js.ethereum.ChainManager().Export()
+	if err := common.WriteFile(fn, data); err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	return otto.TrueValue()
+}
+
+func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
+	var block *types.Block
+	if len(call.ArgumentList) > 0 {
+		if call.Argument(0).IsNumber() {
+			num, _ := call.Argument(0).ToInteger()
+			block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
+		} else if call.Argument(0).IsString() {
+			hash, _ := call.Argument(0).ToString()
+			block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
+		} else {
+			fmt.Println("invalid argument for dump. Either hex string or number")
+		}
+
+	} else {
+		block = js.ethereum.ChainManager().CurrentBlock()
+	}
+	if block == nil {
+		fmt.Println("block not found")
+		return otto.UndefinedValue()
+	}
+
+	statedb := state.New(block.Root(), js.ethereum.StateDb())
+	dump := statedb.RawDump()
+	return js.re.ToVal(dump)
+
+}

+ 54 - 114
cmd/ethereum/js.go

@@ -20,18 +20,16 @@ package main
 import (
 	"bufio"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"strings"
 
+	"github.com/ethereum/go-ethereum/cmd/utils"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/javascript"
-	"github.com/ethereum/go-ethereum/state"
+	re "github.com/ethereum/go-ethereum/jsre"
+	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/ethereum/go-ethereum/xeth"
-	"github.com/obscuren/otto"
 	"github.com/peterh/liner"
 )
 
@@ -59,7 +57,7 @@ func (r dumbterm) PasswordPrompt(p string) (string, error) {
 func (r dumbterm) AppendHistory(string) {}
 
 type jsre struct {
-	re       *javascript.JSRE
+	re       *re.JSRE
 	ethereum *eth.Ethereum
 	xeth     *xeth.XEth
 	ps1      string
@@ -68,11 +66,12 @@ type jsre struct {
 	prompter
 }
 
-func newJSRE(ethereum *eth.Ethereum) *jsre {
+func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
 	js := &jsre{ethereum: ethereum, ps1: "> "}
 	js.xeth = xeth.New(ethereum, js)
-	js.re = javascript.NewJSRE(js.xeth)
-	js.initStdFuncs()
+	js.re = re.New(libPath)
+	js.apiBindings()
+	js.adminBindings()
 
 	if !liner.TerminalSupported() {
 		js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
@@ -89,6 +88,49 @@ func newJSRE(ethereum *eth.Ethereum) *jsre {
 	return js
 }
 
+func (js *jsre) apiBindings() {
+
+	ethApi := rpc.NewEthereumApi(js.xeth, js.ethereum.DataDir)
+	js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal))
+
+	_, err := js.re.Eval(re.BigNumber_JS)
+
+	if err != nil {
+		utils.Fatalf("Error loading bignumber.js: %v", err)
+	}
+
+	// we need to declare a dummy setTimeout. Otto does not support it
+	_, err = js.re.Eval("setTimeout = function(cb, delay) {};")
+	if err != nil {
+		utils.Fatalf("Error defining setTimeout: %v", err)
+	}
+
+	_, err = js.re.Eval(re.Ethereum_JS)
+	if err != nil {
+		utils.Fatalf("Error loading ethereum.js: %v", err)
+	}
+
+	_, err = js.re.Eval("var web3 = require('web3');")
+	if err != nil {
+		utils.Fatalf("Error requiring web3: %v", err)
+	}
+
+	_, err = js.re.Eval("web3.setProvider(jeth)")
+	if err != nil {
+		utils.Fatalf("Error setting web3 provider: %v", err)
+	}
+	_, err = js.re.Eval(`
+	var eth = web3.eth;
+  var shh = web3.shh;
+  var db  = web3.db;
+  var net = web3.net;
+  `)
+	if err != nil {
+		utils.Fatalf("Error setting namespaces: %v", err)
+	}
+
+}
+
 func (self *jsre) ConfirmTransaction(tx *types.Transaction) bool {
 	p := fmt.Sprintf("Confirm Transaction %v\n[y/n] ", tx)
 	answer, _ := self.Prompt(p)
@@ -111,15 +153,7 @@ func (self *jsre) UnlockAccount(addr []byte) bool {
 }
 
 func (self *jsre) exec(filename string) error {
-	file, err := os.Open(filename)
-	if err != nil {
-		return err
-	}
-	content, err := ioutil.ReadAll(file)
-	if err != nil {
-		return err
-	}
-	if _, err := self.re.Run(string(content)); err != nil {
+	if err := self.re.Exec(filename); err != nil {
 		return fmt.Errorf("Javascript Error: %v", err)
 	}
 	return nil
@@ -193,102 +227,8 @@ func (self *jsre) setIndent() {
 }
 
 func (self *jsre) printValue(v interface{}) {
-	method, _ := self.re.Vm.Get("prettyPrint")
-	v, err := self.re.Vm.ToValue(v)
+	val, err := self.re.PrettyPrint(v)
 	if err == nil {
-		val, err := method.Call(method, v)
-		if err == nil {
-			fmt.Printf("%v", val)
-		}
-	}
-}
-
-func (self *jsre) initStdFuncs() {
-	t, _ := self.re.Vm.Get("eth")
-	eth := t.Object()
-	eth.Set("connect", self.connect)
-	eth.Set("stopMining", self.stopMining)
-	eth.Set("startMining", self.startMining)
-	eth.Set("dump", self.dump)
-	eth.Set("export", self.export)
-}
-
-/*
- * The following methods are natively implemented javascript functions.
- */
-
-func (self *jsre) dump(call otto.FunctionCall) otto.Value {
-	var block *types.Block
-
-	if len(call.ArgumentList) > 0 {
-		if call.Argument(0).IsNumber() {
-			num, _ := call.Argument(0).ToInteger()
-			block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num))
-		} else if call.Argument(0).IsString() {
-			hash, _ := call.Argument(0).ToString()
-			block = self.ethereum.ChainManager().GetBlock(common.Hex2Bytes(hash))
-		} else {
-			fmt.Println("invalid argument for dump. Either hex string or number")
-		}
-
-		if block == nil {
-			fmt.Println("block not found")
-
-			return otto.UndefinedValue()
-		}
-
-	} else {
-		block = self.ethereum.ChainManager().CurrentBlock()
-	}
-
-	statedb := state.New(block.Root(), self.ethereum.StateDb())
-
-	v, _ := self.re.Vm.ToValue(statedb.RawDump())
-
-	return v
-}
-
-func (self *jsre) stopMining(call otto.FunctionCall) otto.Value {
-	self.ethereum.StopMining()
-	return otto.TrueValue()
-}
-
-func (self *jsre) startMining(call otto.FunctionCall) otto.Value {
-	if err := self.ethereum.StartMining(); err != nil {
-		return otto.FalseValue()
-	}
-	return otto.TrueValue()
-}
-
-func (self *jsre) connect(call otto.FunctionCall) otto.Value {
-	nodeURL, err := call.Argument(0).ToString()
-	if err != nil {
-		return otto.FalseValue()
-	}
-	if err := self.ethereum.SuggestPeer(nodeURL); err != nil {
-		return otto.FalseValue()
-	}
-	return otto.TrueValue()
-}
-
-func (self *jsre) export(call otto.FunctionCall) otto.Value {
-	if len(call.ArgumentList) == 0 {
-		fmt.Println("err: require file name")
-		return otto.FalseValue()
-	}
-
-	fn, err := call.Argument(0).ToString()
-	if err != nil {
-		fmt.Println(err)
-		return otto.FalseValue()
-	}
-
-	data := self.ethereum.ChainManager().Export()
-
-	if err := common.WriteFile(fn, data); err != nil {
-		fmt.Println(err)
-		return otto.FalseValue()
+		fmt.Printf("%v", val)
 	}
-
-	return otto.TrueValue()
 }

+ 252 - 0
cmd/ethereum/js_test.go

@@ -0,0 +1,252 @@
+package main
+
+import (
+	"fmt"
+	"github.com/obscuren/otto"
+	"os"
+	"path"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/accounts"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/eth"
+)
+
+var port = 30300
+
+func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) {
+	os.RemoveAll("/tmp/eth/")
+	err = os.MkdirAll("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/", os.ModePerm)
+	if err != nil {
+		t.Errorf("%v", err)
+		return
+	}
+	err = os.MkdirAll("/tmp/eth/data", os.ModePerm)
+	if err != nil {
+		t.Errorf("%v", err)
+		return
+	}
+	// FIXME: this does not work ATM
+	ks := crypto.NewKeyStorePlain("/tmp/eth/keys")
+	common.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d",
+		[]byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`))
+
+	port++
+	ethereum, err = eth.New(&eth.Config{
+		DataDir:        "/tmp/eth",
+		AccountManager: accounts.NewManager(ks),
+		Port:           fmt.Sprintf("%d", port),
+		MaxPeers:       10,
+		Name:           "test",
+	})
+
+	if err != nil {
+		t.Errorf("%v", err)
+		return
+	}
+	assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
+	repl = newJSRE(ethereum, assetPath)
+	return
+}
+
+func TestNodeInfo(t *testing.T) {
+	repl, ethereum, err := testJEthRE(t)
+	if err != nil {
+		t.Errorf("error creating jsre, got %v", err)
+		return
+	}
+	err = ethereum.Start()
+	if err != nil {
+		t.Errorf("error starting ethereum: %v", err)
+		return
+	}
+	defer ethereum.Stop()
+
+	val, err := repl.re.Run("admin.nodeInfo()")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	exp, err := val.Export()
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	nodeInfo, ok := exp.(*eth.NodeInfo)
+	if !ok {
+		t.Errorf("expected nodeInfo, got %v", err)
+	}
+	exp = "test"
+	got := nodeInfo.Name
+	if exp != got {
+		t.Errorf("expected %v, got %v", exp, got)
+	}
+	exp = 30301
+	port := nodeInfo.DiscPort
+	if exp != port {
+		t.Errorf("expected %v, got %v", exp, port)
+	}
+	exp = 30301
+	port = nodeInfo.TCPPort
+	if exp != port {
+		t.Errorf("expected %v, got %v", exp, port)
+	}
+}
+
+func TestAccounts(t *testing.T) {
+	repl, ethereum, err := testJEthRE(t)
+	if err != nil {
+		t.Errorf("error creating jsre, got %v", err)
+		return
+	}
+	err = ethereum.Start()
+	if err != nil {
+		t.Errorf("error starting ethereum: %v", err)
+		return
+	}
+	defer ethereum.Stop()
+
+	val, err := repl.re.Run("eth.coinbase")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+
+	pp, err := repl.re.PrettyPrint(val)
+	if err != nil {
+		t.Errorf("%v", err)
+	}
+
+	if !val.IsString() {
+		t.Errorf("incorrect type, expected string, got %v: %v", val, pp)
+	}
+	strVal, _ := val.ToString()
+	expected := "0xe273f01c99144c438695e10f24926dc1f9fbf62d"
+	if strVal != expected {
+		t.Errorf("incorrect result, expected %s, got %v", expected, strVal)
+	}
+
+	val, err = repl.re.Run(`admin.newAccount("password")`)
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	addr, err := val.ToString()
+	if err != nil {
+		t.Errorf("expected string, got %v", err)
+	}
+
+	val, err = repl.re.Run("eth.accounts")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	exp, err := val.Export()
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	addrs, ok := exp.([]string)
+	if !ok {
+		t.Errorf("expected []string, got %v", err)
+	}
+	if len(addrs) != 2 || (addr != addrs[0][2:] && addr != addrs[1][2:]) {
+		t.Errorf("expected addrs == [<default>, <new>], got %v (%v)", addrs, addr)
+	}
+
+}
+
+func TestBlockChain(t *testing.T) {
+	repl, ethereum, err := testJEthRE(t)
+	if err != nil {
+		t.Errorf("error creating jsre, got %v", err)
+		return
+	}
+	err = ethereum.Start()
+	if err != nil {
+		t.Errorf("error starting ethereum: %v", err)
+		return
+	}
+	defer ethereum.Stop()
+
+	// should get current block
+	val0, err := repl.re.Run("admin.dumpBlock()")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+
+	fn := "/tmp/eth/data/blockchain.0"
+	_, err = repl.re.Run("admin.export(\"" + fn + "\")")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	if _, err = os.Stat(fn); err != nil {
+		t.Errorf("expected no error on file, got %v", err)
+	}
+
+	_, err = repl.re.Run("admin.import(\"" + fn + "\")")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+
+	var val1 otto.Value
+
+	// should get current block
+	val1, err = repl.re.Run("admin.dumpBlock()")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+
+	// FIXME: neither != , nor reflect.DeepEqual works, doing string comparison
+	v0 := fmt.Sprintf("%v", val0)
+	v1 := fmt.Sprintf("%v", val1)
+	if v0 != v1 {
+		t.Errorf("expected same head after export-import, got %v (!=%v)", v1, v0)
+	}
+}
+
+func TestMining(t *testing.T) {
+	repl, ethereum, err := testJEthRE(t)
+	if err != nil {
+		t.Errorf("error creating jsre, got %v", err)
+		return
+	}
+	err = ethereum.Start()
+	if err != nil {
+		t.Errorf("error starting ethereum: %v", err)
+		return
+	}
+	defer ethereum.Stop()
+
+	val, err := repl.re.Run("eth.mining")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	var mining bool
+	mining, err = val.ToBoolean()
+	if err != nil {
+		t.Errorf("expected boolean, got %v", err)
+	}
+	if mining {
+		t.Errorf("expected false (not mining), got true")
+	}
+
+}
+
+func TestRPC(t *testing.T) {
+	repl, ethereum, err := testJEthRE(t)
+	if err != nil {
+		t.Errorf("error creating jsre, got %v", err)
+		return
+	}
+	err = ethereum.Start()
+	if err != nil {
+		t.Errorf("error starting ethereum: %v", err)
+		return
+	}
+	defer ethereum.Stop()
+
+	val, err := repl.re.Run(`admin.startRPC("127.0.0.1", 5004)`)
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	success, _ := val.ToBoolean()
+	if !success {
+		t.Errorf("expected true (started), got false")
+	}
+}

+ 37 - 19
cmd/ethereum/main.go

@@ -31,9 +31,9 @@ import (
 
 	"github.com/codegangsta/cli"
 	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/state"
 	"github.com/peterh/liner"
@@ -41,7 +41,7 @@ import (
 
 const (
 	ClientIdentifier = "Ethereum(G)"
-	Version          = "0.9.0"
+	Version          = "0.9.1"
 )
 
 var (
@@ -89,16 +89,20 @@ Use "ethereum dump 0" to dump the genesis block.
 `,
 		},
 		{
-			Action: runjs,
+			Action: console,
+			Name:   "console",
+			Usage:  `Ethereum Console: interactive JavaScript environment`,
+			Description: `
+Console is an interactive shell for the Ethereum JavaScript runtime environment which exposes a node admin interface as well as the DAPP JavaScript API.
+See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
+`,
+		},
+		{
+			Action: execJSFiles,
 			Name:   "js",
-			Usage:  `interactive JavaScript console`,
+			Usage:  `executes the given JavaScript files in the Ethereum Frontier JavaScript VM`,
 			Description: `
-In the console, you can use the eth object to interact
-with the running ethereum stack. The API does not match
-ethereum.js.
-
-A JavaScript file can be provided as the argument. The
-runtime will execute the file and exit.
+The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
 `,
 		},
 		{
@@ -116,6 +120,7 @@ runtime will execute the file and exit.
 		utils.UnlockedAccountFlag,
 		utils.BootnodesFlag,
 		utils.DataDirFlag,
+		utils.JSpathFlag,
 		utils.ListenPortFlag,
 		utils.LogFileFlag,
 		utils.LogFormatFlag,
@@ -131,6 +136,7 @@ runtime will execute the file and exit.
 		utils.RPCPortFlag,
 		utils.UnencryptedKeysFlag,
 		utils.VMDebugFlag,
+
 		//utils.VMTypeFlag,
 	}
 
@@ -168,7 +174,7 @@ func run(ctx *cli.Context) {
 	ethereum.WaitForShutdown()
 }
 
-func runjs(ctx *cli.Context) {
+func console(ctx *cli.Context) {
 	cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
 	ethereum, err := eth.New(cfg)
 	if err != nil {
@@ -176,14 +182,26 @@ func runjs(ctx *cli.Context) {
 	}
 
 	startEth(ctx, ethereum)
-	repl := newJSRE(ethereum)
-	if len(ctx.Args()) == 0 {
-		repl.interactive()
-	} else {
-		for _, file := range ctx.Args() {
-			repl.exec(file)
-		}
+	repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name))
+	repl.interactive()
+
+	ethereum.Stop()
+	ethereum.WaitForShutdown()
+}
+
+func execJSFiles(ctx *cli.Context) {
+	cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
+	ethereum, err := eth.New(cfg)
+	if err != nil {
+		utils.Fatalf("%v", err)
 	}
+
+	startEth(ctx, ethereum)
+	repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name))
+	for _, file := range ctx.Args() {
+		repl.exec(file)
+	}
+
 	ethereum.Stop()
 	ethereum.WaitForShutdown()
 }
@@ -284,7 +302,7 @@ func dump(ctx *cli.Context) {
 	for _, arg := range ctx.Args() {
 		var block *types.Block
 		if hashish(arg) {
-			block = chainmgr.GetBlock(common.Hex2Bytes(arg))
+			block = chainmgr.GetBlock(common.HexToHash(arg))
 		} else {
 			num, _ := strconv.Atoi(arg)
 			block = chainmgr.GetBlockByNumber(uint64(num))

Файловите разлики са ограничени, защото са твърде много
+ 0 - 1
cmd/mist/assets/ext/bignumber.min.js


+ 52 - 62
cmd/mist/assets/qml/main.qml

@@ -12,7 +12,7 @@ import "../ext/http.js" as Http
 
 ApplicationWindow {
     id: root
-    
+
     //flags: Qt.FramelessWindowHint
     // Use this to make the window frameless. But then you'll need to do move and resize by hand
 
@@ -53,7 +53,7 @@ ApplicationWindow {
         whisperTab.view.url = "http://ethereum-dapp-whisper-client.meteor.com/";
         whisperTab.menuItem.title = "Whisper Chat";
 */
-        addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "legacy"});        
+        addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "legacy"});
         addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
         addPlugin("./views/whisper.qml", {noAdd: true, close: false, section: "legacy"});
         addPlugin("./views/chain.qml", {noAdd: true, close: false, section: "legacy"});
@@ -126,7 +126,7 @@ ApplicationWindow {
     }
 
     function newBrowserTab(url) {
-        
+
         var urlMatches = url.toString().match(/^[a-z]*\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
         var requestedDomain = urlMatches && urlMatches[1];
 
@@ -138,17 +138,17 @@ ApplicationWindow {
                 var existingDomain = matches && matches[1];
                 if (requestedDomain == existingDomain) {
                     domainAlreadyOpen = true;
-                    
+
                     if (mainSplit.views[i].view.url != url){
                         mainSplit.views[i].view.url = url;
                     }
-                    
+
                     activeView(mainSplit.views[i].view, mainSplit.views[i].menuItem);
                 }
             }
-        }  
+        }
 
-        if (!domainAlreadyOpen) {            
+        if (!domainAlreadyOpen) {
             var window = addPlugin("./views/browser.qml", {noAdd: true, close: true, section: "apps", active: true});
             window.view.url = url;
             window.menuItem.title = "Mist";
@@ -157,7 +157,6 @@ ApplicationWindow {
     }
 
 
-
     menuBar: MenuBar {
         Menu {
             title: "File"
@@ -165,7 +164,7 @@ ApplicationWindow {
                 text: "New tab"
                 shortcut: "Ctrl+t"
                 onTriggered: {
-	            activeView(catalog.view, catalog.menuItem);
+                activeView(catalog.view, catalog.menuItem);
                 }
             }
 
@@ -206,15 +205,6 @@ ApplicationWindow {
                 }
             }
 
-            MenuItem {
-                text: "Run JS file"
-                onTriggered: {
-                    generalFileDialog.show(true, function(path) {
-                        eth.evalJavascriptFile(path)
-                    })
-                }
-            }
-
             MenuItem {
                 text: "Dump state"
                 onTriggered: {
@@ -313,28 +303,28 @@ ApplicationWindow {
              Layout.minimumWidth: 192
              Layout.maximumWidth: 192
 
-            FontLoader { 
+            FontLoader {
                id: sourceSansPro
-               source: "fonts/SourceSansPro-Regular.ttf" 
+               source: "fonts/SourceSansPro-Regular.ttf"
+            }
+            FontLoader {
+               source: "fonts/SourceSansPro-Semibold.ttf"
+            }
+            FontLoader {
+               source: "fonts/SourceSansPro-Bold.ttf"
+            }
+            FontLoader {
+               source: "fonts/SourceSansPro-Black.ttf"
             }
-            FontLoader { 
-               source: "fonts/SourceSansPro-Semibold.ttf" 
-            }            
-            FontLoader { 
-               source: "fonts/SourceSansPro-Bold.ttf" 
-            } 
-            FontLoader { 
-               source: "fonts/SourceSansPro-Black.ttf" 
-            }            
-            FontLoader { 
-               source: "fonts/SourceSansPro-Light.ttf" 
-            }              
-            FontLoader { 
-               source: "fonts/SourceSansPro-ExtraLight.ttf" 
-            }  
-            FontLoader { 
+            FontLoader {
+               source: "fonts/SourceSansPro-Light.ttf"
+            }
+            FontLoader {
+               source: "fonts/SourceSansPro-ExtraLight.ttf"
+            }
+            FontLoader {
                id: simpleLineIcons
-               source: "fonts/Simple-Line-Icons.ttf" 
+               source: "fonts/Simple-Line-Icons.ttf"
             }
 
             Rectangle {
@@ -393,7 +383,7 @@ ApplicationWindow {
 
                      function setSelection(on) {
                          sel.visible = on
-                         
+
                          if (this.closable == true) {
                                 closeIcon.visible = on
                          }
@@ -404,7 +394,7 @@ ApplicationWindow {
                         label.visible = !on
                         buttonLabel.visible = on
                      }
- 
+
                      width: 192
                      height: 55
                      color: "#00000000"
@@ -417,7 +407,7 @@ ApplicationWindow {
                      Rectangle {
                          // New App Button
                          id: newAppButton
-                         visible: false 
+                         visible: false
                          anchors.fill: parent
                          anchors.rightMargin: 8
                          border.width: 0
@@ -504,16 +494,16 @@ ApplicationWindow {
                         id: buttonLabel
                         visible: false
                         text: "GO TO NEW APP"
-                        font.family: sourceSansPro.name 
+                        font.family: sourceSansPro.name
                         font.weight: Font.DemiBold
                         anchors.horizontalCenter: parent.horizontalCenter
                         anchors.verticalCenter: parent.verticalCenter
                         color: "#AAA0A0"
-                     }   
+                     }
 
                     Text {
                          id: label
-                         font.family: sourceSansPro.name 
+                         font.family: sourceSansPro.name
                          font.weight: Font.DemiBold
                          elide: Text.ElideRight
                          x:250
@@ -529,15 +519,15 @@ ApplicationWindow {
                          }
 
 
-                         
-                         
+
+
                      }
 
                      Text {
                          id: secondary
                          //only shows secondary title if there's no badge
                          visible: (badgeContent == "icon" || badgeContent == "number" )? false : true
-                         font.family: sourceSansPro.name 
+                         font.family: sourceSansPro.name
                          font.weight: Font.Light
                          anchors {
                              left: icon.right
@@ -566,8 +556,8 @@ ApplicationWindow {
                          }
 
                         Text {
-                             
-                             font.family: simpleLineIcons.name 
+
+                             font.family: simpleLineIcons.name
                              anchors {
                                  centerIn: parent
                              }
@@ -575,11 +565,11 @@ ApplicationWindow {
                              font.pixelSize: 20
                              text: "\ue082"
                          }
-                     }                     
+                     }
 
                      Rectangle {
                         id: badge
-                        visible: (badgeContent == "icon" || badgeContent == "number" )? true : false 
+                        visible: (badgeContent == "icon" || badgeContent == "number" )? true : false
                         width: 32
                         color: "#05000000"
                         anchors {
@@ -588,11 +578,11 @@ ApplicationWindow {
                             bottom: parent.bottom;
                             rightMargin: 4;
                         }
-                                      
+
                         Text {
                              id: badgeIconLabel
                              visible: (badgeContent == "icon") ? true : false;
-                             font.family: simpleLineIcons.name 
+                             font.family: simpleLineIcons.name
                              anchors {
                                  centerIn: parent
                              }
@@ -600,7 +590,7 @@ ApplicationWindow {
                              color: "#AAA0A0"
                              font.pixelSize: 20
                              text: badgeIcon
-                         }                       
+                         }
 
                         Text {
                              id: badgeNumberLabel
@@ -609,14 +599,14 @@ ApplicationWindow {
                                  centerIn: parent
                              }
                              horizontalAlignment: Text.AlignCenter
-                             font.family: sourceSansPro.name 
+                             font.family: sourceSansPro.name
                              font.weight: Font.Light
                              color: "#AAA0A0"
                              font.pixelSize: 18
                              text: badgeNumber
                          }
                      }
-                     
+
 
 
                      function closeApp() {
@@ -685,7 +675,7 @@ ApplicationWindow {
                  anchors.left: parent.left
                  anchors.right: parent.right
                  spacing: 3
-                
+
 
 
                 ColumnLayout {
@@ -702,7 +692,7 @@ ApplicationWindow {
                      color: "transparent"
                      Text {
                          text: "ETHEREUM"
-                         font.family: sourceSansPro.name 
+                         font.family: sourceSansPro.name
                          font.weight: Font.Regular
                          // anchors.top:  20
                          // anchors.left:  16
@@ -711,10 +701,10 @@ ApplicationWindow {
                             topMargin: 4
                             fill: parent
                         }
-                         // anchors.leftMargin: 16 
-                         // anchors.topMargin: 16 
+                         // anchors.leftMargin: 16
+                         // anchors.topMargin: 16
                         // anchors.verticalCenterOffset: 50
-                         color: "#AAA0A0" 
+                         color: "#AAA0A0"
                      }
                  }
 
@@ -735,7 +725,7 @@ ApplicationWindow {
 
                      Text {
                          text: "APPS"
-                         font.family: sourceSansPro.name 
+                         font.family: sourceSansPro.name
                          font.weight: Font.Regular
                          anchors.fill: parent
                          anchors.leftMargin: 16
@@ -775,7 +765,7 @@ ApplicationWindow {
               anchors.left: menu.right
               anchors.bottom: parent.bottom
               anchors.top: parent.top
-              color: "#00000000"             
+              color: "#00000000"
 
               /*Rectangle {
                   id: urlPane

+ 2 - 23
cmd/mist/gui.go

@@ -25,9 +25,7 @@ import "C"
 import (
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"math/big"
-	"os"
 	"path"
 	"runtime"
 	"sort"
@@ -99,7 +97,7 @@ func NewWindow(ethereum *eth.Ethereum) *Gui {
 	return gui
 }
 
-func (gui *Gui) Start(assetPath string) {
+func (gui *Gui) Start(assetPath, libPath string) {
 	defer gui.txDb.Close()
 
 	guilogger.Infoln("Starting GUI")
@@ -117,7 +115,7 @@ func (gui *Gui) Start(assetPath string) {
 	// Create a new QML engine
 	gui.engine = qml.NewEngine()
 	context := gui.engine.Context()
-	gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
+	gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath, libPath)
 	gui.whisper = qwhisper.New(gui.eth.Whisper())
 
 	// Expose the eth library and the ui library to QML
@@ -292,25 +290,6 @@ func (self *Gui) getObjectByName(objectName string) qml.Object {
 	return self.win.Root().ObjectByName(objectName)
 }
 
-func loadJavascriptAssets(gui *Gui) (jsfiles string) {
-	for _, fn := range []string{"ext/q.js", "ext/eth.js/main.js", "ext/eth.js/qt.js", "ext/setup.js"} {
-		f, err := os.Open(gui.uiLib.AssetPath(fn))
-		if err != nil {
-			fmt.Println(err)
-			continue
-		}
-
-		content, err := ioutil.ReadAll(f)
-		if err != nil {
-			fmt.Println(err)
-			continue
-		}
-		jsfiles += string(content)
-	}
-
-	return
-}
-
 func (gui *Gui) SendCommand(cmd ServEv) {
 	gui.serviceEvents <- cmd
 }

+ 2 - 1
cmd/mist/main.go

@@ -65,6 +65,7 @@ func init() {
 		utils.NodeKeyFileFlag,
 		utils.RPCListenAddrFlag,
 		utils.RPCPortFlag,
+		utils.JSpathFlag,
 	}
 }
 
@@ -111,7 +112,7 @@ func run(ctx *cli.Context) {
 		gui := NewWindow(ethereum)
 		utils.RegisterInterrupt(func(os.Signal) { gui.Stop() })
 		// gui blocks the main thread
-		gui.Start(ctx.GlobalString(assetPathFlag.Name))
+		gui.Start(ctx.GlobalString(assetPathFlag.Name), ctx.GlobalString(utils.JSpathFlag.Name))
 		return nil
 	})
 }

+ 8 - 19
cmd/mist/ui_lib.go

@@ -21,7 +21,6 @@
 package main
 
 import (
-	"fmt"
 	"io/ioutil"
 	"path"
 
@@ -29,7 +28,6 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/event/filter"
-	"github.com/ethereum/go-ethereum/javascript"
 	"github.com/ethereum/go-ethereum/xeth"
 	"github.com/obscuren/qml"
 )
@@ -49,15 +47,19 @@ type UiLib struct {
 	// The main application window
 	win *qml.Window
 
-	jsEngine *javascript.JSRE
-
 	filterCallbacks map[int][]int
 	filterManager   *filter.FilterManager
 }
 
-func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
+func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath, libPath string) *UiLib {
 	x := xeth.New(eth, nil)
-	lib := &UiLib{XEth: x, engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(x), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)}
+	lib := &UiLib{
+		XEth:            x,
+		engine:          engine,
+		eth:             eth,
+		assetPath:       assetPath,
+		filterCallbacks: make(map[int][]int),
+	}
 	lib.filterManager = filter.NewFilterManager(eth.EventMux())
 	go lib.filterManager.Start()
 
@@ -76,19 +78,6 @@ func (self *UiLib) ImportTx(rlpTx string) {
 	}
 }
 
-func (self *UiLib) EvalJavascriptFile(path string) {
-	self.jsEngine.LoadExtFile(path[7:])
-}
-
-func (self *UiLib) EvalJavascriptString(str string) string {
-	value, err := self.jsEngine.Run(str)
-	if err != nil {
-		return err.Error()
-	}
-
-	return fmt.Sprintf("%v", value)
-}
-
 func (ui *UiLib) Muted(content string) {
 	component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
 	if err != nil {

+ 5 - 0
cmd/utils/flags.go

@@ -163,6 +163,11 @@ var (
 		Usage: "Port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
 		Value: "any",
 	}
+	JSpathFlag = cli.StringFlag{
+		Name:  "jspath",
+		Usage: "JS library path to be used with console and js subcommands",
+		Value: ".",
+	}
 )
 
 func GetNAT(ctx *cli.Context) nat.Interface {

+ 2 - 0
common/types.go

@@ -27,6 +27,7 @@ func HexToHash(s string) Hash    { return BytesToHash(FromHex(s)) }
 func (h Hash) Str() string   { return string(h[:]) }
 func (h Hash) Bytes() []byte { return h[:] }
 func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) }
+func (h Hash) Hex() string   { return "0x" + Bytes2Hex(h[:]) }
 
 // Sets the hash to the value of b. If b is larger than len(h) it will panic
 func (h *Hash) SetBytes(b []byte) {
@@ -65,6 +66,7 @@ func (a Address) Str() string   { return string(a[:]) }
 func (a Address) Bytes() []byte { return a[:] }
 func (a Address) Big() *big.Int { return Bytes2Big(a[:]) }
 func (a Address) Hash() Hash    { return BytesToHash(a[:]) }
+func (a Address) Hex() string   { return "0x" + Bytes2Hex(a[:]) }
 
 // Sets the address to the value of b. If b is larger than len(a) it will panic
 func (a *Address) SetBytes(b []byte) {

+ 6 - 0
core/state_transition.go

@@ -57,6 +57,12 @@ type Message interface {
 	Data() []byte
 }
 
+func AddressFromMessage(msg Message) common.Address {
+	from, _ := msg.From()
+
+	return crypto.CreateAddress(from, msg.Nonce())
+}
+
 func MessageCreatesContract(msg Message) bool {
 	return msg.To() == nil
 }

+ 4 - 0
core/types/common.go

@@ -35,3 +35,7 @@ func (b *Bloom) SetBytes(d []byte) {
 func (b Bloom) Big() *big.Int {
 	return common.Bytes2Big(b[:])
 }
+
+func (b Bloom) Bytes() []byte {
+	return b[:]
+}

+ 70 - 8
eth/backend.go

@@ -10,11 +10,11 @@ import (
 	"github.com/ethereum/ethash"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/blockpool"
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/miner"
@@ -219,6 +219,64 @@ func New(config *Config) (*Ethereum, error) {
 	return eth, nil
 }
 
+type NodeInfo struct {
+	Name       string
+	NodeUrl    string
+	NodeID     string
+	IP         string
+	DiscPort   int // UDP listening port for discovery protocol
+	TCPPort    int // TCP listening port for RLPx
+	Td         string
+	ListenAddr string
+}
+
+func (s *Ethereum) NodeInfo() *NodeInfo {
+	node := s.net.Self()
+
+	return &NodeInfo{
+		Name:       s.Name(),
+		NodeUrl:    node.String(),
+		NodeID:     node.ID.String(),
+		IP:         node.IP.String(),
+		DiscPort:   node.DiscPort,
+		TCPPort:    node.TCPPort,
+		ListenAddr: s.net.ListenAddr,
+		Td:         s.ChainManager().Td().String(),
+	}
+}
+
+type PeerInfo struct {
+	ID            string
+	Name          string
+	Caps          string
+	RemoteAddress string
+	LocalAddress  string
+}
+
+func newPeerInfo(peer *p2p.Peer) *PeerInfo {
+	var caps []string
+	for _, cap := range peer.Caps() {
+		caps = append(caps, cap.String())
+	}
+	return &PeerInfo{
+		ID:            peer.ID().String(),
+		Name:          peer.Name(),
+		Caps:          strings.Join(caps, ", "),
+		RemoteAddress: peer.RemoteAddr().String(),
+		LocalAddress:  peer.LocalAddr().String(),
+	}
+}
+
+// PeersInfo returns an array of PeerInfo objects describing connected peers
+func (s *Ethereum) PeersInfo() (peersinfo []*PeerInfo) {
+	for _, peer := range s.net.Peers() {
+		if peer != nil {
+			peersinfo = append(peersinfo, newPeerInfo(peer))
+		}
+	}
+	return
+}
+
 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
 	s.chainManager.ResetWithGenesisBlock(gb)
 	s.pow.UpdateCache(true)
@@ -230,7 +288,7 @@ func (s *Ethereum) StartMining() error {
 		servlogger.Errorf("Cannot start mining without coinbase: %v\n", err)
 		return fmt.Errorf("no coinbase: %v", err)
 	}
-	s.miner.Start(cb)
+	s.miner.Start(common.BytesToAddress(cb))
 	return nil
 }
 
@@ -246,11 +304,12 @@ func (s *Ethereum) TxPool() *core.TxPool                 { return s.txPool }
 func (s *Ethereum) BlockPool() *blockpool.BlockPool      { return s.blockPool }
 func (s *Ethereum) Whisper() *whisper.Whisper            { return s.whisper }
 func (s *Ethereum) EventMux() *event.TypeMux             { return s.eventMux }
-func (s *Ethereum) BlockDb() common.Database            { return s.blockDb }
-func (s *Ethereum) StateDb() common.Database            { return s.stateDb }
-func (s *Ethereum) ExtraDb() common.Database            { return s.extraDb }
+func (s *Ethereum) BlockDb() common.Database             { return s.blockDb }
+func (s *Ethereum) StateDb() common.Database             { return s.stateDb }
+func (s *Ethereum) ExtraDb() common.Database             { return s.extraDb }
 func (s *Ethereum) IsListening() bool                    { return true } // Always listening
 func (s *Ethereum) PeerCount() int                       { return s.net.PeerCount() }
+func (s *Ethereum) PeerInfo() int                        { return s.net.PeerCount() }
 func (s *Ethereum) Peers() []*p2p.Peer                   { return s.net.Peers() }
 func (s *Ethereum) MaxPeers() int                        { return s.net.MaxPeers }
 func (s *Ethereum) Version() string                      { return s.version }
@@ -262,9 +321,11 @@ func (s *Ethereum) Start() error {
 		ProtocolVersion: ProtocolVersion,
 	})
 
-	err := s.net.Start()
-	if err != nil {
-		return err
+	if s.net.MaxPeers > 0 {
+		err := s.net.Start()
+		if err != nil {
+			return err
+		}
 	}
 
 	// Start services
@@ -311,6 +372,7 @@ func (s *Ethereum) Stop() {
 	// Close the database
 	defer s.blockDb.Close()
 	defer s.stateDb.Close()
+	defer s.extraDb.Close()
 
 	s.txSub.Unsubscribe()    // quits txBroadcastLoop
 	s.blockSub.Unsubscribe() // quits blockBroadcastLoop

+ 31 - 30
eth/protocol.go

@@ -1,13 +1,12 @@
 package eth
 
 import (
-	"bytes"
 	"fmt"
 	"math/big"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/errs"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/rlp"
@@ -76,15 +75,15 @@ type txPool interface {
 }
 
 type chainManager interface {
-	GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte)
-	GetBlock(hash []byte) (block *types.Block)
-	Status() (td *big.Int, currentBlock []byte, genesisBlock []byte)
+	GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash)
+	GetBlock(hash common.Hash) (block *types.Block)
+	Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash)
 }
 
 type blockPool interface {
-	AddBlockHashes(next func() ([]byte, bool), peerId string)
+	AddBlockHashes(next func() (common.Hash, bool), peerId string)
 	AddBlock(block *types.Block, peerId string)
-	AddPeer(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool)
+	AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool)
 	RemovePeer(peerId string)
 }
 
@@ -95,7 +94,7 @@ type newBlockMsgData struct {
 }
 
 type getBlockHashesMsgData struct {
-	Hash   []byte
+	Hash   common.Hash
 	Amount uint64
 }
 
@@ -167,7 +166,7 @@ func (self *ethProtocol) handle() error {
 		}
 		for _, tx := range txs {
 			jsonlogger.LogJson(&logger.EthTxReceived{
-				TxHash:   common.Bytes2Hex(tx.Hash()),
+				TxHash:   tx.Hash().Hex(),
 				RemoteId: self.peer.ID().String(),
 			})
 		}
@@ -183,7 +182,7 @@ func (self *ethProtocol) handle() error {
 			request.Amount = maxHashes
 		}
 		hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount)
-		return p2p.EncodeMsg(self.rw, BlockHashesMsg, common.ByteSliceToInterface(hashes)...)
+		return p2p.EncodeMsg(self.rw, BlockHashesMsg, rlp.Flat(hashes))
 
 	case BlockHashesMsg:
 		msgStream := rlp.NewStream(msg.Payload)
@@ -192,14 +191,16 @@ func (self *ethProtocol) handle() error {
 		}
 
 		var i int
-		iter := func() (hash []byte, ok bool) {
-			hash, err := msgStream.Bytes()
+		iter := func() (hash common.Hash, ok bool) {
+			var h common.Hash
+			err := msgStream.Decode(&h)
 			if err == rlp.EOL {
-				return nil, false
+				return common.Hash{}, false
 			} else if err != nil {
 				self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err)
-				return nil, false
+				return common.Hash{}, false
 			}
+
 			i++
 			return hash, true
 		}
@@ -215,14 +216,14 @@ func (self *ethProtocol) handle() error {
 		var i int
 		for {
 			i++
-			var hash []byte
-			if err := msgStream.Decode(&hash); err != nil {
-				if err == rlp.EOL {
-					break
-				} else {
-					return self.protoError(ErrDecode, "msg %v: %v", msg, err)
-				}
+			var hash common.Hash
+			err := msgStream.Decode(&hash)
+			if err == rlp.EOL {
+				break
+			} else {
+				return self.protoError(ErrDecode, "msg %v: %v", msg, err)
 			}
+
 			block := self.chainManager.GetBlock(hash)
 			if block != nil {
 				blocks = append(blocks, block)
@@ -259,10 +260,10 @@ func (self *ethProtocol) handle() error {
 		_, chainHead, _ := self.chainManager.Status()
 
 		jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
-			BlockHash:     common.Bytes2Hex(hash),
+			BlockHash:     hash.Hex(),
 			BlockNumber:   request.Block.Number(), // this surely must be zero
-			ChainHeadHash: common.Bytes2Hex(chainHead),
-			BlockPrevHash: common.Bytes2Hex(request.Block.ParentHash()),
+			ChainHeadHash: chainHead.Hex(),
+			BlockPrevHash: request.Block.ParentHash().Hex(),
 			RemoteId:      self.peer.ID().String(),
 		})
 		// to simplify backend interface adding a new block
@@ -282,8 +283,8 @@ type statusMsgData struct {
 	ProtocolVersion uint32
 	NetworkId       uint32
 	TD              *big.Int
-	CurrentBlock    []byte
-	GenesisBlock    []byte
+	CurrentBlock    common.Hash
+	GenesisBlock    common.Hash
 }
 
 func (self *ethProtocol) statusMsg() p2p.Msg {
@@ -325,7 +326,7 @@ func (self *ethProtocol) handleStatus() error {
 
 	_, _, genesisBlock := self.chainManager.Status()
 
-	if !bytes.Equal(status.GenesisBlock, genesisBlock) {
+	if status.GenesisBlock != genesisBlock {
 		return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
 	}
 
@@ -344,14 +345,14 @@ func (self *ethProtocol) handleStatus() error {
 	return nil
 }
 
-func (self *ethProtocol) requestBlockHashes(from []byte) error {
+func (self *ethProtocol) requestBlockHashes(from common.Hash) error {
 	self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4])
 	return p2p.EncodeMsg(self.rw, GetBlockHashesMsg, interface{}(from), uint64(maxHashes))
 }
 
-func (self *ethProtocol) requestBlocks(hashes [][]byte) error {
+func (self *ethProtocol) requestBlocks(hashes []common.Hash) error {
 	self.peer.Debugf("fetching %v blocks", len(hashes))
-	return p2p.EncodeMsg(self.rw, GetBlocksMsg, common.ByteSliceToInterface(hashes)...)
+	return p2p.EncodeMsg(self.rw, GetBlocksMsg, rlp.Flat(hashes))
 }
 
 func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) {

+ 0 - 103
javascript/javascript_runtime.go

@@ -1,103 +0,0 @@
-package javascript
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path"
-	"path/filepath"
-
-	"github.com/ethereum/go-ethereum/logger"
-	"github.com/ethereum/go-ethereum/xeth"
-	"github.com/obscuren/otto"
-)
-
-var jsrelogger = logger.NewLogger("JSRE")
-
-type JSRE struct {
-	Vm   *otto.Otto
-	xeth *xeth.XEth
-
-	objectCb map[string][]otto.Value
-}
-
-func (jsre *JSRE) LoadExtFile(path string) {
-	result, err := ioutil.ReadFile(path)
-	if err == nil {
-		jsre.Vm.Run(result)
-	} else {
-		jsrelogger.Infoln("Could not load file:", path)
-	}
-}
-
-func (jsre *JSRE) LoadIntFile(file string) {
-	assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
-	jsre.LoadExtFile(path.Join(assetPath, file))
-}
-
-func NewJSRE(xeth *xeth.XEth) *JSRE {
-	re := &JSRE{
-		otto.New(),
-		xeth,
-		make(map[string][]otto.Value),
-	}
-
-	// Init the JS lib
-	re.Vm.Run(jsLib)
-
-	// Load extra javascript files
-	re.LoadIntFile("bignumber.min.js")
-
-	re.Bind("eth", &JSEthereum{re.xeth, re.Vm})
-
-	re.initStdFuncs()
-
-	jsrelogger.Infoln("started")
-
-	return re
-}
-
-func (self *JSRE) Bind(name string, v interface{}) {
-	self.Vm.Set(name, v)
-}
-
-func (self *JSRE) Run(code string) (otto.Value, error) {
-	return self.Vm.Run(code)
-}
-
-func (self *JSRE) initStdFuncs() {
-	t, _ := self.Vm.Get("eth")
-	eth := t.Object()
-	eth.Set("require", self.require)
-}
-
-func (self *JSRE) Require(file string) error {
-	if len(filepath.Ext(file)) == 0 {
-		file += ".js"
-	}
-
-	fh, err := os.Open(file)
-	if err != nil {
-		return err
-	}
-
-	content, _ := ioutil.ReadAll(fh)
-	self.Run("exports = {};(function() {" + string(content) + "})();")
-
-	return nil
-}
-
-func (self *JSRE) require(call otto.FunctionCall) otto.Value {
-	file, err := call.Argument(0).ToString()
-	if err != nil {
-		return otto.UndefinedValue()
-	}
-	if err := self.Require(file); err != nil {
-		fmt.Println("err:", err)
-		return otto.UndefinedValue()
-	}
-
-	t, _ := self.Vm.Get("exports")
-
-	return t
-}

+ 0 - 94
javascript/types.go

@@ -1,94 +0,0 @@
-package javascript
-
-import (
-	"fmt"
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/state"
-	"github.com/ethereum/go-ethereum/xeth"
-	"github.com/obscuren/otto"
-)
-
-type JSStateObject struct {
-	*xeth.Object
-	eth *JSEthereum
-}
-
-func (self *JSStateObject) EachStorage(call otto.FunctionCall) otto.Value {
-	cb := call.Argument(0)
-
-	it := self.Object.Trie().Iterator()
-	for it.Next() {
-		cb.Call(self.eth.toVal(self), self.eth.toVal(common.Bytes2Hex(it.Key)), self.eth.toVal(common.Bytes2Hex(it.Value)))
-	}
-
-	return otto.UndefinedValue()
-}
-
-// The JSEthereum object attempts to wrap the PEthereum object and returns
-// meaningful javascript objects
-type JSBlock struct {
-	*xeth.Block
-	eth *JSEthereum
-}
-
-func (self *JSBlock) GetTransaction(hash string) otto.Value {
-	return self.eth.toVal(self.Block.GetTransaction(hash))
-}
-
-type JSLog struct {
-	Address string   `json:address`
-	Topics  []string `json:topics`
-	Number  int32    `json:number`
-	Data    string   `json:data`
-}
-
-func NewJSLog(log state.Log) JSLog {
-	return JSLog{
-		Address: common.Bytes2Hex(log.Address()),
-		Topics:  nil, //common.Bytes2Hex(log.Address()),
-		Number:  0,
-		Data:    common.Bytes2Hex(log.Data()),
-	}
-}
-
-type JSEthereum struct {
-	*xeth.XEth
-	vm *otto.Otto
-}
-
-func (self *JSEthereum) Block(v interface{}) otto.Value {
-	if number, ok := v.(int64); ok {
-		return self.toVal(&JSBlock{self.XEth.BlockByNumber(number), self})
-	} else if hash, ok := v.(string); ok {
-		return self.toVal(&JSBlock{self.XEth.BlockByHash(hash), self})
-	}
-
-	return otto.UndefinedValue()
-}
-
-func (self *JSEthereum) GetStateObject(addr string) otto.Value {
-	return self.toVal(&JSStateObject{self.XEth.State().SafeGet(addr), self})
-}
-
-func (self *JSEthereum) Transact(fromStr, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
-	r, err := self.XEth.Transact(fromStr, recipient, valueStr, gasStr, gasPriceStr, dataStr)
-	if err != nil {
-		fmt.Println(err)
-
-		return otto.UndefinedValue()
-	}
-
-	return self.toVal(r)
-}
-
-func (self *JSEthereum) toVal(v interface{}) otto.Value {
-	result, err := self.vm.ToValue(v)
-
-	if err != nil {
-		fmt.Println("Value unknown:", err)
-
-		return otto.UndefinedValue()
-	}
-
-	return result
-}

Файловите разлики са ограничени, защото са твърде много
+ 4 - 0
jsre/bignumber_js.go


Файловите разлики са ограничени, защото са твърде много
+ 2 - 0
jsre/ethereum_js.go


+ 115 - 0
jsre/jsre.go

@@ -0,0 +1,115 @@
+package jsre
+
+import (
+	"fmt"
+	"github.com/obscuren/otto"
+	"io/ioutil"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+/*
+JSRE is a generic JS runtime environment embedding the otto JS interpreter.
+It provides some helper functions to
+- load code from files
+- run code snippets
+- require libraries
+- bind native go objects
+*/
+type JSRE struct {
+	assetPath string
+	vm        *otto.Otto
+}
+
+func New(assetPath string) *JSRE {
+	re := &JSRE{
+		assetPath,
+		otto.New(),
+	}
+
+	// load prettyprint func definition
+	re.vm.Run(pp_js)
+	re.vm.Set("loadScript", re.loadScript)
+
+	return re
+}
+
+// Exec(file) loads and runs the contents of a file
+// if a relative path is given, the jsre's assetPath is used
+func (self *JSRE) Exec(file string) error {
+	return self.exec(common.AbsolutePath(self.assetPath, file))
+}
+
+func (self *JSRE) exec(path string) error {
+	code, err := ioutil.ReadFile(path)
+	if err != nil {
+		return err
+	}
+	_, err = self.vm.Run(code)
+	return err
+}
+
+func (self *JSRE) Bind(name string, v interface{}) (err error) {
+	self.vm.Set(name, v)
+	return
+}
+
+func (self *JSRE) Run(code string) (otto.Value, error) {
+	return self.vm.Run(code)
+}
+
+func (self *JSRE) Get(ns string) (otto.Value, error) {
+	return self.vm.Get(ns)
+}
+
+func (self *JSRE) Set(ns string, v interface{}) error {
+	return self.vm.Set(ns, v)
+}
+
+func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
+	file, err := call.Argument(0).ToString()
+	if err != nil {
+		return otto.FalseValue()
+	}
+	if err := self.Exec(file); err != nil {
+		fmt.Println("err:", err)
+		return otto.FalseValue()
+	}
+
+	return otto.TrueValue()
+}
+
+func (self *JSRE) PrettyPrint(v interface{}) (val otto.Value, err error) {
+	var method otto.Value
+	v, err = self.vm.ToValue(v)
+	if err != nil {
+		return
+	}
+	method, err = self.vm.Get("prettyPrint")
+	if err != nil {
+		return
+	}
+	return method.Call(method, v)
+}
+
+func (self *JSRE) ToVal(v interface{}) otto.Value {
+	result, err := self.vm.ToValue(v)
+	if err != nil {
+		fmt.Println("Value unknown:", err)
+		return otto.UndefinedValue()
+	}
+	return result
+}
+
+func (self *JSRE) Eval(code string) (s string, err error) {
+	var val otto.Value
+	val, err = self.Run(code)
+	if err != nil {
+		return
+	}
+	val, err = self.PrettyPrint(val)
+	if err != nil {
+		return
+	}
+	return fmt.Sprintf("%v", val), nil
+}

+ 84 - 0
jsre/jsre_test.go

@@ -0,0 +1,84 @@
+package jsre
+
+import (
+	"github.com/obscuren/otto"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+type testNativeObjectBinding struct {
+	toVal func(interface{}) otto.Value
+}
+
+type msg struct {
+	Msg string
+}
+
+func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value {
+	m, err := call.Argument(0).ToString()
+	if err != nil {
+		return otto.UndefinedValue()
+	}
+	return no.toVal(&msg{m})
+}
+
+func TestExec(t *testing.T) {
+	jsre := New("/tmp")
+
+	common.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`))
+	err := jsre.Exec("test.js")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	val, err := jsre.Run("msg")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	if !val.IsString() {
+		t.Errorf("expected string value, got %v", val)
+	}
+	exp := "testMsg"
+	got, _ := val.ToString()
+	if exp != got {
+		t.Errorf("expected '%v', got '%v'", exp, got)
+	}
+}
+
+func TestBind(t *testing.T) {
+	jsre := New("/tmp")
+
+	jsre.Bind("no", &testNativeObjectBinding{jsre.ToVal})
+
+	val, err := jsre.Run(`no.testMethod("testMsg")`)
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	pp, err := jsre.PrettyPrint(val)
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	t.Logf("no: %v", pp)
+}
+
+func TestLoadScript(t *testing.T) {
+	jsre := New("/tmp")
+
+	common.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`))
+	_, err := jsre.Run(`loadScript("test.js")`)
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	val, err := jsre.Run("msg")
+	if err != nil {
+		t.Errorf("expected no error, got %v", err)
+	}
+	if !val.IsString() {
+		t.Errorf("expected string value, got %v", val)
+	}
+	exp := "testMsg"
+	got, _ := val.ToString()
+	if exp != got {
+		t.Errorf("expected '%v', got '%v'", exp, got)
+	}
+}

+ 3 - 3
javascript/js_lib.go → jsre/pp_js.go

@@ -1,6 +1,6 @@
-package javascript
+package jsre
 
-const jsLib = `
+const pp_js = `
 function pp(object) {
     var str = "";
 
@@ -34,7 +34,7 @@ function pp(object) {
     } else if(typeof(object) === "function") {
 	str += "\033[35m[Function]";
     } else {
-        str += object;                    
+        str += object;
     }
 
     str += "\033[0m";

+ 2 - 1
miner/miner.go

@@ -4,6 +4,7 @@ import (
 	"math/big"
 
 	"github.com/ethereum/ethash"
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/pow"
@@ -32,7 +33,7 @@ func (self *Miner) Mining() bool {
 	return self.mining
 }
 
-func (self *Miner) Start(coinbase []byte) {
+func (self *Miner) Start(coinbase common.Address) {
 	self.mining = true
 	self.worker = newWorker(coinbase, self.eth)
 	self.worker.register(NewCpuMiner(0, self.pow))

+ 14 - 13
miner/worker.go

@@ -7,9 +7,9 @@ import (
 	"sync"
 	"time"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/pow"
@@ -39,7 +39,7 @@ func env(block *types.Block, eth core.Backend) *environment {
 		coinbase:     state.GetOrNewStateObject(block.Coinbase()),
 	}
 	for _, ancestor := range eth.ChainManager().GetAncestors(block, 7) {
-		env.ancestors.Add(string(ancestor.Hash()))
+		env.ancestors.Add(ancestor.Hash())
 	}
 
 	return env
@@ -71,14 +71,14 @@ type worker struct {
 	eth      core.Backend
 	chain    *core.ChainManager
 	proc     *core.BlockProcessor
-	coinbase []byte
+	coinbase common.Address
 
 	current *environment
 
 	mining bool
 }
 
-func newWorker(coinbase []byte, eth core.Backend) *worker {
+func newWorker(coinbase common.Address, eth core.Backend) *worker {
 	return &worker{
 		eth:      eth,
 		mux:      eth.EventMux(),
@@ -152,13 +152,13 @@ func (self *worker) wait() {
 			block := self.current.block
 			if block.Number().Uint64() == work.Number && block.Nonce() == 0 {
 				self.current.block.SetNonce(work.Nonce)
-				self.current.block.Header().MixDigest = work.MixDigest
+				self.current.block.Header().MixDigest = common.BytesToHash(work.MixDigest)
 
 				jsonlogger.LogJson(&logger.EthMinerNewBlock{
-					BlockHash:     common.Bytes2Hex(block.Hash()),
+					BlockHash:     block.Hash().Hex(),
 					BlockNumber:   block.Number(),
-					ChainHeadHash: common.Bytes2Hex(block.ParentHeaderHash),
-					BlockPrevHash: common.Bytes2Hex(block.ParentHeaderHash),
+					ChainHeadHash: block.ParentHeaderHash.Hex(),
+					BlockPrevHash: block.ParentHeaderHash.Hex(),
 				})
 
 				if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil {
@@ -208,9 +208,10 @@ gasLimit:
 			fallthrough
 		case core.IsInvalidTxErr(err):
 			// Remove invalid transactions
-			self.chain.TxState().RemoveNonce(tx.From(), tx.Nonce())
+			from, _ := tx.From()
+			self.chain.TxState().RemoveNonce(from, tx.Nonce())
 			remove = append(remove, tx)
-			minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash()[:4])
+			minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash().Bytes()[:4])
 		case state.IsGasLimitErr(err):
 			minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i)
 			// Break on gas limit
@@ -232,13 +233,13 @@ var (
 )
 
 func (self *worker) commitUncle(uncle *types.Header) error {
-	if self.current.uncles.Has(string(uncle.Hash())) {
+	if self.current.uncles.Has(uncle.Hash()) {
 		// Error not unique
 		return core.UncleError("Uncle not unique")
 	}
-	self.current.uncles.Add(string(uncle.Hash()))
+	self.current.uncles.Add(uncle.Hash())
 
-	if !self.current.ancestors.Has(string(uncle.ParentHash)) {
+	if !self.current.ancestors.Has(uncle.ParentHash) {
 		return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
 	}
 

+ 3 - 3
p2p/discover/table.go

@@ -51,9 +51,9 @@ func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr) *Table {
 	return tab
 }
 
-// Self returns the local node ID.
-func (tab *Table) Self() NodeID {
-	return tab.self.ID
+// Self returns the local node.
+func (tab *Table) Self() *Node {
+	return tab.self
 }
 
 // Close terminates the network listener.

+ 9 - 5
p2p/server.go

@@ -180,7 +180,7 @@ func (srv *Server) Start() (err error) {
 	srv.ntab = ntab
 
 	// handshake
-	srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self()}
+	srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self().ID}
 	for _, p := range srv.Protocols {
 		srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
 	}
@@ -298,7 +298,7 @@ func (srv *Server) dialLoop() {
 			srv.lock.Lock()
 			_, isconnected := srv.peers[dest.ID]
 			srv.lock.Unlock()
-			if isconnected || dialing[dest.ID] || dest.ID == srv.ntab.Self() {
+			if isconnected || dialing[dest.ID] || dest.ID == srv.Self().ID {
 				continue
 			}
 
@@ -332,12 +332,16 @@ func (srv *Server) dialNode(dest *discover.Node) {
 	srv.startPeer(conn, dest)
 }
 
+func (srv *Server) Self() *discover.Node {
+	return srv.ntab.Self()
+}
+
 func (srv *Server) findPeers() {
-	far := srv.ntab.Self()
+	far := srv.Self().ID
 	for i := range far {
 		far[i] = ^far[i]
 	}
-	closeToSelf := srv.ntab.Lookup(srv.ntab.Self())
+	closeToSelf := srv.ntab.Lookup(srv.Self().ID)
 	farFromSelf := srv.ntab.Lookup(far)
 
 	for i := 0; i < len(closeToSelf) || i < len(farFromSelf); i++ {
@@ -402,7 +406,7 @@ func (srv *Server) addPeer(id discover.NodeID, p *Peer) (bool, DiscReason) {
 		return false, DiscTooManyPeers
 	case srv.peers[id] != nil:
 		return false, DiscAlreadyConnected
-	case id == srv.ntab.Self():
+	case id == srv.Self().ID:
 		return false, DiscSelf
 	}
 	srv.peers[id] = p

+ 21 - 11
rpc/api.go

@@ -9,11 +9,11 @@ import (
 	"sync"
 	"time"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event/filter"
 	"github.com/ethereum/go-ethereum/state"
@@ -371,6 +371,11 @@ func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
 	return nil
 }
 
+// func (p *EthereumApi) RemoveWhisperIdentity(args *WhisperIdentityArgs, reply *interface{}) error {
+// 	*reply = p.xeth().Whisper().RemoveIdentity(args.Identity)
+// 	return nil
+// }
+
 func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error {
 	var id int
 	opts := new(xeth.Options)
@@ -663,7 +668,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return NewValidationError("Index", "does not exist")
 		}
 
-		uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
+		uncle, err := p.GetBlockByHash(v.Uncles[args.Index].Hex(), false)
 		if err != nil {
 			return err
 		}
@@ -682,7 +687,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return NewValidationError("Index", "does not exist")
 		}
 
-		uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
+		uncle, err := p.GetBlockByHash(v.Uncles[args.Index].Hex(), false)
 		if err != nil {
 			return err
 		}
@@ -751,6 +756,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		return p.WhisperPost(args, reply)
 	case "shh_newIdentity":
 		return p.NewWhisperIdentity(reply)
+	// case "shh_removeIdentity":
+	// 	args := new(WhisperIdentityArgs)
+	// 	if err := json.Unmarshal(req.Params, &args); err != nil {
+	// 		return err
+	// 	}
+	// 	return p.RemoveWhisperIdentity(args, reply)
 	case "shh_hasIdentity":
 		args := new(WhisperIdentityArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
@@ -821,12 +832,12 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions {
 
 	// Convert optional address slice/string to byte slice
 	if str, ok := options.Address.(string); ok {
-		opts.Address = [][]byte{common.FromHex(str)}
+		opts.Address = []common.Address{common.HexToAddress(str)}
 	} else if slice, ok := options.Address.([]interface{}); ok {
-		bslice := make([][]byte, len(slice))
+		bslice := make([]common.Address, len(slice))
 		for i, addr := range slice {
 			if saddr, ok := addr.(string); ok {
-				bslice[i] = common.FromHex(saddr)
+				bslice[i] = common.HexToAddress(saddr)
 			}
 		}
 		opts.Address = bslice
@@ -835,16 +846,15 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions {
 	opts.Earliest = options.Earliest
 	opts.Latest = options.Latest
 
-	topics := make([][][]byte, len(options.Topics))
+	topics := make([][]common.Hash, len(options.Topics))
 	for i, topicDat := range options.Topics {
 		if slice, ok := topicDat.([]interface{}); ok {
-			topics[i] = make([][]byte, len(slice))
+			topics[i] = make([]common.Hash, len(slice))
 			for j, topic := range slice {
-				topics[i][j] = common.FromHex(topic.(string))
+				topics[i][j] = common.HexToHash(topic.(string))
 			}
 		} else if str, ok := topicDat.(string); ok {
-			topics[i] = make([][]byte, 1)
-			topics[i][0] = common.FromHex(str)
+			topics[i] = []common.Hash{common.HexToHash(str)}
 		}
 	}
 	opts.Topics = topics

+ 28 - 40
rpc/args.go

@@ -331,42 +331,6 @@ func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
 	return nil
 }
 
-// type FilterArgs struct {
-// 	FromBlock uint64
-// 	ToBlock   uint64
-// 	Limit     uint64
-// 	Offset    uint64
-// 	Address   string
-// 	Topics    []string
-// }
-
-// func (args *FilterArgs) UnmarshalJSON(b []byte) (err error) {
-// 	var obj []struct {
-// 		FromBlock string   `json:"fromBlock"`
-// 		ToBlock   string   `json:"toBlock"`
-// 		Limit     string   `json:"limit"`
-// 		Offset    string   `json:"offset"`
-// 		Address   string   `json:"address"`
-// 		Topics    []string `json:"topics"`
-// 	}
-
-// 	if err = json.Unmarshal(b, &obj); err != nil {
-// 		return errDecodeArgs
-// 	}
-
-// 	if len(obj) < 1 {
-// 		return errArguments
-// 	}
-// 	args.FromBlock = uint64(common.Big(obj[0].FromBlock).Int64())
-// 	args.ToBlock = uint64(common.Big(obj[0].ToBlock).Int64())
-// 	args.Limit = uint64(common.Big(obj[0].Limit).Int64())
-// 	args.Offset = uint64(common.Big(obj[0].Offset).Int64())
-// 	args.Address = obj[0].Address
-// 	args.Topics = obj[0].Topics
-
-// 	return nil
-// }
-
 type FilterOptions struct {
 	Earliest int64
 	Latest   int64
@@ -378,8 +342,8 @@ type FilterOptions struct {
 
 func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
 	var obj []struct {
-		FromBlock string        `json:"fromBlock"`
-		ToBlock   string        `json:"toBlock"`
+		FromBlock interface{}   `json:"fromBlock"`
+		ToBlock   interface{}   `json:"toBlock"`
 		Limit     string        `json:"limit"`
 		Offset    string        `json:"offset"`
 		Address   string        `json:"address"`
@@ -394,8 +358,32 @@ func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
 		return NewInsufficientParamsError(len(obj), 1)
 	}
 
-	args.Earliest = int64(common.Big(obj[0].FromBlock).Int64())
-	args.Latest = int64(common.Big(obj[0].ToBlock).Int64())
+	fromstr, ok := obj[0].FromBlock.(string)
+	if !ok {
+		return NewDecodeParamError("FromBlock is not a string")
+	}
+
+	switch fromstr {
+	case "latest":
+		args.Earliest = 0
+	default:
+		args.Earliest = int64(common.Big(obj[0].FromBlock.(string)).Int64())
+	}
+
+	tostr, ok := obj[0].ToBlock.(string)
+	if !ok {
+		return NewDecodeParamError("ToBlock is not a string")
+	}
+
+	switch tostr {
+	case "latest":
+		args.Latest = 0
+	case "pending":
+		args.Latest = -1
+	default:
+		args.Latest = int64(common.Big(obj[0].ToBlock.(string)).Int64())
+	}
+
 	args.Max = int(common.Big(obj[0].Limit).Int64())
 	args.Skip = int(common.Big(obj[0].Offset).Int64())
 	args.Address = obj[0].Address

+ 120 - 0
rpc/args_test.go

@@ -74,6 +74,16 @@ func TestGetBlockByHashArgs(t *testing.T) {
 	}
 }
 
+func TestGetBlockByHashEmpty(t *testing.T) {
+	input := `[]`
+
+	args := new(GetBlockByHashArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestGetBlockByNumberArgs(t *testing.T) {
 	input := `["0x1b4", false]`
 	expected := new(GetBlockByNumberArgs)
@@ -94,6 +104,16 @@ func TestGetBlockByNumberArgs(t *testing.T) {
 	}
 }
 
+func TestGetBlockByNumberEmpty(t *testing.T) {
+	input := `[]`
+
+	args := new(GetBlockByNumberArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestNewTxArgs(t *testing.T) {
 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
@@ -139,6 +159,16 @@ func TestNewTxArgs(t *testing.T) {
 	}
 }
 
+func TestNewTxArgsEmpty(t *testing.T) {
+	input := `[]`
+
+	args := new(NewTxArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestGetStorageArgs(t *testing.T) {
 	input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
 	expected := new(GetStorageArgs)
@@ -163,6 +193,16 @@ func TestGetStorageArgs(t *testing.T) {
 	}
 }
 
+func TestGetStorageEmptyArgs(t *testing.T) {
+	input := `[]`
+
+	args := new(GetStorageArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestGetStorageAtArgs(t *testing.T) {
 	input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"]`
 	expected := new(GetStorageAtArgs)
@@ -192,6 +232,16 @@ func TestGetStorageAtArgs(t *testing.T) {
 	}
 }
 
+func TestGetStorageAtEmptyArgs(t *testing.T) {
+	input := `[]`
+
+	args := new(GetStorageAtArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestGetTxCountArgs(t *testing.T) {
 	input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
 	expected := new(GetTxCountArgs)
@@ -216,6 +266,16 @@ func TestGetTxCountArgs(t *testing.T) {
 	}
 }
 
+func TestGetTxCountEmptyArgs(t *testing.T) {
+	input := `[]`
+
+	args := new(GetTxCountArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestGetDataArgs(t *testing.T) {
 	input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", "latest"]`
 	expected := new(GetDataArgs)
@@ -240,6 +300,16 @@ func TestGetDataArgs(t *testing.T) {
 	}
 }
 
+func TestGetDataEmptyArgs(t *testing.T) {
+	input := `[]`
+
+	args := new(GetDataArgs)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestFilterOptions(t *testing.T) {
 	input := `[{
   "fromBlock": "0x1",
@@ -286,6 +356,56 @@ func TestFilterOptions(t *testing.T) {
 	// }
 }
 
+func TestFilterOptionsWords(t *testing.T) {
+	input := `[{
+  "fromBlock": "latest",
+  "toBlock": "pending"
+  }]`
+	expected := new(FilterOptions)
+	expected.Earliest = 0
+	expected.Latest = -1
+
+	args := new(FilterOptions)
+	if err := json.Unmarshal([]byte(input), &args); err != nil {
+		t.Error(err)
+	}
+
+	if expected.Earliest != args.Earliest {
+		t.Errorf("Earliest shoud be %#v but is %#v", expected.Earliest, args.Earliest)
+	}
+
+	if expected.Latest != args.Latest {
+		t.Errorf("Latest shoud be %#v but is %#v", expected.Latest, args.Latest)
+	}
+}
+
+func TestFilterOptionsNums(t *testing.T) {
+	input := `[{
+  "fromBlock": 2,
+  "toBlock": 3
+  }]`
+
+	args := new(FilterOptions)
+	err := json.Unmarshal([]byte(input), &args)
+	switch err.(type) {
+	case *DecodeParamError:
+		break
+	default:
+		t.Errorf("Should have *DecodeParamError but instead have %T", err)
+	}
+
+}
+
+func TestFilterOptionsEmptyArgs(t *testing.T) {
+	input := `[]`
+
+	args := new(FilterOptions)
+	err := json.Unmarshal([]byte(input), &args)
+	if err == nil {
+		t.Error("Expected error but didn't get one")
+	}
+}
+
 func TestDbArgs(t *testing.T) {
 	input := `["0x74657374","0x6b6579","0x6d79537472696e67"]`
 	expected := new(DbArgs)

+ 7 - 7
rpc/http.go

@@ -26,7 +26,7 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 
 		if req.ContentLength > maxSizeReqLength {
 			jsonerr := &RpcErrorObject{-32700, "Request too large"}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
+			json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
 			return
 		}
 
@@ -36,11 +36,11 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 			break
 		case *DecodeParamError, *InsufficientParamsError, *ValidationError:
 			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
+			json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
 			return
 		default:
 			jsonerr := &RpcErrorObject{-32700, "Could not parse request"}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
+			json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
 			return
 		}
 
@@ -51,19 +51,19 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 			break
 		case *NotImplementedError:
 			jsonerr := &RpcErrorObject{-32601, reserr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
+			json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Error: jsonerr})
 			return
 		case *DecodeParamError, *InsufficientParamsError, *ValidationError:
 			jsonerr := &RpcErrorObject{-32602, reserr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
+			json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Error: jsonerr})
 			return
 		default:
 			jsonerr := &RpcErrorObject{-32603, reserr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
+			json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Error: jsonerr})
 			return
 		}
 
 		rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
-		json.Send(w, &RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response})
+		json.Send(w, &RpcSuccessResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Result: response})
 	})
 }

+ 43 - 0
rpc/jeth.go

@@ -0,0 +1,43 @@
+package rpc
+
+import (
+	"encoding/json"
+	// "fmt"
+	"github.com/obscuren/otto"
+)
+
+type Jeth struct {
+	ethApi *EthereumApi
+	toVal  func(interface{}) otto.Value
+}
+
+func NewJeth(ethApi *EthereumApi, toVal func(interface{}) otto.Value) *Jeth {
+	return &Jeth{ethApi, toVal}
+}
+
+func (self *Jeth) err(code int, msg string, id interface{}) otto.Value {
+	rpcerr := &RpcErrorObject{code, msg}
+	rpcresponse := &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: rpcerr}
+	return self.toVal(rpcresponse)
+}
+
+func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
+	reqif, err := call.Argument(0).Export()
+	if err != nil {
+		return self.err(-32700, err.Error(), nil)
+	}
+
+	jsonreq, err := json.Marshal(reqif)
+
+	var req RpcRequest
+	err = json.Unmarshal(jsonreq, &req)
+
+	var respif interface{}
+	err = self.ethApi.GetRequestReply(&req, &respif)
+	if err != nil {
+		return self.err(-32603, err.Error(), req.Id)
+	}
+	rpcresponse := &RpcSuccessResponse{Jsonrpc: jsonrpcver, Id: req.Id, Result: respif}
+	response = self.toVal(rpcresponse)
+	return
+}

+ 6 - 6
rpc/messages.go

@@ -83,21 +83,21 @@ func NewValidationError(param string, msg string) error {
 }
 
 type RpcRequest struct {
-	ID      interface{}     `json:"id"`
-	JsonRpc string          `json:"jsonrpc"`
+	Id      interface{}     `json:"id"`
+	Jsonrpc string          `json:"jsonrpc"`
 	Method  string          `json:"method"`
 	Params  json.RawMessage `json:"params"`
 }
 
 type RpcSuccessResponse struct {
-	ID      interface{} `json:"id"`
-	JsonRpc string      `json:"jsonrpc"`
+	Id      interface{} `json:"id"`
+	Jsonrpc string      `json:"jsonrpc"`
 	Result  interface{} `json:"result"`
 }
 
 type RpcErrorResponse struct {
-	ID      interface{}     `json:"id"`
-	JsonRpc string          `json:"jsonrpc"`
+	Id      interface{}     `json:"id"`
+	Jsonrpc string          `json:"jsonrpc"`
 	Error   *RpcErrorObject `json:"error"`
 }
 

+ 41 - 36
rpc/responses.go

@@ -5,6 +5,7 @@ import (
 	// "fmt"
 	"math/big"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
 )
 
@@ -12,14 +13,14 @@ type BlockRes struct {
 	fullTx bool
 
 	BlockNumber     int64             `json:"number"`
-	BlockHash       []byte            `json:"hash"`
-	ParentHash      []byte            `json:"parentHash"`
-	Nonce           []byte            `json:"nonce"`
-	Sha3Uncles      []byte            `json:"sha3Uncles"`
-	LogsBloom       []byte            `json:"logsBloom"`
-	TransactionRoot []byte            `json:"transactionRoot"`
-	StateRoot       []byte            `json:"stateRoot"`
-	Miner           []byte            `json:"miner"`
+	BlockHash       common.Hash       `json:"hash"`
+	ParentHash      common.Hash       `json:"parentHash"`
+	Nonce           [8]byte           `json:"nonce"`
+	Sha3Uncles      common.Hash       `json:"sha3Uncles"`
+	LogsBloom       types.Bloom       `json:"logsBloom"`
+	TransactionRoot common.Hash       `json:"transactionRoot"`
+	StateRoot       common.Hash       `json:"stateRoot"`
+	Miner           common.Address    `json:"miner"`
 	Difficulty      int64             `json:"difficulty"`
 	TotalDifficulty int64             `json:"totalDifficulty"`
 	Size            int64             `json:"size"`
@@ -29,7 +30,7 @@ type BlockRes struct {
 	GasUsed         int64             `json:"gasUsed"`
 	UnixTimestamp   int64             `json:"timestamp"`
 	Transactions    []*TransactionRes `json:"transactions"`
-	Uncles          [][]byte          `json:"uncles"`
+	Uncles          []common.Hash     `json:"uncles"`
 }
 
 func (b *BlockRes) MarshalJSON() ([]byte, error) {
@@ -57,14 +58,14 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
 
 	// convert strict types to hexified strings
 	ext.BlockNumber = toHex(big.NewInt(b.BlockNumber).Bytes())
-	ext.BlockHash = toHex(b.BlockHash)
-	ext.ParentHash = toHex(b.ParentHash)
-	ext.Nonce = toHex(b.Nonce)
-	ext.Sha3Uncles = toHex(b.Sha3Uncles)
-	ext.LogsBloom = toHex(b.LogsBloom)
-	ext.TransactionRoot = toHex(b.TransactionRoot)
-	ext.StateRoot = toHex(b.StateRoot)
-	ext.Miner = toHex(b.Miner)
+	ext.BlockHash = b.BlockHash.Hex()
+	ext.ParentHash = b.ParentHash.Hex()
+	ext.Nonce = toHex(b.Nonce[:])
+	ext.Sha3Uncles = b.Sha3Uncles.Hex()
+	ext.LogsBloom = toHex(b.LogsBloom[:])
+	ext.TransactionRoot = b.TransactionRoot.Hex()
+	ext.StateRoot = b.StateRoot.Hex()
+	ext.Miner = b.Miner.Hex()
 	ext.Difficulty = toHex(big.NewInt(b.Difficulty).Bytes())
 	ext.TotalDifficulty = toHex(big.NewInt(b.TotalDifficulty).Bytes())
 	ext.Size = toHex(big.NewInt(b.Size).Bytes())
@@ -80,12 +81,12 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
 		}
 	} else {
 		for i, tx := range b.Transactions {
-			ext.Transactions[i] = toHex(tx.Hash)
+			ext.Transactions[i] = tx.Hash.Hex()
 		}
 	}
 	ext.Uncles = make([]string, len(b.Uncles))
 	for i, v := range b.Uncles {
-		ext.Uncles[i] = toHex(v)
+		ext.Uncles[i] = v.Hex()
 	}
 
 	return json.Marshal(ext)
@@ -124,7 +125,7 @@ func NewBlockRes(block *types.Block) *BlockRes {
 		v.TxIndex = int64(i)
 		res.Transactions[i] = v
 	}
-	res.Uncles = make([][]byte, len(block.Uncles()))
+	res.Uncles = make([]common.Hash, len(block.Uncles()))
 	for i, uncle := range block.Uncles() {
 		res.Uncles[i] = uncle.Hash()
 	}
@@ -132,17 +133,17 @@ func NewBlockRes(block *types.Block) *BlockRes {
 }
 
 type TransactionRes struct {
-	Hash        []byte `json:"hash"`
-	Nonce       int64  `json:"nonce"`
-	BlockHash   []byte `json:"blockHash,omitempty"`
-	BlockNumber int64  `json:"blockNumber,omitempty"`
-	TxIndex     int64  `json:"transactionIndex,omitempty"`
-	From        []byte `json:"from"`
-	To          []byte `json:"to"`
-	Value       int64  `json:"value"`
-	Gas         int64  `json:"gas"`
-	GasPrice    int64  `json:"gasPrice"`
-	Input       []byte `json:"input"`
+	Hash        common.Hash     `json:"hash"`
+	Nonce       int64           `json:"nonce"`
+	BlockHash   common.Hash     `json:"blockHash,omitempty"`
+	BlockNumber int64           `json:"blockNumber,omitempty"`
+	TxIndex     int64           `json:"transactionIndex,omitempty"`
+	From        common.Address  `json:"from"`
+	To          *common.Address `json:"to"`
+	Value       int64           `json:"value"`
+	Gas         int64           `json:"gas"`
+	GasPrice    int64           `json:"gasPrice"`
+	Input       []byte          `json:"input"`
 }
 
 func (t *TransactionRes) MarshalJSON() ([]byte, error) {
@@ -160,13 +161,17 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
 		Input       string `json:"input"`
 	}
 
-	ext.Hash = toHex(t.Hash)
+	ext.Hash = t.Hash.Hex()
 	ext.Nonce = toHex(big.NewInt(t.Nonce).Bytes())
-	ext.BlockHash = toHex(t.BlockHash)
+	ext.BlockHash = t.BlockHash.Hex()
 	ext.BlockNumber = toHex(big.NewInt(t.BlockNumber).Bytes())
 	ext.TxIndex = toHex(big.NewInt(t.TxIndex).Bytes())
-	ext.From = toHex(t.From)
-	ext.To = toHex(t.To)
+	ext.From = t.From.Hex()
+	if t.To == nil {
+		ext.To = "0x00"
+	} else {
+		ext.To = t.To.Hex()
+	}
 	ext.Value = toHex(big.NewInt(t.Value).Bytes())
 	ext.Gas = toHex(big.NewInt(t.Gas).Bytes())
 	ext.GasPrice = toHex(big.NewInt(t.GasPrice).Bytes())
@@ -179,7 +184,7 @@ func NewTransactionRes(tx *types.Transaction) *TransactionRes {
 	var v = new(TransactionRes)
 	v.Hash = tx.Hash()
 	v.Nonce = int64(tx.Nonce())
-	v.From = tx.From()
+	v.From, _ = tx.From()
 	v.To = tx.To()
 	v.Value = tx.Value().Int64()
 	v.Gas = tx.Gas().Int64()

+ 7 - 2
rpc/util.go

@@ -45,6 +45,11 @@ func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error
 		return NewDecodeParamError(err.Error())
 	}
 
+	// Hrm... Occurs when no params
+	if len(data) == 0 {
+		return NewDecodeParamError("No data")
+	}
+
 	// Number index determines the index in the array for a possible block number
 	numberIndex := 0
 
@@ -150,11 +155,11 @@ func toLogs(logs state.Logs) (ls []Log) {
 	for i, log := range logs {
 		var l Log
 		l.Topic = make([]string, len(log.Topics()))
-		l.Address = toHex(log.Address())
+		l.Address = log.Address().Hex()
 		l.Data = toHex(log.Data())
 		l.Number = log.Number()
 		for j, topic := range log.Topics() {
-			l.Topic[j] = toHex(topic)
+			l.Topic[j] = topic.Hex()
 		}
 		ls[i] = l
 	}

+ 4 - 5
tests/blocktest.go

@@ -13,7 +13,6 @@ import (
 	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/state"
@@ -99,7 +98,7 @@ func LoadBlockTests(file string) (map[string]*BlockTest, error) {
 // InsertPreState populates the given database with the genesis
 // accounts defined by the test.
 func (t *BlockTest) InsertPreState(db common.Database) error {
-	statedb := state.New(nil, db)
+	statedb := state.New(common.Hash{}, db)
 	for addrString, acct := range t.preAccounts {
 		// XXX: is is worth it checking for errors here?
 		//addr, _ := hex.DecodeString(addrString)
@@ -120,7 +119,7 @@ func (t *BlockTest) InsertPreState(db common.Database) error {
 	// sync trie to disk
 	statedb.Sync()
 
-	if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root()) {
+	if t.Genesis.Root() != statedb.Root() {
 		return errors.New("computed state root does not match genesis block")
 	}
 	return nil
@@ -212,12 +211,12 @@ func mustConvertAddress(in string) common.Address {
 	return common.BytesToAddress(out)
 }
 
-func mustConvertBloom(in string) core.Bloom {
+func mustConvertBloom(in string) types.Bloom {
 	out, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
 	if err != nil {
 		panic(fmt.Errorf("invalid hex: %q", in))
 	}
-	return core.BytesToBloom(out)
+	return types.BytesToBloom(out)
 }
 
 func mustConvertBigInt10(in string) *big.Int {

+ 9 - 0
whisper/whisper.go

@@ -116,6 +116,15 @@ func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey {
 	return self.keys[string(crypto.FromECDSAPub(key))]
 }
 
+// func (self *Whisper) RemoveIdentity(key *ecdsa.PublicKey) bool {
+// 	k := string(crypto.FromECDSAPub(key))
+// 	if _, ok := self.keys[k]; ok {
+// 		delete(self.keys, k)
+// 		return true
+// 	}
+// 	return false
+// }
+
 func (self *Whisper) Watch(opts Filter) int {
 	return self.filters.Install(filter.Generic{
 		Str1: string(crypto.FromECDSAPub(opts.To)),

+ 3 - 3
xeth/state.go

@@ -19,7 +19,7 @@ func (self *State) State() *state.StateDB {
 }
 
 func (self *State) Get(addr string) *Object {
-	return &Object{self.state.GetStateObject(common.FromHex(addr))}
+	return &Object{self.state.GetStateObject(common.HexToAddress(addr))}
 }
 
 func (self *State) SafeGet(addr string) *Object {
@@ -27,9 +27,9 @@ func (self *State) SafeGet(addr string) *Object {
 }
 
 func (self *State) safeGet(addr string) *state.StateObject {
-	object := self.state.GetStateObject(common.FromHex(addr))
+	object := self.state.GetStateObject(common.HexToAddress(addr))
 	if object == nil {
-		object = state.NewStateObject(common.FromHex(addr), self.xeth.eth.StateDb())
+		object = state.NewStateObject(common.HexToAddress(addr), self.xeth.eth.StateDb())
 	}
 
 	return object

+ 22 - 22
xeth/types.go

@@ -5,10 +5,10 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/state"
@@ -59,19 +59,19 @@ func (self *Object) Storage() (storage map[string]string) {
 type Block struct {
 	//Transactions string `json:"transactions"`
 	ref          *types.Block
-	Size         string        `json:"size"`
-	Number       int           `json:"number"`
-	Hash         string        `json:"hash"`
+	Size         string       `json:"size"`
+	Number       int          `json:"number"`
+	Hash         string       `json:"hash"`
 	Transactions *common.List `json:"transactions"`
 	Uncles       *common.List `json:"uncles"`
-	Time         int64         `json:"time"`
-	Coinbase     string        `json:"coinbase"`
-	Name         string        `json:"name"`
-	GasLimit     string        `json:"gasLimit"`
-	GasUsed      string        `json:"gasUsed"`
-	PrevHash     string        `json:"prevHash"`
-	Bloom        string        `json:"bloom"`
-	Raw          string        `json:"raw"`
+	Time         int64        `json:"time"`
+	Coinbase     string       `json:"coinbase"`
+	Name         string       `json:"name"`
+	GasLimit     string       `json:"gasLimit"`
+	GasUsed      string       `json:"gasUsed"`
+	PrevHash     string       `json:"prevHash"`
+	Bloom        string       `json:"bloom"`
+	Raw          string       `json:"raw"`
 }
 
 // Creates a new QML Block from a chain block
@@ -95,12 +95,12 @@ func NewBlock(block *types.Block) *Block {
 	return &Block{
 		ref: block, Size: block.Size().String(),
 		Number: int(block.NumberU64()), GasUsed: block.GasUsed().String(),
-		GasLimit: block.GasLimit().String(), Hash: toHex(block.Hash()),
+		GasLimit: block.GasLimit().String(), Hash: toHex(block.Hash().Bytes()),
 		Transactions: txlist, Uncles: ulist,
 		Time:     block.Time(),
-		Coinbase: toHex(block.Coinbase()),
-		PrevHash: toHex(block.ParentHash()),
-		Bloom:    toHex(block.Bloom()),
+		Coinbase: toHex(block.Coinbase().Bytes()),
+		PrevHash: toHex(block.ParentHash().Bytes()),
+		Bloom:    toHex(block.Bloom().Bytes()),
 		Raw:      block.String(),
 	}
 }
@@ -114,7 +114,7 @@ func (self *Block) ToString() string {
 }
 
 func (self *Block) GetTransaction(hash string) *Transaction {
-	tx := self.ref.Transaction(common.FromHex(hash))
+	tx := self.ref.Transaction(common.HexToHash(hash))
 	if tx == nil {
 		return nil
 	}
@@ -139,12 +139,12 @@ type Transaction struct {
 }
 
 func NewTx(tx *types.Transaction) *Transaction {
-	hash := toHex(tx.Hash())
-	receiver := toHex(tx.To())
+	hash := tx.Hash().Hex()
+	receiver := tx.To().Hex()
 	if len(receiver) == 0 {
-		receiver = toHex(core.AddressFromMessage(tx))
+		receiver = core.AddressFromMessage(tx).Hex()
 	}
-	sender := toHex(tx.From())
+	sender, _ := tx.From()
 	createsContract := core.MessageCreatesContract(tx)
 
 	var data string
@@ -154,7 +154,7 @@ func NewTx(tx *types.Transaction) *Transaction {
 		data = toHex(tx.Data())
 	}
 
-	return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: toHex(tx.Data())}
+	return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender.Hex(), CreatesContract: createsContract, RawData: toHex(tx.Data())}
 }
 
 func (self *Transaction) ToString() string {

+ 5 - 1
xeth/whisper.go

@@ -4,8 +4,8 @@ import (
 	"errors"
 	"time"
 
-	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/whisper"
 )
@@ -63,6 +63,10 @@ func (self *Whisper) HasIdentity(key string) bool {
 	return self.Whisper.HasIdentity(crypto.ToECDSAPub(common.FromHex(key)))
 }
 
+// func (self *Whisper) RemoveIdentity(key string) bool {
+// 	return self.Whisper.RemoveIdentity(crypto.ToECDSAPub(common.FromHex(key)))
+// }
+
 func (self *Whisper) Watch(opts *Options) int {
 	filter := whisper.Filter{
 		To:     crypto.ToECDSAPub(common.FromHex(opts.To)),

+ 23 - 27
xeth/xeth.go

@@ -8,10 +8,10 @@ import (
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/accounts"
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/p2p"
@@ -116,14 +116,14 @@ func (self *XEth) State() *State { return self.state }
 func (self *XEth) Whisper() *Whisper { return self.whisper }
 
 func (self *XEth) BlockByHash(strHash string) *Block {
-	hash := common.FromHex(strHash)
+	hash := common.HexToHash(strHash)
 	block := self.chainManager.GetBlock(hash)
 
 	return NewBlock(block)
 }
 
 func (self *XEth) EthBlockByHash(strHash string) *types.Block {
-	hash := common.FromHex(strHash)
+	hash := common.HexToHash(strHash)
 	block := self.chainManager.GetBlock(hash)
 
 	return block
@@ -293,9 +293,9 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
 
 	if tx.To() == nil {
 		addr := core.AddressFromMessage(tx)
-		return toHex(addr), nil
+		return addr.Hex(), nil
 	}
-	return toHex(tx.Hash()), nil
+	return tx.Hash().Hex(), nil
 }
 
 var (
@@ -306,8 +306,8 @@ var (
 func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
 	statedb := self.State().State() //self.chainManager.TransState()
 	msg := callmsg{
-		from:     statedb.GetOrNewStateObject(common.FromHex(fromStr)),
-		to:       common.FromHex(toStr),
+		from:     statedb.GetOrNewStateObject(common.HexToAddress(fromStr)),
+		to:       common.HexToAddress(toStr),
 		gas:      common.Big(gasStr),
 		gasPrice: common.Big(gasPriceStr),
 		value:    common.Big(valueStr),
@@ -330,8 +330,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
 
 func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
 	var (
-		from             []byte
-		to               []byte
+		from             = common.HexToAddress(fromStr)
+		to               = common.HexToAddress(toStr)
 		value            = common.NewValue(valueStr)
 		gas              = common.NewValue(gasStr)
 		price            = common.NewValue(gasPriceStr)
@@ -339,10 +339,8 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
 		contractCreation bool
 	)
 
-	from = common.FromHex(fromStr)
 	data = common.FromHex(codeStr)
-	to = common.FromHex(toStr)
-	if len(to) == 0 {
+	if len(toStr) == 0 {
 		contractCreation = true
 	}
 
@@ -368,21 +366,19 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
 	if contractCreation {
 		addr := core.AddressFromMessage(tx)
 		pipelogger.Infof("Contract addr %x\n", addr)
-	}
 
-	if types.IsContractAddr(to) {
-		return toHex(core.AddressFromMessage(tx)), nil
+		return core.AddressFromMessage(tx).Hex(), nil
 	}
-	return toHex(tx.Hash()), nil
+	return tx.Hash().Hex(), nil
 }
 
-func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error {
-	sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash())
+func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock bool) error {
+	sig, err := self.accountManager.Sign(accounts.Account{Address: from.Bytes()}, tx.Hash().Bytes())
 	if err == accounts.ErrLocked {
 		if didUnlock {
 			return fmt.Errorf("sender account still locked after successful unlock")
 		}
-		if !self.frontend.UnlockAccount(from) {
+		if !self.frontend.UnlockAccount(from.Bytes()) {
 			return fmt.Errorf("could not unlock sender account")
 		}
 		// retry signing, the account should now be unlocked.
@@ -397,17 +393,17 @@ func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error
 // callmsg is the message type used for call transations.
 type callmsg struct {
 	from          *state.StateObject
-	to            []byte
+	to            common.Address
 	gas, gasPrice *big.Int
 	value         *big.Int
 	data          []byte
 }
 
 // accessor boilerplate to implement core.Message
-func (m callmsg) From() []byte       { return m.from.Address() }
-func (m callmsg) Nonce() uint64      { return m.from.Nonce() }
-func (m callmsg) To() []byte         { return m.to }
-func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
-func (m callmsg) Gas() *big.Int      { return m.gas }
-func (m callmsg) Value() *big.Int    { return m.value }
-func (m callmsg) Data() []byte       { return m.data }
+func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil }
+func (m callmsg) Nonce() uint64                 { return m.from.Nonce() }
+func (m callmsg) To() *common.Address           { return &m.to }
+func (m callmsg) GasPrice() *big.Int            { return m.gasPrice }
+func (m callmsg) Gas() *big.Int                 { return m.gas }
+func (m callmsg) Value() *big.Int               { return m.value }
+func (m callmsg) Data() []byte                  { return m.data }

Някои файлове не бяха показани, защото твърде много файлове са промени