forked from cerc-io/plugeth
Merge remote-tracking branch 'ethereum/conversion' into conversion
This commit is contained in:
commit
d15f90645d
259
cmd/ethereum/admin.go
Normal file
259
cmd/ethereum/admin.go
Normal file
@ -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)
|
||||||
|
|
||||||
|
}
|
@ -20,18 +20,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
re "github.com/ethereum/go-ethereum/jsre"
|
||||||
"github.com/ethereum/go-ethereum/javascript"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
"github.com/obscuren/otto"
|
|
||||||
"github.com/peterh/liner"
|
"github.com/peterh/liner"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,7 +57,7 @@ func (r dumbterm) PasswordPrompt(p string) (string, error) {
|
|||||||
func (r dumbterm) AppendHistory(string) {}
|
func (r dumbterm) AppendHistory(string) {}
|
||||||
|
|
||||||
type jsre struct {
|
type jsre struct {
|
||||||
re *javascript.JSRE
|
re *re.JSRE
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
xeth *xeth.XEth
|
xeth *xeth.XEth
|
||||||
ps1 string
|
ps1 string
|
||||||
@ -68,11 +66,12 @@ type jsre struct {
|
|||||||
prompter
|
prompter
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJSRE(ethereum *eth.Ethereum) *jsre {
|
func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
|
||||||
js := &jsre{ethereum: ethereum, ps1: "> "}
|
js := &jsre{ethereum: ethereum, ps1: "> "}
|
||||||
js.xeth = xeth.New(ethereum, js)
|
js.xeth = xeth.New(ethereum, js)
|
||||||
js.re = javascript.NewJSRE(js.xeth)
|
js.re = re.New(libPath)
|
||||||
js.initStdFuncs()
|
js.apiBindings()
|
||||||
|
js.adminBindings()
|
||||||
|
|
||||||
if !liner.TerminalSupported() {
|
if !liner.TerminalSupported() {
|
||||||
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
||||||
@ -89,6 +88,49 @@ func newJSRE(ethereum *eth.Ethereum) *jsre {
|
|||||||
return js
|
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 {
|
func (self *jsre) ConfirmTransaction(tx *types.Transaction) bool {
|
||||||
p := fmt.Sprintf("Confirm Transaction %v\n[y/n] ", tx)
|
p := fmt.Sprintf("Confirm Transaction %v\n[y/n] ", tx)
|
||||||
answer, _ := self.Prompt(p)
|
answer, _ := self.Prompt(p)
|
||||||
@ -111,15 +153,7 @@ func (self *jsre) UnlockAccount(addr []byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *jsre) exec(filename string) error {
|
func (self *jsre) exec(filename string) error {
|
||||||
file, err := os.Open(filename)
|
if err := self.re.Exec(filename); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
content, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := self.re.Run(string(content)); err != nil {
|
|
||||||
return fmt.Errorf("Javascript Error: %v", err)
|
return fmt.Errorf("Javascript Error: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -193,102 +227,8 @@ func (self *jsre) setIndent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *jsre) printValue(v interface{}) {
|
func (self *jsre) printValue(v interface{}) {
|
||||||
method, _ := self.re.Vm.Get("prettyPrint")
|
val, err := self.re.PrettyPrint(v)
|
||||||
v, err := self.re.Vm.ToValue(v)
|
|
||||||
if err == nil {
|
|
||||||
val, err := method.Call(method, v)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("%v", val)
|
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
return otto.TrueValue()
|
|
||||||
}
|
|
||||||
|
252
cmd/ethereum/js_test.go
Normal file
252
cmd/ethereum/js_test.go
Normal file
@ -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(ð.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")
|
||||||
|
}
|
||||||
|
}
|
@ -31,9 +31,9 @@ import (
|
|||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
"github.com/peterh/liner"
|
"github.com/peterh/liner"
|
||||||
@ -41,7 +41,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "Ethereum(G)"
|
ClientIdentifier = "Ethereum(G)"
|
||||||
Version = "0.9.0"
|
Version = "0.9.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -89,16 +89,20 @@ Use "ethereum dump 0" to dump the genesis block.
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Action: runjs,
|
Action: console,
|
||||||
Name: "js",
|
Name: "console",
|
||||||
Usage: `interactive JavaScript console`,
|
Usage: `Ethereum Console: interactive JavaScript environment`,
|
||||||
Description: `
|
Description: `
|
||||||
In the console, you can use the eth object to interact
|
Console is an interactive shell for the Ethereum JavaScript runtime environment which exposes a node admin interface as well as the DAPP JavaScript API.
|
||||||
with the running ethereum stack. The API does not match
|
See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
|
||||||
ethereum.js.
|
`,
|
||||||
|
},
|
||||||
A JavaScript file can be provided as the argument. The
|
{
|
||||||
runtime will execute the file and exit.
|
Action: execJSFiles,
|
||||||
|
Name: "js",
|
||||||
|
Usage: `executes the given JavaScript files in the Ethereum Frontier JavaScript VM`,
|
||||||
|
Description: `
|
||||||
|
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.UnlockedAccountFlag,
|
||||||
utils.BootnodesFlag,
|
utils.BootnodesFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
|
utils.JSpathFlag,
|
||||||
utils.ListenPortFlag,
|
utils.ListenPortFlag,
|
||||||
utils.LogFileFlag,
|
utils.LogFileFlag,
|
||||||
utils.LogFormatFlag,
|
utils.LogFormatFlag,
|
||||||
@ -131,6 +136,7 @@ runtime will execute the file and exit.
|
|||||||
utils.RPCPortFlag,
|
utils.RPCPortFlag,
|
||||||
utils.UnencryptedKeysFlag,
|
utils.UnencryptedKeysFlag,
|
||||||
utils.VMDebugFlag,
|
utils.VMDebugFlag,
|
||||||
|
|
||||||
//utils.VMTypeFlag,
|
//utils.VMTypeFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +174,7 @@ func run(ctx *cli.Context) {
|
|||||||
ethereum.WaitForShutdown()
|
ethereum.WaitForShutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runjs(ctx *cli.Context) {
|
func console(ctx *cli.Context) {
|
||||||
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
|
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
|
||||||
ethereum, err := eth.New(cfg)
|
ethereum, err := eth.New(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -176,14 +182,26 @@ func runjs(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startEth(ctx, ethereum)
|
startEth(ctx, ethereum)
|
||||||
repl := newJSRE(ethereum)
|
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name))
|
||||||
if len(ctx.Args()) == 0 {
|
|
||||||
repl.interactive()
|
repl.interactive()
|
||||||
} else {
|
|
||||||
|
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() {
|
for _, file := range ctx.Args() {
|
||||||
repl.exec(file)
|
repl.exec(file)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ethereum.Stop()
|
ethereum.Stop()
|
||||||
ethereum.WaitForShutdown()
|
ethereum.WaitForShutdown()
|
||||||
}
|
}
|
||||||
@ -284,7 +302,7 @@ func dump(ctx *cli.Context) {
|
|||||||
for _, arg := range ctx.Args() {
|
for _, arg := range ctx.Args() {
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
if hashish(arg) {
|
if hashish(arg) {
|
||||||
block = chainmgr.GetBlock(common.Hex2Bytes(arg))
|
block = chainmgr.GetBlock(common.HexToHash(arg))
|
||||||
} else {
|
} else {
|
||||||
num, _ := strconv.Atoi(arg)
|
num, _ := strconv.Atoi(arg)
|
||||||
block = chainmgr.GetBlockByNumber(uint64(num))
|
block = chainmgr.GetBlockByNumber(uint64(num))
|
||||||
|
6
cmd/mist/assets/ext/bignumber.min.js
vendored
6
cmd/mist/assets/ext/bignumber.min.js
vendored
File diff suppressed because one or more lines are too long
@ -157,7 +157,6 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
menuBar: MenuBar {
|
menuBar: MenuBar {
|
||||||
Menu {
|
Menu {
|
||||||
title: "File"
|
title: "File"
|
||||||
@ -206,15 +205,6 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem {
|
|
||||||
text: "Run JS file"
|
|
||||||
onTriggered: {
|
|
||||||
generalFileDialog.show(true, function(path) {
|
|
||||||
eth.evalJavascriptFile(path)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Dump state"
|
text: "Dump state"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
|
@ -25,9 +25,7 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
@ -99,7 +97,7 @@ func NewWindow(ethereum *eth.Ethereum) *Gui {
|
|||||||
return gui
|
return gui
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) Start(assetPath string) {
|
func (gui *Gui) Start(assetPath, libPath string) {
|
||||||
defer gui.txDb.Close()
|
defer gui.txDb.Close()
|
||||||
|
|
||||||
guilogger.Infoln("Starting GUI")
|
guilogger.Infoln("Starting GUI")
|
||||||
@ -117,7 +115,7 @@ func (gui *Gui) Start(assetPath string) {
|
|||||||
// Create a new QML engine
|
// Create a new QML engine
|
||||||
gui.engine = qml.NewEngine()
|
gui.engine = qml.NewEngine()
|
||||||
context := gui.engine.Context()
|
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())
|
gui.whisper = qwhisper.New(gui.eth.Whisper())
|
||||||
|
|
||||||
// Expose the eth library and the ui library to QML
|
// 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)
|
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) {
|
func (gui *Gui) SendCommand(cmd ServEv) {
|
||||||
gui.serviceEvents <- cmd
|
gui.serviceEvents <- cmd
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ func init() {
|
|||||||
utils.NodeKeyFileFlag,
|
utils.NodeKeyFileFlag,
|
||||||
utils.RPCListenAddrFlag,
|
utils.RPCListenAddrFlag,
|
||||||
utils.RPCPortFlag,
|
utils.RPCPortFlag,
|
||||||
|
utils.JSpathFlag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ func run(ctx *cli.Context) {
|
|||||||
gui := NewWindow(ethereum)
|
gui := NewWindow(ethereum)
|
||||||
utils.RegisterInterrupt(func(os.Signal) { gui.Stop() })
|
utils.RegisterInterrupt(func(os.Signal) { gui.Stop() })
|
||||||
// gui blocks the main thread
|
// gui blocks the main thread
|
||||||
gui.Start(ctx.GlobalString(assetPathFlag.Name))
|
gui.Start(ctx.GlobalString(assetPathFlag.Name), ctx.GlobalString(utils.JSpathFlag.Name))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
@ -29,7 +28,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/event/filter"
|
"github.com/ethereum/go-ethereum/event/filter"
|
||||||
"github.com/ethereum/go-ethereum/javascript"
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
"github.com/obscuren/qml"
|
"github.com/obscuren/qml"
|
||||||
)
|
)
|
||||||
@ -49,15 +47,19 @@ type UiLib struct {
|
|||||||
// The main application window
|
// The main application window
|
||||||
win *qml.Window
|
win *qml.Window
|
||||||
|
|
||||||
jsEngine *javascript.JSRE
|
|
||||||
|
|
||||||
filterCallbacks map[int][]int
|
filterCallbacks map[int][]int
|
||||||
filterManager *filter.FilterManager
|
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)
|
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())
|
lib.filterManager = filter.NewFilterManager(eth.EventMux())
|
||||||
go lib.filterManager.Start()
|
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) {
|
func (ui *UiLib) Muted(content string) {
|
||||||
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
|
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -163,6 +163,11 @@ var (
|
|||||||
Usage: "Port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
|
Usage: "Port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
|
||||||
Value: "any",
|
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 {
|
func GetNAT(ctx *cli.Context) nat.Interface {
|
||||||
|
@ -27,6 +27,7 @@ func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
|||||||
func (h Hash) Str() string { return string(h[:]) }
|
func (h Hash) Str() string { return string(h[:]) }
|
||||||
func (h Hash) Bytes() []byte { return h[:] }
|
func (h Hash) Bytes() []byte { return h[:] }
|
||||||
func (h Hash) Big() *big.Int { return Bytes2Big(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
|
// Sets the hash to the value of b. If b is larger than len(h) it will panic
|
||||||
func (h *Hash) SetBytes(b []byte) {
|
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) Bytes() []byte { return a[:] }
|
||||||
func (a Address) Big() *big.Int { return Bytes2Big(a[:]) }
|
func (a Address) Big() *big.Int { return Bytes2Big(a[:]) }
|
||||||
func (a Address) Hash() Hash { return BytesToHash(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
|
// Sets the address to the value of b. If b is larger than len(a) it will panic
|
||||||
func (a *Address) SetBytes(b []byte) {
|
func (a *Address) SetBytes(b []byte) {
|
||||||
|
@ -57,6 +57,12 @@ type Message interface {
|
|||||||
Data() []byte
|
Data() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddressFromMessage(msg Message) common.Address {
|
||||||
|
from, _ := msg.From()
|
||||||
|
|
||||||
|
return crypto.CreateAddress(from, msg.Nonce())
|
||||||
|
}
|
||||||
|
|
||||||
func MessageCreatesContract(msg Message) bool {
|
func MessageCreatesContract(msg Message) bool {
|
||||||
return msg.To() == nil
|
return msg.To() == nil
|
||||||
}
|
}
|
||||||
|
@ -35,3 +35,7 @@ func (b *Bloom) SetBytes(d []byte) {
|
|||||||
func (b Bloom) Big() *big.Int {
|
func (b Bloom) Big() *big.Int {
|
||||||
return common.Bytes2Big(b[:])
|
return common.Bytes2Big(b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b Bloom) Bytes() []byte {
|
||||||
|
return b[:]
|
||||||
|
}
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/blockpool"
|
"github.com/ethereum/go-ethereum/blockpool"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
@ -219,6 +219,64 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
return eth, nil
|
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) {
|
func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
||||||
s.chainManager.ResetWithGenesisBlock(gb)
|
s.chainManager.ResetWithGenesisBlock(gb)
|
||||||
s.pow.UpdateCache(true)
|
s.pow.UpdateCache(true)
|
||||||
@ -230,7 +288,7 @@ func (s *Ethereum) StartMining() error {
|
|||||||
servlogger.Errorf("Cannot start mining without coinbase: %v\n", err)
|
servlogger.Errorf("Cannot start mining without coinbase: %v\n", err)
|
||||||
return fmt.Errorf("no coinbase: %v", err)
|
return fmt.Errorf("no coinbase: %v", err)
|
||||||
}
|
}
|
||||||
s.miner.Start(cb)
|
s.miner.Start(common.BytesToAddress(cb))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +309,7 @@ func (s *Ethereum) StateDb() common.Database { return s.stateDb }
|
|||||||
func (s *Ethereum) ExtraDb() common.Database { return s.extraDb }
|
func (s *Ethereum) ExtraDb() common.Database { return s.extraDb }
|
||||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
||||||
func (s *Ethereum) PeerCount() int { return s.net.PeerCount() }
|
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) Peers() []*p2p.Peer { return s.net.Peers() }
|
||||||
func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers }
|
func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers }
|
||||||
func (s *Ethereum) Version() string { return s.version }
|
func (s *Ethereum) Version() string { return s.version }
|
||||||
@ -262,10 +321,12 @@ func (s *Ethereum) Start() error {
|
|||||||
ProtocolVersion: ProtocolVersion,
|
ProtocolVersion: ProtocolVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if s.net.MaxPeers > 0 {
|
||||||
err := s.net.Start()
|
err := s.net.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start services
|
// Start services
|
||||||
s.txPool.Start()
|
s.txPool.Start()
|
||||||
@ -311,6 +372,7 @@ func (s *Ethereum) Stop() {
|
|||||||
// Close the database
|
// Close the database
|
||||||
defer s.blockDb.Close()
|
defer s.blockDb.Close()
|
||||||
defer s.stateDb.Close()
|
defer s.stateDb.Close()
|
||||||
|
defer s.extraDb.Close()
|
||||||
|
|
||||||
s.txSub.Unsubscribe() // quits txBroadcastLoop
|
s.txSub.Unsubscribe() // quits txBroadcastLoop
|
||||||
s.blockSub.Unsubscribe() // quits blockBroadcastLoop
|
s.blockSub.Unsubscribe() // quits blockBroadcastLoop
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/errs"
|
"github.com/ethereum/go-ethereum/errs"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@ -76,15 +75,15 @@ type txPool interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type chainManager interface {
|
type chainManager interface {
|
||||||
GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte)
|
GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash)
|
||||||
GetBlock(hash []byte) (block *types.Block)
|
GetBlock(hash common.Hash) (block *types.Block)
|
||||||
Status() (td *big.Int, currentBlock []byte, genesisBlock []byte)
|
Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
type blockPool interface {
|
type blockPool interface {
|
||||||
AddBlockHashes(next func() ([]byte, bool), peerId string)
|
AddBlockHashes(next func() (common.Hash, bool), peerId string)
|
||||||
AddBlock(block *types.Block, 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)
|
RemovePeer(peerId string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +94,7 @@ type newBlockMsgData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type getBlockHashesMsgData struct {
|
type getBlockHashesMsgData struct {
|
||||||
Hash []byte
|
Hash common.Hash
|
||||||
Amount uint64
|
Amount uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +166,7 @@ func (self *ethProtocol) handle() error {
|
|||||||
}
|
}
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
jsonlogger.LogJson(&logger.EthTxReceived{
|
jsonlogger.LogJson(&logger.EthTxReceived{
|
||||||
TxHash: common.Bytes2Hex(tx.Hash()),
|
TxHash: tx.Hash().Hex(),
|
||||||
RemoteId: self.peer.ID().String(),
|
RemoteId: self.peer.ID().String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -183,7 +182,7 @@ func (self *ethProtocol) handle() error {
|
|||||||
request.Amount = maxHashes
|
request.Amount = maxHashes
|
||||||
}
|
}
|
||||||
hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount)
|
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:
|
case BlockHashesMsg:
|
||||||
msgStream := rlp.NewStream(msg.Payload)
|
msgStream := rlp.NewStream(msg.Payload)
|
||||||
@ -192,14 +191,16 @@ func (self *ethProtocol) handle() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var i int
|
var i int
|
||||||
iter := func() (hash []byte, ok bool) {
|
iter := func() (hash common.Hash, ok bool) {
|
||||||
hash, err := msgStream.Bytes()
|
var h common.Hash
|
||||||
|
err := msgStream.Decode(&h)
|
||||||
if err == rlp.EOL {
|
if err == rlp.EOL {
|
||||||
return nil, false
|
return common.Hash{}, false
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err)
|
self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err)
|
||||||
return nil, false
|
return common.Hash{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
i++
|
i++
|
||||||
return hash, true
|
return hash, true
|
||||||
}
|
}
|
||||||
@ -215,14 +216,14 @@ func (self *ethProtocol) handle() error {
|
|||||||
var i int
|
var i int
|
||||||
for {
|
for {
|
||||||
i++
|
i++
|
||||||
var hash []byte
|
var hash common.Hash
|
||||||
if err := msgStream.Decode(&hash); err != nil {
|
err := msgStream.Decode(&hash)
|
||||||
if err == rlp.EOL {
|
if err == rlp.EOL {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
block := self.chainManager.GetBlock(hash)
|
block := self.chainManager.GetBlock(hash)
|
||||||
if block != nil {
|
if block != nil {
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
@ -259,10 +260,10 @@ func (self *ethProtocol) handle() error {
|
|||||||
_, chainHead, _ := self.chainManager.Status()
|
_, chainHead, _ := self.chainManager.Status()
|
||||||
|
|
||||||
jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
|
jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
|
||||||
BlockHash: common.Bytes2Hex(hash),
|
BlockHash: hash.Hex(),
|
||||||
BlockNumber: request.Block.Number(), // this surely must be zero
|
BlockNumber: request.Block.Number(), // this surely must be zero
|
||||||
ChainHeadHash: common.Bytes2Hex(chainHead),
|
ChainHeadHash: chainHead.Hex(),
|
||||||
BlockPrevHash: common.Bytes2Hex(request.Block.ParentHash()),
|
BlockPrevHash: request.Block.ParentHash().Hex(),
|
||||||
RemoteId: self.peer.ID().String(),
|
RemoteId: self.peer.ID().String(),
|
||||||
})
|
})
|
||||||
// to simplify backend interface adding a new block
|
// to simplify backend interface adding a new block
|
||||||
@ -282,8 +283,8 @@ type statusMsgData struct {
|
|||||||
ProtocolVersion uint32
|
ProtocolVersion uint32
|
||||||
NetworkId uint32
|
NetworkId uint32
|
||||||
TD *big.Int
|
TD *big.Int
|
||||||
CurrentBlock []byte
|
CurrentBlock common.Hash
|
||||||
GenesisBlock []byte
|
GenesisBlock common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ethProtocol) statusMsg() p2p.Msg {
|
func (self *ethProtocol) statusMsg() p2p.Msg {
|
||||||
@ -325,7 +326,7 @@ func (self *ethProtocol) handleStatus() error {
|
|||||||
|
|
||||||
_, _, genesisBlock := self.chainManager.Status()
|
_, _, genesisBlock := self.chainManager.Status()
|
||||||
|
|
||||||
if !bytes.Equal(status.GenesisBlock, genesisBlock) {
|
if status.GenesisBlock != genesisBlock {
|
||||||
return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
|
return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,14 +345,14 @@ func (self *ethProtocol) handleStatus() error {
|
|||||||
return nil
|
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])
|
self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4])
|
||||||
return p2p.EncodeMsg(self.rw, GetBlockHashesMsg, interface{}(from), uint64(maxHashes))
|
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))
|
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) {
|
func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) {
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
6
jsre/bignumber_js.go
Normal file
6
jsre/bignumber_js.go
Normal file
File diff suppressed because one or more lines are too long
3
jsre/ethereum_js.go
Normal file
3
jsre/ethereum_js.go
Normal file
File diff suppressed because one or more lines are too long
115
jsre/jsre.go
Normal file
115
jsre/jsre.go
Normal file
@ -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
jsre/jsre_test.go
Normal file
84
jsre/jsre_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package javascript
|
package jsre
|
||||||
|
|
||||||
const jsLib = `
|
const pp_js = `
|
||||||
function pp(object) {
|
function pp(object) {
|
||||||
var str = "";
|
var str = "";
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
@ -32,7 +33,7 @@ func (self *Miner) Mining() bool {
|
|||||||
return self.mining
|
return self.mining
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) Start(coinbase []byte) {
|
func (self *Miner) Start(coinbase common.Address) {
|
||||||
self.mining = true
|
self.mining = true
|
||||||
self.worker = newWorker(coinbase, self.eth)
|
self.worker = newWorker(coinbase, self.eth)
|
||||||
self.worker.register(NewCpuMiner(0, self.pow))
|
self.worker.register(NewCpuMiner(0, self.pow))
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
@ -39,7 +39,7 @@ func env(block *types.Block, eth core.Backend) *environment {
|
|||||||
coinbase: state.GetOrNewStateObject(block.Coinbase()),
|
coinbase: state.GetOrNewStateObject(block.Coinbase()),
|
||||||
}
|
}
|
||||||
for _, ancestor := range eth.ChainManager().GetAncestors(block, 7) {
|
for _, ancestor := range eth.ChainManager().GetAncestors(block, 7) {
|
||||||
env.ancestors.Add(string(ancestor.Hash()))
|
env.ancestors.Add(ancestor.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
return env
|
return env
|
||||||
@ -71,14 +71,14 @@ type worker struct {
|
|||||||
eth core.Backend
|
eth core.Backend
|
||||||
chain *core.ChainManager
|
chain *core.ChainManager
|
||||||
proc *core.BlockProcessor
|
proc *core.BlockProcessor
|
||||||
coinbase []byte
|
coinbase common.Address
|
||||||
|
|
||||||
current *environment
|
current *environment
|
||||||
|
|
||||||
mining bool
|
mining bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWorker(coinbase []byte, eth core.Backend) *worker {
|
func newWorker(coinbase common.Address, eth core.Backend) *worker {
|
||||||
return &worker{
|
return &worker{
|
||||||
eth: eth,
|
eth: eth,
|
||||||
mux: eth.EventMux(),
|
mux: eth.EventMux(),
|
||||||
@ -152,13 +152,13 @@ func (self *worker) wait() {
|
|||||||
block := self.current.block
|
block := self.current.block
|
||||||
if block.Number().Uint64() == work.Number && block.Nonce() == 0 {
|
if block.Number().Uint64() == work.Number && block.Nonce() == 0 {
|
||||||
self.current.block.SetNonce(work.Nonce)
|
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{
|
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
||||||
BlockHash: common.Bytes2Hex(block.Hash()),
|
BlockHash: block.Hash().Hex(),
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
ChainHeadHash: common.Bytes2Hex(block.ParentHeaderHash),
|
ChainHeadHash: block.ParentHeaderHash.Hex(),
|
||||||
BlockPrevHash: common.Bytes2Hex(block.ParentHeaderHash),
|
BlockPrevHash: block.ParentHeaderHash.Hex(),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil {
|
if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil {
|
||||||
@ -208,9 +208,10 @@ gasLimit:
|
|||||||
fallthrough
|
fallthrough
|
||||||
case core.IsInvalidTxErr(err):
|
case core.IsInvalidTxErr(err):
|
||||||
// Remove invalid transactions
|
// 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)
|
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):
|
case state.IsGasLimitErr(err):
|
||||||
minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i)
|
minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i)
|
||||||
// Break on gas limit
|
// Break on gas limit
|
||||||
@ -232,13 +233,13 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (self *worker) commitUncle(uncle *types.Header) error {
|
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
|
// Error not unique
|
||||||
return core.UncleError("Uncle 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]))
|
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +51,9 @@ func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr) *Table {
|
|||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
|
|
||||||
// Self returns the local node ID.
|
// Self returns the local node.
|
||||||
func (tab *Table) Self() NodeID {
|
func (tab *Table) Self() *Node {
|
||||||
return tab.self.ID
|
return tab.self
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close terminates the network listener.
|
// Close terminates the network listener.
|
||||||
|
@ -180,7 +180,7 @@ func (srv *Server) Start() (err error) {
|
|||||||
srv.ntab = ntab
|
srv.ntab = ntab
|
||||||
|
|
||||||
// handshake
|
// 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 {
|
for _, p := range srv.Protocols {
|
||||||
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
|
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ func (srv *Server) dialLoop() {
|
|||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
_, isconnected := srv.peers[dest.ID]
|
_, isconnected := srv.peers[dest.ID]
|
||||||
srv.lock.Unlock()
|
srv.lock.Unlock()
|
||||||
if isconnected || dialing[dest.ID] || dest.ID == srv.ntab.Self() {
|
if isconnected || dialing[dest.ID] || dest.ID == srv.Self().ID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,12 +332,16 @@ func (srv *Server) dialNode(dest *discover.Node) {
|
|||||||
srv.startPeer(conn, dest)
|
srv.startPeer(conn, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Self() *discover.Node {
|
||||||
|
return srv.ntab.Self()
|
||||||
|
}
|
||||||
|
|
||||||
func (srv *Server) findPeers() {
|
func (srv *Server) findPeers() {
|
||||||
far := srv.ntab.Self()
|
far := srv.Self().ID
|
||||||
for i := range far {
|
for i := range far {
|
||||||
far[i] = ^far[i]
|
far[i] = ^far[i]
|
||||||
}
|
}
|
||||||
closeToSelf := srv.ntab.Lookup(srv.ntab.Self())
|
closeToSelf := srv.ntab.Lookup(srv.Self().ID)
|
||||||
farFromSelf := srv.ntab.Lookup(far)
|
farFromSelf := srv.ntab.Lookup(far)
|
||||||
|
|
||||||
for i := 0; i < len(closeToSelf) || i < len(farFromSelf); i++ {
|
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
|
return false, DiscTooManyPeers
|
||||||
case srv.peers[id] != nil:
|
case srv.peers[id] != nil:
|
||||||
return false, DiscAlreadyConnected
|
return false, DiscAlreadyConnected
|
||||||
case id == srv.ntab.Self():
|
case id == srv.Self().ID:
|
||||||
return false, DiscSelf
|
return false, DiscSelf
|
||||||
}
|
}
|
||||||
srv.peers[id] = p
|
srv.peers[id] = p
|
||||||
|
32
rpc/api.go
32
rpc/api.go
@ -9,11 +9,11 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/event/filter"
|
"github.com/ethereum/go-ethereum/event/filter"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
@ -371,6 +371,11 @@ func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
|
|||||||
return nil
|
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 {
|
func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error {
|
||||||
var id int
|
var id int
|
||||||
opts := new(xeth.Options)
|
opts := new(xeth.Options)
|
||||||
@ -663,7 +668,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
|
|||||||
return NewValidationError("Index", "does not exist")
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -682,7 +687,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
|
|||||||
return NewValidationError("Index", "does not exist")
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -751,6 +756,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
|
|||||||
return p.WhisperPost(args, reply)
|
return p.WhisperPost(args, reply)
|
||||||
case "shh_newIdentity":
|
case "shh_newIdentity":
|
||||||
return p.NewWhisperIdentity(reply)
|
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":
|
case "shh_hasIdentity":
|
||||||
args := new(WhisperIdentityArgs)
|
args := new(WhisperIdentityArgs)
|
||||||
if err := json.Unmarshal(req.Params, &args); err != nil {
|
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
|
// Convert optional address slice/string to byte slice
|
||||||
if str, ok := options.Address.(string); ok {
|
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 {
|
} else if slice, ok := options.Address.([]interface{}); ok {
|
||||||
bslice := make([][]byte, len(slice))
|
bslice := make([]common.Address, len(slice))
|
||||||
for i, addr := range slice {
|
for i, addr := range slice {
|
||||||
if saddr, ok := addr.(string); ok {
|
if saddr, ok := addr.(string); ok {
|
||||||
bslice[i] = common.FromHex(saddr)
|
bslice[i] = common.HexToAddress(saddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts.Address = bslice
|
opts.Address = bslice
|
||||||
@ -835,16 +846,15 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions {
|
|||||||
opts.Earliest = options.Earliest
|
opts.Earliest = options.Earliest
|
||||||
opts.Latest = options.Latest
|
opts.Latest = options.Latest
|
||||||
|
|
||||||
topics := make([][][]byte, len(options.Topics))
|
topics := make([][]common.Hash, len(options.Topics))
|
||||||
for i, topicDat := range options.Topics {
|
for i, topicDat := range options.Topics {
|
||||||
if slice, ok := topicDat.([]interface{}); ok {
|
if slice, ok := topicDat.([]interface{}); ok {
|
||||||
topics[i] = make([][]byte, len(slice))
|
topics[i] = make([]common.Hash, len(slice))
|
||||||
for j, topic := range 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 {
|
} else if str, ok := topicDat.(string); ok {
|
||||||
topics[i] = make([][]byte, 1)
|
topics[i] = []common.Hash{common.HexToHash(str)}
|
||||||
topics[i][0] = common.FromHex(str)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts.Topics = topics
|
opts.Topics = topics
|
||||||
|
68
rpc/args.go
68
rpc/args.go
@ -331,42 +331,6 @@ func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
|
|||||||
return nil
|
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 {
|
type FilterOptions struct {
|
||||||
Earliest int64
|
Earliest int64
|
||||||
Latest int64
|
Latest int64
|
||||||
@ -378,8 +342,8 @@ type FilterOptions struct {
|
|||||||
|
|
||||||
func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
|
func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
|
||||||
var obj []struct {
|
var obj []struct {
|
||||||
FromBlock string `json:"fromBlock"`
|
FromBlock interface{} `json:"fromBlock"`
|
||||||
ToBlock string `json:"toBlock"`
|
ToBlock interface{} `json:"toBlock"`
|
||||||
Limit string `json:"limit"`
|
Limit string `json:"limit"`
|
||||||
Offset string `json:"offset"`
|
Offset string `json:"offset"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
@ -394,8 +358,32 @@ func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
|
|||||||
return NewInsufficientParamsError(len(obj), 1)
|
return NewInsufficientParamsError(len(obj), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Earliest = int64(common.Big(obj[0].FromBlock).Int64())
|
fromstr, ok := obj[0].FromBlock.(string)
|
||||||
args.Latest = int64(common.Big(obj[0].ToBlock).Int64())
|
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.Max = int(common.Big(obj[0].Limit).Int64())
|
||||||
args.Skip = int(common.Big(obj[0].Offset).Int64())
|
args.Skip = int(common.Big(obj[0].Offset).Int64())
|
||||||
args.Address = obj[0].Address
|
args.Address = obj[0].Address
|
||||||
|
120
rpc/args_test.go
120
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) {
|
func TestGetBlockByNumberArgs(t *testing.T) {
|
||||||
input := `["0x1b4", false]`
|
input := `["0x1b4", false]`
|
||||||
expected := new(GetBlockByNumberArgs)
|
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) {
|
func TestNewTxArgs(t *testing.T) {
|
||||||
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
|
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
|
||||||
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
|
"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) {
|
func TestGetStorageArgs(t *testing.T) {
|
||||||
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
|
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
|
||||||
expected := new(GetStorageArgs)
|
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) {
|
func TestGetStorageAtArgs(t *testing.T) {
|
||||||
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"]`
|
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"]`
|
||||||
expected := new(GetStorageAtArgs)
|
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) {
|
func TestGetTxCountArgs(t *testing.T) {
|
||||||
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
|
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
|
||||||
expected := new(GetTxCountArgs)
|
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) {
|
func TestGetDataArgs(t *testing.T) {
|
||||||
input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", "latest"]`
|
input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", "latest"]`
|
||||||
expected := new(GetDataArgs)
|
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) {
|
func TestFilterOptions(t *testing.T) {
|
||||||
input := `[{
|
input := `[{
|
||||||
"fromBlock": "0x1",
|
"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) {
|
func TestDbArgs(t *testing.T) {
|
||||||
input := `["0x74657374","0x6b6579","0x6d79537472696e67"]`
|
input := `["0x74657374","0x6b6579","0x6d79537472696e67"]`
|
||||||
expected := new(DbArgs)
|
expected := new(DbArgs)
|
||||||
|
14
rpc/http.go
14
rpc/http.go
@ -26,7 +26,7 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
|
|||||||
|
|
||||||
if req.ContentLength > maxSizeReqLength {
|
if req.ContentLength > maxSizeReqLength {
|
||||||
jsonerr := &RpcErrorObject{-32700, "Request too large"}
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +36,11 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
|
|||||||
break
|
break
|
||||||
case *DecodeParamError, *InsufficientParamsError, *ValidationError:
|
case *DecodeParamError, *InsufficientParamsError, *ValidationError:
|
||||||
jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
|
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
|
return
|
||||||
default:
|
default:
|
||||||
jsonerr := &RpcErrorObject{-32700, "Could not parse request"}
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,19 +51,19 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
|
|||||||
break
|
break
|
||||||
case *NotImplementedError:
|
case *NotImplementedError:
|
||||||
jsonerr := &RpcErrorObject{-32601, reserr.Error()}
|
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
|
return
|
||||||
case *DecodeParamError, *InsufficientParamsError, *ValidationError:
|
case *DecodeParamError, *InsufficientParamsError, *ValidationError:
|
||||||
jsonerr := &RpcErrorObject{-32602, reserr.Error()}
|
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
|
return
|
||||||
default:
|
default:
|
||||||
jsonerr := &RpcErrorObject{-32603, reserr.Error()}
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
|
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
rpc/jeth.go
Normal file
43
rpc/jeth.go
Normal file
@ -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
|
||||||
|
}
|
@ -83,21 +83,21 @@ func NewValidationError(param string, msg string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RpcRequest struct {
|
type RpcRequest struct {
|
||||||
ID interface{} `json:"id"`
|
Id interface{} `json:"id"`
|
||||||
JsonRpc string `json:"jsonrpc"`
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Params json.RawMessage `json:"params"`
|
Params json.RawMessage `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RpcSuccessResponse struct {
|
type RpcSuccessResponse struct {
|
||||||
ID interface{} `json:"id"`
|
Id interface{} `json:"id"`
|
||||||
JsonRpc string `json:"jsonrpc"`
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
Result interface{} `json:"result"`
|
Result interface{} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RpcErrorResponse struct {
|
type RpcErrorResponse struct {
|
||||||
ID interface{} `json:"id"`
|
Id interface{} `json:"id"`
|
||||||
JsonRpc string `json:"jsonrpc"`
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
Error *RpcErrorObject `json:"error"`
|
Error *RpcErrorObject `json:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
// "fmt"
|
// "fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,14 +13,14 @@ type BlockRes struct {
|
|||||||
fullTx bool
|
fullTx bool
|
||||||
|
|
||||||
BlockNumber int64 `json:"number"`
|
BlockNumber int64 `json:"number"`
|
||||||
BlockHash []byte `json:"hash"`
|
BlockHash common.Hash `json:"hash"`
|
||||||
ParentHash []byte `json:"parentHash"`
|
ParentHash common.Hash `json:"parentHash"`
|
||||||
Nonce []byte `json:"nonce"`
|
Nonce [8]byte `json:"nonce"`
|
||||||
Sha3Uncles []byte `json:"sha3Uncles"`
|
Sha3Uncles common.Hash `json:"sha3Uncles"`
|
||||||
LogsBloom []byte `json:"logsBloom"`
|
LogsBloom types.Bloom `json:"logsBloom"`
|
||||||
TransactionRoot []byte `json:"transactionRoot"`
|
TransactionRoot common.Hash `json:"transactionRoot"`
|
||||||
StateRoot []byte `json:"stateRoot"`
|
StateRoot common.Hash `json:"stateRoot"`
|
||||||
Miner []byte `json:"miner"`
|
Miner common.Address `json:"miner"`
|
||||||
Difficulty int64 `json:"difficulty"`
|
Difficulty int64 `json:"difficulty"`
|
||||||
TotalDifficulty int64 `json:"totalDifficulty"`
|
TotalDifficulty int64 `json:"totalDifficulty"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
@ -29,7 +30,7 @@ type BlockRes struct {
|
|||||||
GasUsed int64 `json:"gasUsed"`
|
GasUsed int64 `json:"gasUsed"`
|
||||||
UnixTimestamp int64 `json:"timestamp"`
|
UnixTimestamp int64 `json:"timestamp"`
|
||||||
Transactions []*TransactionRes `json:"transactions"`
|
Transactions []*TransactionRes `json:"transactions"`
|
||||||
Uncles [][]byte `json:"uncles"`
|
Uncles []common.Hash `json:"uncles"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
||||||
@ -57,14 +58,14 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
|||||||
|
|
||||||
// convert strict types to hexified strings
|
// convert strict types to hexified strings
|
||||||
ext.BlockNumber = toHex(big.NewInt(b.BlockNumber).Bytes())
|
ext.BlockNumber = toHex(big.NewInt(b.BlockNumber).Bytes())
|
||||||
ext.BlockHash = toHex(b.BlockHash)
|
ext.BlockHash = b.BlockHash.Hex()
|
||||||
ext.ParentHash = toHex(b.ParentHash)
|
ext.ParentHash = b.ParentHash.Hex()
|
||||||
ext.Nonce = toHex(b.Nonce)
|
ext.Nonce = toHex(b.Nonce[:])
|
||||||
ext.Sha3Uncles = toHex(b.Sha3Uncles)
|
ext.Sha3Uncles = b.Sha3Uncles.Hex()
|
||||||
ext.LogsBloom = toHex(b.LogsBloom)
|
ext.LogsBloom = toHex(b.LogsBloom[:])
|
||||||
ext.TransactionRoot = toHex(b.TransactionRoot)
|
ext.TransactionRoot = b.TransactionRoot.Hex()
|
||||||
ext.StateRoot = toHex(b.StateRoot)
|
ext.StateRoot = b.StateRoot.Hex()
|
||||||
ext.Miner = toHex(b.Miner)
|
ext.Miner = b.Miner.Hex()
|
||||||
ext.Difficulty = toHex(big.NewInt(b.Difficulty).Bytes())
|
ext.Difficulty = toHex(big.NewInt(b.Difficulty).Bytes())
|
||||||
ext.TotalDifficulty = toHex(big.NewInt(b.TotalDifficulty).Bytes())
|
ext.TotalDifficulty = toHex(big.NewInt(b.TotalDifficulty).Bytes())
|
||||||
ext.Size = toHex(big.NewInt(b.Size).Bytes())
|
ext.Size = toHex(big.NewInt(b.Size).Bytes())
|
||||||
@ -80,12 +81,12 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i, tx := range b.Transactions {
|
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))
|
ext.Uncles = make([]string, len(b.Uncles))
|
||||||
for i, v := range b.Uncles {
|
for i, v := range b.Uncles {
|
||||||
ext.Uncles[i] = toHex(v)
|
ext.Uncles[i] = v.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(ext)
|
return json.Marshal(ext)
|
||||||
@ -124,7 +125,7 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
|||||||
v.TxIndex = int64(i)
|
v.TxIndex = int64(i)
|
||||||
res.Transactions[i] = v
|
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() {
|
for i, uncle := range block.Uncles() {
|
||||||
res.Uncles[i] = uncle.Hash()
|
res.Uncles[i] = uncle.Hash()
|
||||||
}
|
}
|
||||||
@ -132,13 +133,13 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TransactionRes struct {
|
type TransactionRes struct {
|
||||||
Hash []byte `json:"hash"`
|
Hash common.Hash `json:"hash"`
|
||||||
Nonce int64 `json:"nonce"`
|
Nonce int64 `json:"nonce"`
|
||||||
BlockHash []byte `json:"blockHash,omitempty"`
|
BlockHash common.Hash `json:"blockHash,omitempty"`
|
||||||
BlockNumber int64 `json:"blockNumber,omitempty"`
|
BlockNumber int64 `json:"blockNumber,omitempty"`
|
||||||
TxIndex int64 `json:"transactionIndex,omitempty"`
|
TxIndex int64 `json:"transactionIndex,omitempty"`
|
||||||
From []byte `json:"from"`
|
From common.Address `json:"from"`
|
||||||
To []byte `json:"to"`
|
To *common.Address `json:"to"`
|
||||||
Value int64 `json:"value"`
|
Value int64 `json:"value"`
|
||||||
Gas int64 `json:"gas"`
|
Gas int64 `json:"gas"`
|
||||||
GasPrice int64 `json:"gasPrice"`
|
GasPrice int64 `json:"gasPrice"`
|
||||||
@ -160,13 +161,17 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
|||||||
Input string `json:"input"`
|
Input string `json:"input"`
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.Hash = toHex(t.Hash)
|
ext.Hash = t.Hash.Hex()
|
||||||
ext.Nonce = toHex(big.NewInt(t.Nonce).Bytes())
|
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.BlockNumber = toHex(big.NewInt(t.BlockNumber).Bytes())
|
||||||
ext.TxIndex = toHex(big.NewInt(t.TxIndex).Bytes())
|
ext.TxIndex = toHex(big.NewInt(t.TxIndex).Bytes())
|
||||||
ext.From = toHex(t.From)
|
ext.From = t.From.Hex()
|
||||||
ext.To = toHex(t.To)
|
if t.To == nil {
|
||||||
|
ext.To = "0x00"
|
||||||
|
} else {
|
||||||
|
ext.To = t.To.Hex()
|
||||||
|
}
|
||||||
ext.Value = toHex(big.NewInt(t.Value).Bytes())
|
ext.Value = toHex(big.NewInt(t.Value).Bytes())
|
||||||
ext.Gas = toHex(big.NewInt(t.Gas).Bytes())
|
ext.Gas = toHex(big.NewInt(t.Gas).Bytes())
|
||||||
ext.GasPrice = toHex(big.NewInt(t.GasPrice).Bytes())
|
ext.GasPrice = toHex(big.NewInt(t.GasPrice).Bytes())
|
||||||
@ -179,7 +184,7 @@ func NewTransactionRes(tx *types.Transaction) *TransactionRes {
|
|||||||
var v = new(TransactionRes)
|
var v = new(TransactionRes)
|
||||||
v.Hash = tx.Hash()
|
v.Hash = tx.Hash()
|
||||||
v.Nonce = int64(tx.Nonce())
|
v.Nonce = int64(tx.Nonce())
|
||||||
v.From = tx.From()
|
v.From, _ = tx.From()
|
||||||
v.To = tx.To()
|
v.To = tx.To()
|
||||||
v.Value = tx.Value().Int64()
|
v.Value = tx.Value().Int64()
|
||||||
v.Gas = tx.Gas().Int64()
|
v.Gas = tx.Gas().Int64()
|
||||||
|
@ -45,6 +45,11 @@ func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error
|
|||||||
return NewDecodeParamError(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
|
// Number index determines the index in the array for a possible block number
|
||||||
numberIndex := 0
|
numberIndex := 0
|
||||||
|
|
||||||
@ -150,11 +155,11 @@ func toLogs(logs state.Logs) (ls []Log) {
|
|||||||
for i, log := range logs {
|
for i, log := range logs {
|
||||||
var l Log
|
var l Log
|
||||||
l.Topic = make([]string, len(log.Topics()))
|
l.Topic = make([]string, len(log.Topics()))
|
||||||
l.Address = toHex(log.Address())
|
l.Address = log.Address().Hex()
|
||||||
l.Data = toHex(log.Data())
|
l.Data = toHex(log.Data())
|
||||||
l.Number = log.Number()
|
l.Number = log.Number()
|
||||||
for j, topic := range log.Topics() {
|
for j, topic := range log.Topics() {
|
||||||
l.Topic[j] = toHex(topic)
|
l.Topic[j] = topic.Hex()
|
||||||
}
|
}
|
||||||
ls[i] = l
|
ls[i] = l
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"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
|
// InsertPreState populates the given database with the genesis
|
||||||
// accounts defined by the test.
|
// accounts defined by the test.
|
||||||
func (t *BlockTest) InsertPreState(db common.Database) error {
|
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 {
|
for addrString, acct := range t.preAccounts {
|
||||||
// XXX: is is worth it checking for errors here?
|
// XXX: is is worth it checking for errors here?
|
||||||
//addr, _ := hex.DecodeString(addrString)
|
//addr, _ := hex.DecodeString(addrString)
|
||||||
@ -120,7 +119,7 @@ func (t *BlockTest) InsertPreState(db common.Database) error {
|
|||||||
// sync trie to disk
|
// sync trie to disk
|
||||||
statedb.Sync()
|
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 errors.New("computed state root does not match genesis block")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -212,12 +211,12 @@ func mustConvertAddress(in string) common.Address {
|
|||||||
return common.BytesToAddress(out)
|
return common.BytesToAddress(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustConvertBloom(in string) core.Bloom {
|
func mustConvertBloom(in string) types.Bloom {
|
||||||
out, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
|
out, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("invalid hex: %q", in))
|
panic(fmt.Errorf("invalid hex: %q", in))
|
||||||
}
|
}
|
||||||
return core.BytesToBloom(out)
|
return types.BytesToBloom(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustConvertBigInt10(in string) *big.Int {
|
func mustConvertBigInt10(in string) *big.Int {
|
||||||
|
@ -116,6 +116,15 @@ func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey {
|
|||||||
return self.keys[string(crypto.FromECDSAPub(key))]
|
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 {
|
func (self *Whisper) Watch(opts Filter) int {
|
||||||
return self.filters.Install(filter.Generic{
|
return self.filters.Install(filter.Generic{
|
||||||
Str1: string(crypto.FromECDSAPub(opts.To)),
|
Str1: string(crypto.FromECDSAPub(opts.To)),
|
||||||
|
@ -19,7 +19,7 @@ func (self *State) State() *state.StateDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *State) Get(addr string) *Object {
|
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 {
|
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 {
|
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 {
|
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
|
return object
|
||||||
|
@ -5,10 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
@ -95,12 +95,12 @@ func NewBlock(block *types.Block) *Block {
|
|||||||
return &Block{
|
return &Block{
|
||||||
ref: block, Size: block.Size().String(),
|
ref: block, Size: block.Size().String(),
|
||||||
Number: int(block.NumberU64()), GasUsed: block.GasUsed().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,
|
Transactions: txlist, Uncles: ulist,
|
||||||
Time: block.Time(),
|
Time: block.Time(),
|
||||||
Coinbase: toHex(block.Coinbase()),
|
Coinbase: toHex(block.Coinbase().Bytes()),
|
||||||
PrevHash: toHex(block.ParentHash()),
|
PrevHash: toHex(block.ParentHash().Bytes()),
|
||||||
Bloom: toHex(block.Bloom()),
|
Bloom: toHex(block.Bloom().Bytes()),
|
||||||
Raw: block.String(),
|
Raw: block.String(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ func (self *Block) ToString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Block) GetTransaction(hash string) *Transaction {
|
func (self *Block) GetTransaction(hash string) *Transaction {
|
||||||
tx := self.ref.Transaction(common.FromHex(hash))
|
tx := self.ref.Transaction(common.HexToHash(hash))
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -139,12 +139,12 @@ type Transaction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTx(tx *types.Transaction) *Transaction {
|
func NewTx(tx *types.Transaction) *Transaction {
|
||||||
hash := toHex(tx.Hash())
|
hash := tx.Hash().Hex()
|
||||||
receiver := toHex(tx.To())
|
receiver := tx.To().Hex()
|
||||||
if len(receiver) == 0 {
|
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)
|
createsContract := core.MessageCreatesContract(tx)
|
||||||
|
|
||||||
var data string
|
var data string
|
||||||
@ -154,7 +154,7 @@ func NewTx(tx *types.Transaction) *Transaction {
|
|||||||
data = toHex(tx.Data())
|
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 {
|
func (self *Transaction) ToString() string {
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/whisper"
|
"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)))
|
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 {
|
func (self *Whisper) Watch(opts *Options) int {
|
||||||
filter := whisper.Filter{
|
filter := whisper.Filter{
|
||||||
To: crypto.ToECDSAPub(common.FromHex(opts.To)),
|
To: crypto.ToECDSAPub(common.FromHex(opts.To)),
|
||||||
|
44
xeth/xeth.go
44
xeth/xeth.go
@ -8,10 +8,10 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"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) Whisper() *Whisper { return self.whisper }
|
||||||
|
|
||||||
func (self *XEth) BlockByHash(strHash string) *Block {
|
func (self *XEth) BlockByHash(strHash string) *Block {
|
||||||
hash := common.FromHex(strHash)
|
hash := common.HexToHash(strHash)
|
||||||
block := self.chainManager.GetBlock(hash)
|
block := self.chainManager.GetBlock(hash)
|
||||||
|
|
||||||
return NewBlock(block)
|
return NewBlock(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) EthBlockByHash(strHash string) *types.Block {
|
func (self *XEth) EthBlockByHash(strHash string) *types.Block {
|
||||||
hash := common.FromHex(strHash)
|
hash := common.HexToHash(strHash)
|
||||||
block := self.chainManager.GetBlock(hash)
|
block := self.chainManager.GetBlock(hash)
|
||||||
|
|
||||||
return block
|
return block
|
||||||
@ -293,9 +293,9 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
|
|||||||
|
|
||||||
if tx.To() == nil {
|
if tx.To() == nil {
|
||||||
addr := core.AddressFromMessage(tx)
|
addr := core.AddressFromMessage(tx)
|
||||||
return toHex(addr), nil
|
return addr.Hex(), nil
|
||||||
}
|
}
|
||||||
return toHex(tx.Hash()), nil
|
return tx.Hash().Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -306,8 +306,8 @@ var (
|
|||||||
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
|
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
|
||||||
statedb := self.State().State() //self.chainManager.TransState()
|
statedb := self.State().State() //self.chainManager.TransState()
|
||||||
msg := callmsg{
|
msg := callmsg{
|
||||||
from: statedb.GetOrNewStateObject(common.FromHex(fromStr)),
|
from: statedb.GetOrNewStateObject(common.HexToAddress(fromStr)),
|
||||||
to: common.FromHex(toStr),
|
to: common.HexToAddress(toStr),
|
||||||
gas: common.Big(gasStr),
|
gas: common.Big(gasStr),
|
||||||
gasPrice: common.Big(gasPriceStr),
|
gasPrice: common.Big(gasPriceStr),
|
||||||
value: common.Big(valueStr),
|
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) {
|
func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||||
var (
|
var (
|
||||||
from []byte
|
from = common.HexToAddress(fromStr)
|
||||||
to []byte
|
to = common.HexToAddress(toStr)
|
||||||
value = common.NewValue(valueStr)
|
value = common.NewValue(valueStr)
|
||||||
gas = common.NewValue(gasStr)
|
gas = common.NewValue(gasStr)
|
||||||
price = common.NewValue(gasPriceStr)
|
price = common.NewValue(gasPriceStr)
|
||||||
@ -339,10 +339,8 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
|
|||||||
contractCreation bool
|
contractCreation bool
|
||||||
)
|
)
|
||||||
|
|
||||||
from = common.FromHex(fromStr)
|
|
||||||
data = common.FromHex(codeStr)
|
data = common.FromHex(codeStr)
|
||||||
to = common.FromHex(toStr)
|
if len(toStr) == 0 {
|
||||||
if len(to) == 0 {
|
|
||||||
contractCreation = true
|
contractCreation = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,21 +366,19 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
|
|||||||
if contractCreation {
|
if contractCreation {
|
||||||
addr := core.AddressFromMessage(tx)
|
addr := core.AddressFromMessage(tx)
|
||||||
pipelogger.Infof("Contract addr %x\n", addr)
|
pipelogger.Infof("Contract addr %x\n", addr)
|
||||||
|
|
||||||
|
return core.AddressFromMessage(tx).Hex(), nil
|
||||||
|
}
|
||||||
|
return tx.Hash().Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if types.IsContractAddr(to) {
|
func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock bool) error {
|
||||||
return toHex(core.AddressFromMessage(tx)), nil
|
sig, err := self.accountManager.Sign(accounts.Account{Address: from.Bytes()}, tx.Hash().Bytes())
|
||||||
}
|
|
||||||
return toHex(tx.Hash()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error {
|
|
||||||
sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash())
|
|
||||||
if err == accounts.ErrLocked {
|
if err == accounts.ErrLocked {
|
||||||
if didUnlock {
|
if didUnlock {
|
||||||
return fmt.Errorf("sender account still locked after successful unlock")
|
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")
|
return fmt.Errorf("could not unlock sender account")
|
||||||
}
|
}
|
||||||
// retry signing, the account should now be unlocked.
|
// retry signing, the account should now be unlocked.
|
||||||
@ -397,16 +393,16 @@ func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error
|
|||||||
// callmsg is the message type used for call transations.
|
// callmsg is the message type used for call transations.
|
||||||
type callmsg struct {
|
type callmsg struct {
|
||||||
from *state.StateObject
|
from *state.StateObject
|
||||||
to []byte
|
to common.Address
|
||||||
gas, gasPrice *big.Int
|
gas, gasPrice *big.Int
|
||||||
value *big.Int
|
value *big.Int
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor boilerplate to implement core.Message
|
// accessor boilerplate to implement core.Message
|
||||||
func (m callmsg) From() []byte { return m.from.Address() }
|
func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil }
|
||||||
func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
|
func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
|
||||||
func (m callmsg) To() []byte { return m.to }
|
func (m callmsg) To() *common.Address { return &m.to }
|
||||||
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
|
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
|
||||||
func (m callmsg) Gas() *big.Int { return m.gas }
|
func (m callmsg) Gas() *big.Int { return m.gas }
|
||||||
func (m callmsg) Value() *big.Int { return m.value }
|
func (m callmsg) Value() *big.Int { return m.value }
|
||||||
|
Loading…
Reference in New Issue
Block a user