rpc: migrated the RPC insterface to a new reflection based RPC layer
This commit is contained in:
committed by
Jeffrey Wilcke
parent
f2ab351e8d
commit
19b2640e89
174
cmd/geth/js.go
174
cmd/geth/js.go
@ -24,23 +24,16 @@ import (
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/natspec"
|
||||
"github.com/ethereum/go-ethereum/common/registrar"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
re "github.com/ethereum/go-ethereum/jsre"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/rpc/api"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
"github.com/peterh/liner"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
@ -79,82 +72,90 @@ func (r dumbterm) AppendHistory(string) {}
|
||||
type jsre struct {
|
||||
re *re.JSRE
|
||||
stack *node.Node
|
||||
xeth *xeth.XEth
|
||||
wait chan *big.Int
|
||||
ps1 string
|
||||
atexit func()
|
||||
corsDomain string
|
||||
client comms.EthereumClient
|
||||
client rpc.Client
|
||||
prompter
|
||||
}
|
||||
|
||||
var (
|
||||
loadedModulesMethods map[string][]string
|
||||
loadedModulesMethods map[string][]string
|
||||
autoCompleteStatement = "function _autocomplete(obj) {var results = []; for (var e in obj) { results.push(e); }; return results; }; _autocomplete(%s)"
|
||||
)
|
||||
|
||||
func keywordCompleter(line string) []string {
|
||||
results := make([]string, 0)
|
||||
func keywordCompleter(jsre *jsre, line string) []string {
|
||||
var results []string
|
||||
parts := strings.Split(line, ".")
|
||||
objRef := "this"
|
||||
prefix := line
|
||||
if len(parts) > 1 {
|
||||
objRef = strings.Join(parts[0:len(parts) - 1], ".")
|
||||
prefix = parts[len(parts) - 1]
|
||||
}
|
||||
|
||||
if strings.Contains(line, ".") {
|
||||
elements := strings.Split(line, ".")
|
||||
if len(elements) == 2 {
|
||||
module := elements[0]
|
||||
partialMethod := elements[1]
|
||||
if methods, found := loadedModulesMethods[module]; found {
|
||||
for _, method := range methods {
|
||||
if strings.HasPrefix(method, partialMethod) { // e.g. debug.se
|
||||
results = append(results, module+"."+method)
|
||||
}
|
||||
result, _ := jsre.re.Run(fmt.Sprintf(autoCompleteStatement, objRef))
|
||||
raw, _ := result.Export()
|
||||
if keys, ok := raw.([]interface{}); ok {
|
||||
for _, k := range keys {
|
||||
if strings.HasPrefix(fmt.Sprintf("%s", k), prefix) {
|
||||
if objRef == "this" {
|
||||
results = append(results, fmt.Sprintf("%s", k))
|
||||
} else {
|
||||
results = append(results, fmt.Sprintf("%s.%s", strings.Join(parts[:len(parts) - 1], "."), k))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for module, methods := range loadedModulesMethods {
|
||||
if line == module { // user typed in full module name, show all methods
|
||||
for _, method := range methods {
|
||||
results = append(results, module+"."+method)
|
||||
}
|
||||
} else if strings.HasPrefix(module, line) { // partial method name, e.g. admi
|
||||
results = append(results, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// e.g. web3<tab><tab> append dot since its an object
|
||||
isObj, _ := jsre.re.Run(fmt.Sprintf("typeof(%s) === 'object'", line))
|
||||
if isObject, _ := isObj.ToBoolean(); isObject {
|
||||
results = append(results, line + ".")
|
||||
}
|
||||
|
||||
sort.Strings(results)
|
||||
return results
|
||||
}
|
||||
|
||||
func apiWordCompleter(line string, pos int) (head string, completions []string, tail string) {
|
||||
if len(line) == 0 || pos == 0 {
|
||||
return "", nil, ""
|
||||
func apiWordCompleterWithContext(jsre *jsre) liner.WordCompleter {
|
||||
completer := func(line string, pos int) (head string, completions []string, tail string) {
|
||||
if len(line) == 0 || pos == 0 {
|
||||
return "", nil, ""
|
||||
}
|
||||
|
||||
// chuck data to relevant part for autocompletion, e.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab>
|
||||
i := 0
|
||||
for i = pos - 1; i > 0; i-- {
|
||||
if line[i] == '.' || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') {
|
||||
continue
|
||||
}
|
||||
if i >= 3 && line[i] == '3' && line[i - 3] == 'w' && line[i - 2] == 'e' && line[i - 1] == 'b' {
|
||||
continue
|
||||
}
|
||||
i += 1
|
||||
break
|
||||
}
|
||||
|
||||
begin := line[:i]
|
||||
keyword := line[i:pos]
|
||||
end := line[pos:]
|
||||
|
||||
completionWords := keywordCompleter(jsre, keyword)
|
||||
return begin, completionWords, end
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i = pos - 1; i > 0; i-- {
|
||||
if line[i] == '.' || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') {
|
||||
continue
|
||||
}
|
||||
if i >= 3 && line[i] == '3' && line[i-3] == 'w' && line[i-2] == 'e' && line[i-1] == 'b' {
|
||||
continue
|
||||
}
|
||||
i += 1
|
||||
break
|
||||
}
|
||||
|
||||
begin := line[:i]
|
||||
keyword := line[i:pos]
|
||||
end := line[pos:]
|
||||
|
||||
completionWords := keywordCompleter(keyword)
|
||||
return begin, completionWords, end
|
||||
return completer
|
||||
}
|
||||
|
||||
func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir string, interactive bool) *jsre {
|
||||
func newLightweightJSRE(docRoot string, client rpc.Client, datadir string, interactive bool) *jsre {
|
||||
js := &jsre{ps1: "> "}
|
||||
js.wait = make(chan *big.Int)
|
||||
js.client = client
|
||||
|
||||
// update state in separare forever blocks
|
||||
js.re = re.New(docRoot)
|
||||
if err := js.apiBindings(js); err != nil {
|
||||
if err := js.apiBindings(); err != nil {
|
||||
utils.Fatalf("Unable to initialize console - %v", err)
|
||||
}
|
||||
|
||||
@ -165,7 +166,7 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str
|
||||
js.withHistory(datadir, func(hist *os.File) { lr.ReadHistory(hist) })
|
||||
lr.SetCtrlCAborts(true)
|
||||
js.loadAutoCompletion()
|
||||
lr.SetWordCompleter(apiWordCompleter)
|
||||
lr.SetWordCompleter(apiWordCompleterWithContext(js))
|
||||
lr.SetTabCompletionStyle(liner.TabPrints)
|
||||
js.prompter = lr
|
||||
js.atexit = func() {
|
||||
@ -177,25 +178,15 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str
|
||||
return js
|
||||
}
|
||||
|
||||
func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
|
||||
func newJSRE(stack *node.Node, docRoot, corsDomain string, client rpc.Client, interactive bool) *jsre {
|
||||
js := &jsre{stack: stack, ps1: "> "}
|
||||
// set default cors domain used by startRpc from CLI flag
|
||||
js.corsDomain = corsDomain
|
||||
if f == nil {
|
||||
f = js
|
||||
}
|
||||
js.xeth = xeth.New(stack, f)
|
||||
js.wait = js.xeth.UpdateState()
|
||||
js.wait = make(chan *big.Int)
|
||||
js.client = client
|
||||
if clt, ok := js.client.(*comms.InProcClient); ok {
|
||||
if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, stack); err == nil {
|
||||
clt.Initialize(api.Merge(offeredApis...))
|
||||
}
|
||||
}
|
||||
|
||||
// update state in separare forever blocks
|
||||
js.re = re.New(docRoot)
|
||||
if err := js.apiBindings(f); err != nil {
|
||||
if err := js.apiBindings(); err != nil {
|
||||
utils.Fatalf("Unable to connect - %v", err)
|
||||
}
|
||||
|
||||
@ -206,7 +197,7 @@ func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.Ethereum
|
||||
js.withHistory(stack.DataDir(), func(hist *os.File) { lr.ReadHistory(hist) })
|
||||
lr.SetCtrlCAborts(true)
|
||||
js.loadAutoCompletion()
|
||||
lr.SetWordCompleter(apiWordCompleter)
|
||||
lr.SetWordCompleter(apiWordCompleterWithContext(js))
|
||||
lr.SetTabCompletionStyle(liner.TabPrints)
|
||||
js.prompter = lr
|
||||
js.atexit = func() {
|
||||
@ -222,7 +213,7 @@ func (self *jsre) loadAutoCompletion() {
|
||||
if modules, err := self.supportedApis(); err == nil {
|
||||
loadedModulesMethods = make(map[string][]string)
|
||||
for module, _ := range modules {
|
||||
loadedModulesMethods[module] = api.AutoCompletion[module]
|
||||
loadedModulesMethods[module] = rpc.AutoCompletion[module]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,7 +249,6 @@ func (self *jsre) welcome() {
|
||||
loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version))
|
||||
}
|
||||
sort.Strings(loadedModules)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +256,7 @@ func (self *jsre) supportedApis() (map[string]string, error) {
|
||||
return self.client.SupportedModules()
|
||||
}
|
||||
|
||||
func (js *jsre) apiBindings(f xeth.Frontend) error {
|
||||
func (js *jsre) apiBindings() error {
|
||||
apis, err := js.supportedApis()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -277,12 +267,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
|
||||
apiNames = append(apiNames, a)
|
||||
}
|
||||
|
||||
apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.stack)
|
||||
if err != nil {
|
||||
utils.Fatalf("Unable to determine supported api's: %v", err)
|
||||
}
|
||||
|
||||
jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client, f)
|
||||
jeth := utils.NewJeth(js.re, js.client)
|
||||
js.re.Set("jeth", struct{}{})
|
||||
t, _ := js.re.Get("jeth")
|
||||
jethObj := t.Object()
|
||||
@ -313,14 +298,16 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
|
||||
// load only supported API's in javascript runtime
|
||||
shortcuts := "var eth = web3.eth; "
|
||||
for _, apiName := range apiNames {
|
||||
if apiName == shared.Web3ApiName {
|
||||
continue // manually mapped
|
||||
if apiName == "web3" || apiName == "rpc" {
|
||||
continue // manually mapped or ignore
|
||||
}
|
||||
|
||||
if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), api.Javascript(apiName)); err == nil {
|
||||
shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName)
|
||||
} else {
|
||||
utils.Fatalf("Error loading %s.js: %v", apiName, err)
|
||||
if jsFile, ok := rpc.WEB3Extensions[apiName]; ok {
|
||||
if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), jsFile); err == nil {
|
||||
shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName)
|
||||
} else {
|
||||
utils.Fatalf("Error loading %s.js: %v", apiName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,14 +362,13 @@ func (self *jsre) ConfirmTransaction(tx string) bool {
|
||||
return false
|
||||
}
|
||||
// If natspec is enabled, ask for permission
|
||||
if ethereum.NatSpec {
|
||||
notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient())
|
||||
fmt.Println(notice)
|
||||
answer, _ := self.Prompt("Confirm Transaction [y/n]")
|
||||
return strings.HasPrefix(strings.Trim(answer, " "), "y")
|
||||
} else {
|
||||
return true
|
||||
if ethereum.NatSpec && false /* disabled for now */ {
|
||||
// notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient())
|
||||
// fmt.Println(notice)
|
||||
// answer, _ := self.Prompt("Confirm Transaction [y/n]")
|
||||
// return strings.HasPrefix(strings.Trim(answer, " "), "y")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *jsre) UnlockAccount(addr []byte) bool {
|
||||
|
@ -32,30 +32,27 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/compiler"
|
||||
"github.com/ethereum/go-ethereum/common/httpclient"
|
||||
"github.com/ethereum/go-ethereum/common/natspec"
|
||||
"github.com/ethereum/go-ethereum/common/registrar"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
testSolcPath = ""
|
||||
solcVersion = "0.9.23"
|
||||
solcVersion = "0.9.23"
|
||||
|
||||
testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
|
||||
testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
|
||||
testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||
testBalance = "10000000000000000000"
|
||||
// of empty string
|
||||
// of empty string
|
||||
testHash = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
||||
)
|
||||
|
||||
var (
|
||||
versionRE = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`))
|
||||
versionRE = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`))
|
||||
testNodeKey = crypto.ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f"))
|
||||
testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}`
|
||||
)
|
||||
@ -77,15 +74,16 @@ func (self *testjethre) UnlockAccount(acc []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *testjethre) ConfirmTransaction(tx string) bool {
|
||||
var ethereum *eth.Ethereum
|
||||
self.stack.Service(ðereum)
|
||||
|
||||
if ethereum.NatSpec {
|
||||
self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client)
|
||||
}
|
||||
return true
|
||||
}
|
||||
// Temporary disabled while natspec hasn't been migrated
|
||||
//func (self *testjethre) ConfirmTransaction(tx string) bool {
|
||||
// var ethereum *eth.Ethereum
|
||||
// self.stack.Service(ðereum)
|
||||
//
|
||||
// if ethereum.NatSpec {
|
||||
// self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client)
|
||||
// }
|
||||
// return true
|
||||
//}
|
||||
|
||||
func testJEthRE(t *testing.T) (string, *testjethre, *node.Node) {
|
||||
return testREPL(t, nil)
|
||||
@ -118,7 +116,9 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod
|
||||
if config != nil {
|
||||
config(ethConf)
|
||||
}
|
||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
|
||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
return eth.New(ctx, ethConf)
|
||||
}); err != nil {
|
||||
t.Fatalf("failed to register ethereum protocol: %v", err)
|
||||
}
|
||||
// Initialize all the keys for testing
|
||||
@ -141,9 +141,10 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod
|
||||
stack.Service(ðereum)
|
||||
|
||||
assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
|
||||
client := comms.NewInProcClient(codec.JSON)
|
||||
//client := comms.NewInProcClient(codec.JSON)
|
||||
client := utils.NewInProcRPCClient(stack)
|
||||
tf := &testjethre{client: ethereum.HTTPClient()}
|
||||
repl := newJSRE(stack, assetPath, "", client, false, tf)
|
||||
repl := newJSRE(stack, assetPath, "", client, false)
|
||||
tf.jsre = repl
|
||||
return tmp, tf, stack
|
||||
}
|
||||
@ -166,8 +167,8 @@ func TestAccounts(t *testing.T) {
|
||||
defer node.Stop()
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
|
||||
checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`)
|
||||
checkEvalJSON(t, repl, `eth.accounts`, `["` + testAddress + `"]`)
|
||||
checkEvalJSON(t, repl, `eth.coinbase`, `"` + testAddress + `"`)
|
||||
val, err := repl.re.Run(`jeth.newAccount("password")`)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
@ -177,7 +178,7 @@ func TestAccounts(t *testing.T) {
|
||||
t.Errorf("address not hex: %q", addr)
|
||||
}
|
||||
|
||||
checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`","`+addr+`"]`)
|
||||
checkEvalJSON(t, repl, `eth.accounts`, `["` + testAddress + `","` + addr + `"]`)
|
||||
|
||||
}
|
||||
|
||||
@ -205,13 +206,13 @@ func TestBlockChain(t *testing.T) {
|
||||
node.Service(ðereum)
|
||||
ethereum.BlockChain().Reset()
|
||||
|
||||
checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`)
|
||||
checkEvalJSON(t, repl, `admin.exportChain(` + tmpfileq + `)`, `true`)
|
||||
if _, err := os.Stat(tmpfile); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// check import, verify that dumpBlock gives the same result.
|
||||
checkEvalJSON(t, repl, `admin.importChain(`+tmpfileq+`)`, `true`)
|
||||
checkEvalJSON(t, repl, `admin.importChain(` + tmpfileq + `)`, `true`)
|
||||
checkEvalJSON(t, repl, `debug.dumpBlock(eth.blockNumber)`, beforeExport)
|
||||
}
|
||||
|
||||
@ -239,7 +240,7 @@ func TestCheckTestAccountBalance(t *testing.T) {
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
repl.re.Run(`primary = "` + testAddress + `"`)
|
||||
checkEvalJSON(t, repl, `eth.getBalance(primary)`, `"`+testBalance+`"`)
|
||||
checkEvalJSON(t, repl, `eth.getBalance(primary)`, `"` + testBalance + `"`)
|
||||
}
|
||||
|
||||
func TestSignature(t *testing.T) {
|
||||
@ -278,19 +279,20 @@ func TestContract(t *testing.T) {
|
||||
defer ethereum.Stop()
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
reg := registrar.New(repl.xeth)
|
||||
_, err := reg.SetGlobalRegistrar("", coinbase)
|
||||
if err != nil {
|
||||
t.Errorf("error setting HashReg: %v", err)
|
||||
}
|
||||
_, err = reg.SetHashReg("", coinbase)
|
||||
if err != nil {
|
||||
t.Errorf("error setting HashReg: %v", err)
|
||||
}
|
||||
_, err = reg.SetUrlHint("", coinbase)
|
||||
if err != nil {
|
||||
t.Errorf("error setting HashReg: %v", err)
|
||||
}
|
||||
// Temporary disabled while registrar isn't migrated
|
||||
//reg := registrar.New(repl.xeth)
|
||||
//_, err := reg.SetGlobalRegistrar("", coinbase)
|
||||
//if err != nil {
|
||||
// t.Errorf("error setting HashReg: %v", err)
|
||||
//}
|
||||
//_, err = reg.SetHashReg("", coinbase)
|
||||
//if err != nil {
|
||||
// t.Errorf("error setting HashReg: %v", err)
|
||||
//}
|
||||
//_, err = reg.SetUrlHint("", coinbase)
|
||||
//if err != nil {
|
||||
// t.Errorf("error setting HashReg: %v", err)
|
||||
//}
|
||||
/* TODO:
|
||||
* lookup receipt and contract addresses by tx hash
|
||||
* name registration for HashReg and UrlHint addresses
|
||||
@ -299,11 +301,11 @@ func TestContract(t *testing.T) {
|
||||
*/
|
||||
|
||||
source := `contract test {\n` +
|
||||
" /// @notice Will multiply `a` by 7." + `\n` +
|
||||
` function multiply(uint a) returns(uint d) {\n` +
|
||||
` return a * 7;\n` +
|
||||
` }\n` +
|
||||
`}\n`
|
||||
" /// @notice Will multiply `a` by 7." + `\n` +
|
||||
` function multiply(uint a) returns(uint d) {\n` +
|
||||
` return a * 7;\n` +
|
||||
` }\n` +
|
||||
`}\n`
|
||||
|
||||
if checkEvalJSON(t, repl, `admin.stopNatSpec()`, `true`) != nil {
|
||||
return
|
||||
@ -313,10 +315,10 @@ func TestContract(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
if checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`) != nil {
|
||||
if checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"` + testAddress + `"`) != nil {
|
||||
return
|
||||
}
|
||||
if checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`) != nil {
|
||||
if checkEvalJSON(t, repl, `source = "` + source + `"`, `"` + source + `"`) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -394,7 +396,7 @@ multiply7 = Multiply7.at(contractaddress);
|
||||
|
||||
var contentHash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"`
|
||||
if sol != nil && solcVersion != sol.Version() {
|
||||
modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`))
|
||||
modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"` + sol.Version() + `"`))
|
||||
fmt.Printf("modified contractinfo:\n%s\n", modContractInfo)
|
||||
contentHash = `"` + common.ToHex(crypto.Sha3([]byte(modContractInfo))) + `"`
|
||||
}
|
||||
@ -474,11 +476,12 @@ func processTxs(repl *testjethre, t *testing.T, expTxc int) bool {
|
||||
defer ethereum.StopMining()
|
||||
|
||||
timer := time.NewTimer(100 * time.Second)
|
||||
height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1))
|
||||
blockNr := ethereum.BlockChain().CurrentBlock().Number()
|
||||
height := new(big.Int).Add(blockNr, big.NewInt(1))
|
||||
repl.wait <- height
|
||||
select {
|
||||
case <-timer.C:
|
||||
// if times out make sure the xeth loop does not block
|
||||
// if times out make sure the xeth loop does not block
|
||||
go func() {
|
||||
select {
|
||||
case repl.wait <- nil:
|
||||
|
@ -40,8 +40,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -263,11 +261,11 @@ See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
|
||||
Name: "attach",
|
||||
Usage: `Geth Console: interactive JavaScript environment (connect to node)`,
|
||||
Description: `
|
||||
The Geth console is an interactive shell for the JavaScript runtime environment
|
||||
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
||||
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.
|
||||
This command allows to open a console on a running geth node.
|
||||
`,
|
||||
The Geth console is an interactive shell for the JavaScript runtime environment
|
||||
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
||||
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.
|
||||
This command allows to open a console on a running geth node.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Action: execScripts,
|
||||
@ -309,11 +307,15 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
||||
utils.RPCEnabledFlag,
|
||||
utils.RPCListenAddrFlag,
|
||||
utils.RPCPortFlag,
|
||||
utils.RpcApiFlag,
|
||||
utils.RPCApiFlag,
|
||||
utils.WSEnabledFlag,
|
||||
utils.WSListenAddrFlag,
|
||||
utils.WSPortFlag,
|
||||
utils.WSApiFlag,
|
||||
utils.WSAllowedDomainsFlag,
|
||||
utils.IPCDisabledFlag,
|
||||
utils.IPCApiFlag,
|
||||
utils.IPCPathFlag,
|
||||
utils.IPCExperimental,
|
||||
utils.ExecFlag,
|
||||
utils.WhisperEnabledFlag,
|
||||
utils.DevModeFlag,
|
||||
@ -392,20 +394,12 @@ func geth(ctx *cli.Context) {
|
||||
node.Wait()
|
||||
}
|
||||
|
||||
// attach will connect to a running geth instance attaching a JavaScript console and to it.
|
||||
func attach(ctx *cli.Context) {
|
||||
var client comms.EthereumClient
|
||||
var err error
|
||||
if ctx.Args().Present() {
|
||||
client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON)
|
||||
} else {
|
||||
cfg := comms.IpcConfig{
|
||||
Endpoint: utils.IpcSocketPath(ctx),
|
||||
}
|
||||
client, err = comms.NewIpcClient(cfg, codec.JSON)
|
||||
}
|
||||
|
||||
// attach to a running geth instance
|
||||
client, err := utils.NewRemoteRPCClient(ctx)
|
||||
if err != nil {
|
||||
utils.Fatalf("Unable to attach to geth node - %v", err)
|
||||
utils.Fatalf("Unable to attach to geth - %v", err)
|
||||
}
|
||||
|
||||
repl := newLightweightJSRE(
|
||||
@ -431,11 +425,12 @@ func console(ctx *cli.Context) {
|
||||
startNode(ctx, node)
|
||||
|
||||
// Attach to the newly started node, and either execute script or become interactive
|
||||
client := comms.NewInProcClient(codec.JSON)
|
||||
client := utils.NewInProcRPCClient(node)
|
||||
|
||||
repl := newJSRE(node,
|
||||
ctx.GlobalString(utils.JSpathFlag.Name),
|
||||
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
|
||||
client, true, nil)
|
||||
client, true)
|
||||
|
||||
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
|
||||
repl.batch(script)
|
||||
@ -454,11 +449,12 @@ func execScripts(ctx *cli.Context) {
|
||||
startNode(ctx, node)
|
||||
|
||||
// Attach to the newly started node and execute the given scripts
|
||||
client := comms.NewInProcClient(codec.JSON)
|
||||
client := utils.NewInProcRPCClient(node)
|
||||
|
||||
repl := newJSRE(node,
|
||||
ctx.GlobalString(utils.JSpathFlag.Name),
|
||||
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
|
||||
client, false, nil)
|
||||
client, false)
|
||||
|
||||
for _, file := range ctx.Args() {
|
||||
repl.exec(file)
|
||||
@ -517,6 +513,11 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||
utils.Fatalf("Failed to start RPC: %v", err)
|
||||
}
|
||||
}
|
||||
if ctx.GlobalBool(utils.WSEnabledFlag.Name) {
|
||||
if err := utils.StartWS(stack, ctx); err != nil {
|
||||
utils.Fatalf("Failed to start WS: %v", err)
|
||||
}
|
||||
}
|
||||
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
||||
if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil {
|
||||
utils.Fatalf("Failed to start mining: %v", err)
|
||||
|
@ -21,16 +21,15 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||
"github.com/gizak/termui"
|
||||
)
|
||||
|
||||
@ -70,20 +69,18 @@ to display multiple metrics simultaneously.
|
||||
// monitor starts a terminal UI based monitoring tool for the requested metrics.
|
||||
func monitor(ctx *cli.Context) {
|
||||
var (
|
||||
client comms.EthereumClient
|
||||
client rpc.Client
|
||||
err error
|
||||
)
|
||||
// Attach to an Ethereum node over IPC or RPC
|
||||
endpoint := ctx.String(monitorCommandAttachFlag.Name)
|
||||
if client, err = comms.ClientFromEndpoint(endpoint, codec.JSON); err != nil {
|
||||
if client, err = utils.NewRemoteRPCClientFromString(endpoint); err != nil {
|
||||
utils.Fatalf("Unable to attach to geth node: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
xeth := rpc.NewXeth(client)
|
||||
|
||||
// Retrieve all the available metrics and resolve the user pattens
|
||||
metrics, err := retrieveMetrics(xeth)
|
||||
metrics, err := retrieveMetrics(client)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to retrieve system metrics: %v", err)
|
||||
}
|
||||
@ -133,7 +130,7 @@ func monitor(ctx *cli.Context) {
|
||||
}
|
||||
termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer)))
|
||||
|
||||
refreshCharts(xeth, monitored, data, units, charts, ctx, footer)
|
||||
refreshCharts(client, monitored, data, units, charts, ctx, footer)
|
||||
termui.Body.Align()
|
||||
termui.Render(termui.Body)
|
||||
|
||||
@ -154,7 +151,7 @@ func monitor(ctx *cli.Context) {
|
||||
termui.Render(termui.Body)
|
||||
}
|
||||
case <-refresh:
|
||||
if refreshCharts(xeth, monitored, data, units, charts, ctx, footer) {
|
||||
if refreshCharts(client, monitored, data, units, charts, ctx, footer) {
|
||||
termui.Body.Align()
|
||||
}
|
||||
termui.Render(termui.Body)
|
||||
@ -164,8 +161,30 @@ func monitor(ctx *cli.Context) {
|
||||
|
||||
// retrieveMetrics contacts the attached geth node and retrieves the entire set
|
||||
// of collected system metrics.
|
||||
func retrieveMetrics(xeth *rpc.Xeth) (map[string]interface{}, error) {
|
||||
return xeth.Call("debug_metrics", []interface{}{true})
|
||||
func retrieveMetrics(client rpc.Client) (map[string]interface{}, error) {
|
||||
req := map[string]interface{}{
|
||||
"id": new(int64),
|
||||
"method": "debug_metrics",
|
||||
"jsonrpc": "2.0",
|
||||
"params": []interface{}{true},
|
||||
}
|
||||
|
||||
if err := client.Send(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res rpc.JSONSuccessResponse
|
||||
if err := client.Recv(&res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.Result != nil {
|
||||
if mets, ok := res.Result.(map[string]interface{}); ok {
|
||||
return mets, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to retrieve metrics")
|
||||
}
|
||||
|
||||
// resolveMetrics takes a list of input metric patterns, and resolves each to one
|
||||
@ -253,8 +272,8 @@ func fetchMetric(metrics map[string]interface{}, metric string) float64 {
|
||||
|
||||
// refreshCharts retrieves a next batch of metrics, and inserts all the new
|
||||
// values into the active datasets and charts
|
||||
func refreshCharts(xeth *rpc.Xeth, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) {
|
||||
values, err := retrieveMetrics(xeth)
|
||||
func refreshCharts(client rpc.Client, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) {
|
||||
values, err := retrieveMetrics(client)
|
||||
for i, metric := range metrics {
|
||||
if len(data) < 512 {
|
||||
data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...)
|
||||
|
@ -87,7 +87,12 @@ var AppHelpFlagGroups = []flagGroup{
|
||||
utils.RPCEnabledFlag,
|
||||
utils.RPCListenAddrFlag,
|
||||
utils.RPCPortFlag,
|
||||
utils.RpcApiFlag,
|
||||
utils.RPCApiFlag,
|
||||
utils.WSEnabledFlag,
|
||||
utils.WSListenAddrFlag,
|
||||
utils.WSPortFlag,
|
||||
utils.WSApiFlag,
|
||||
utils.WSAllowedDomainsFlag,
|
||||
utils.IPCDisabledFlag,
|
||||
utils.IPCApiFlag,
|
||||
utils.IPCPathFlag,
|
||||
@ -158,7 +163,6 @@ var AppHelpFlagGroups = []flagGroup{
|
||||
Flags: []cli.Flag{
|
||||
utils.WhisperEnabledFlag,
|
||||
utils.NatspecEnabledFlag,
|
||||
utils.IPCExperimental,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -26,8 +26,9 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
@ -35,13 +36,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc/api"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||
rpc "github.com/ethereum/go-ethereum/rpc/v2"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/tests"
|
||||
"github.com/ethereum/go-ethereum/whisper"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
)
|
||||
|
||||
const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||
@ -176,21 +173,25 @@ func RunTest(stack *node.Node, test *tests.BlockTest) error {
|
||||
|
||||
// StartRPC initializes an RPC interface to the given protocol stack.
|
||||
func StartRPC(stack *node.Node) error {
|
||||
config := comms.HttpConfig{
|
||||
ListenAddress: "127.0.0.1",
|
||||
ListenPort: 8545,
|
||||
}
|
||||
xeth := xeth.New(stack, nil)
|
||||
codec := codec.JSON
|
||||
/*
|
||||
web3 := NewPublicWeb3API(stack)
|
||||
server.RegisterName("web3", web3)
|
||||
net := NewPublicNetAPI(stack.Server(), ethereum.NetVersion())
|
||||
server.RegisterName("net", net)
|
||||
*/
|
||||
|
||||
apis, err := api.ParseApiString(comms.DefaultHttpRpcApis, codec, xeth, stack)
|
||||
if err != nil {
|
||||
return err
|
||||
for _, api := range stack.APIs() {
|
||||
if adminApi, ok := api.Service.(*node.PrivateAdminAPI); ok {
|
||||
_, err := adminApi.StartRPC("127.0.0.1", 8545, "", "admin,db,eth,debug,miner,net,shh,txpool,personal,web3")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return comms.StartHttp(config, codec, api.Merge(apis...))
|
||||
|
||||
glog.V(logger.Error).Infof("Unable to start RPC-HTTP interface, could not find admin API")
|
||||
return errors.New("Unable to start RPC-HTTP interface")
|
||||
}
|
||||
|
||||
// StartRPC initializes an IPC interface to the given protocol stack.
|
||||
// StartIPC initializes an IPC interface to the given protocol stack.
|
||||
func StartIPC(stack *node.Node) error {
|
||||
var ethereum *eth.Ethereum
|
||||
if err := stack.Service(ðereum); err != nil {
|
||||
@ -202,11 +203,7 @@ func StartIPC(stack *node.Node) error {
|
||||
endpoint = filepath.Join(common.DefaultDataDir(), "geth.ipc")
|
||||
}
|
||||
|
||||
config := comms.IpcConfig{
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
||||
listener, err := comms.CreateListener(config)
|
||||
listener, err := rpc.CreateIPCListener(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -217,16 +214,16 @@ func StartIPC(stack *node.Node) error {
|
||||
offered := stack.APIs()
|
||||
for _, api := range offered {
|
||||
server.RegisterName(api.Namespace, api.Service)
|
||||
glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace)
|
||||
glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace)
|
||||
}
|
||||
|
||||
web3 := utils.NewPublicWeb3API(stack)
|
||||
server.RegisterName("web3", web3)
|
||||
net := utils.NewPublicNetAPI(stack.Server(), ethereum.NetVersion())
|
||||
server.RegisterName("net", net)
|
||||
//var ethereum *eth.Ethereum
|
||||
//if err := stack.Service(ðereum); err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
go func() {
|
||||
glog.V(logger.Info).Infof("Start IPC server on %s\n", config.Endpoint)
|
||||
glog.V(logger.Info).Infof("Start IPC server on %s\n", endpoint)
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
|
@ -1,74 +0,0 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
rpc "github.com/ethereum/go-ethereum/rpc/v2"
|
||||
)
|
||||
|
||||
// PublicWeb3API offers helper utils
|
||||
type PublicWeb3API struct {
|
||||
stack *node.Node
|
||||
}
|
||||
|
||||
// NewPublicWeb3API creates a new Web3Service instance
|
||||
func NewPublicWeb3API(stack *node.Node) *PublicWeb3API {
|
||||
return &PublicWeb3API{stack}
|
||||
}
|
||||
|
||||
// ClientVersion returns the node name
|
||||
func (s *PublicWeb3API) ClientVersion() string {
|
||||
return s.stack.Server().Name
|
||||
}
|
||||
|
||||
// Sha3 applies the ethereum sha3 implementation on the input.
|
||||
// It assumes the input is hex encoded.
|
||||
func (s *PublicWeb3API) Sha3(input string) string {
|
||||
return common.ToHex(crypto.Sha3(common.FromHex(input)))
|
||||
}
|
||||
|
||||
// PublicNetAPI offers network related RPC methods
|
||||
type PublicNetAPI struct {
|
||||
net *p2p.Server
|
||||
networkVersion int
|
||||
}
|
||||
|
||||
// NewPublicNetAPI creates a new net api instance.
|
||||
func NewPublicNetAPI(net *p2p.Server, networkVersion int) *PublicNetAPI {
|
||||
return &PublicNetAPI{net, networkVersion}
|
||||
}
|
||||
|
||||
// Listening returns an indication if the node is listening for network connections.
|
||||
func (s *PublicNetAPI) Listening() bool {
|
||||
return true // always listening
|
||||
}
|
||||
|
||||
// Peercount returns the number of connected peers
|
||||
func (s *PublicNetAPI) PeerCount() *rpc.HexNumber {
|
||||
return rpc.NewHexNumber(s.net.PeerCount())
|
||||
}
|
||||
|
||||
// ProtocolVersion returns the current ethereum protocol version.
|
||||
func (s *PublicNetAPI) Version() string {
|
||||
return fmt.Sprintf("%d", s.networkVersion)
|
||||
}
|
176
cmd/utils/client.go
Normal file
176
cmd/utils/client.go
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
// NewInProcRPCClient will start a new RPC server for the given node and returns a client to interact with it.
|
||||
func NewInProcRPCClient(stack *node.Node) *inProcClient {
|
||||
server := rpc.NewServer()
|
||||
|
||||
offered := stack.APIs()
|
||||
for _, api := range offered {
|
||||
server.RegisterName(api.Namespace, api.Service)
|
||||
}
|
||||
|
||||
web3 := node.NewPublicWeb3API(stack)
|
||||
server.RegisterName("web3", web3)
|
||||
|
||||
var ethereum *eth.Ethereum
|
||||
if err := stack.Service(ðereum); err == nil {
|
||||
net := eth.NewPublicNetAPI(stack.Server(), ethereum.NetVersion())
|
||||
server.RegisterName("net", net)
|
||||
} else {
|
||||
glog.V(logger.Warn).Infof("%v\n", err)
|
||||
}
|
||||
|
||||
buf := &buf{
|
||||
requests: make(chan []byte),
|
||||
responses: make(chan []byte),
|
||||
}
|
||||
client := &inProcClient{
|
||||
server: server,
|
||||
buf: buf,
|
||||
}
|
||||
|
||||
go func() {
|
||||
server.ServeCodec(rpc.NewJSONCodec(client.buf))
|
||||
}()
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// buf represents the connection between the RPC server and console
|
||||
type buf struct {
|
||||
readBuf []byte // store remaining request bytes after a partial read
|
||||
requests chan []byte // list with raw serialized requests
|
||||
responses chan []byte // list with raw serialized responses
|
||||
}
|
||||
|
||||
// will read the next request in json format
|
||||
func (b *buf) Read(p []byte) (int, error) {
|
||||
// last read didn't read entire request, return remaining bytes
|
||||
if len(b.readBuf) > 0 {
|
||||
n := copy(p, b.readBuf)
|
||||
if n < len(b.readBuf) {
|
||||
b.readBuf = b.readBuf[:n]
|
||||
} else {
|
||||
b.readBuf = b.readBuf[:0]
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// read next request
|
||||
req := <-b.requests
|
||||
n := copy(p, req)
|
||||
if n < len(req) {
|
||||
// buf too small, store remaining chunk for next read
|
||||
b.readBuf = req[n:]
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Write send the given buffer to the backend
|
||||
func (b *buf) Write(p []byte) (n int, err error) {
|
||||
b.responses <- p
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Close cleans up obtained resources.
|
||||
func (b *buf) Close() error {
|
||||
close(b.requests)
|
||||
close(b.responses)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// inProcClient starts a RPC server and uses buf to communicate with it.
|
||||
type inProcClient struct {
|
||||
server *rpc.Server
|
||||
buf *buf
|
||||
}
|
||||
|
||||
// Close will stop the RPC server
|
||||
func (c *inProcClient) Close() {
|
||||
c.server.Stop()
|
||||
}
|
||||
|
||||
// Send a msg to the endpoint
|
||||
func (c *inProcClient) Send(msg interface{}) error {
|
||||
d, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.buf.requests <- d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Recv reads a message and tries to parse it into the given msg
|
||||
func (c *inProcClient) Recv(msg interface{}) error {
|
||||
data := <-c.buf.responses
|
||||
return json.Unmarshal(data, &msg)
|
||||
}
|
||||
|
||||
// Returns the collection of modules the RPC server offers.
|
||||
func (c *inProcClient) SupportedModules() (map[string]string, error) {
|
||||
return rpc.SupportedModules(c)
|
||||
}
|
||||
|
||||
// NewRemoteRPCClient returns a RPC client which connects to a running geth instance.
|
||||
// Depending on the given context this can either be a IPC or a HTTP client.
|
||||
func NewRemoteRPCClient(ctx *cli.Context) (rpc.Client, error) {
|
||||
if ctx.Args().Present() {
|
||||
endpoint := ctx.Args().First()
|
||||
return NewRemoteRPCClientFromString(endpoint)
|
||||
}
|
||||
|
||||
// use IPC by default
|
||||
endpoint := IPCSocketPath(ctx)
|
||||
return rpc.NewIPCClient(endpoint)
|
||||
}
|
||||
|
||||
// NewRemoteRPCClientFromString returns a RPC client which connects to the given
|
||||
// endpoint. It must start with either `ipc:` or `rpc:` (HTTP).
|
||||
func NewRemoteRPCClientFromString(endpoint string) (rpc.Client, error) {
|
||||
if strings.HasPrefix(endpoint, "ipc:") {
|
||||
return rpc.NewIPCClient(endpoint[4:])
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "rpc:") {
|
||||
return rpc.NewHTTPClient(endpoint[4:])
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "http://") {
|
||||
return rpc.NewHTTPClient(endpoint)
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "ws:") {
|
||||
return rpc.NewWSClient(endpoint)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid endpoint")
|
||||
}
|
@ -23,7 +23,6 @@ import (
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -31,6 +30,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
@ -49,14 +50,8 @@ import (
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc/api"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||
"github.com/ethereum/go-ethereum/rpc/useragent"
|
||||
rpc "github.com/ethereum/go-ethereum/rpc/v2"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/whisper"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -282,10 +277,10 @@ var (
|
||||
Usage: "Domains from which to accept cross origin requests (browser enforced)",
|
||||
Value: "",
|
||||
}
|
||||
RpcApiFlag = cli.StringFlag{
|
||||
RPCApiFlag = cli.StringFlag{
|
||||
Name: "rpcapi",
|
||||
Usage: "API's offered over the HTTP-RPC interface",
|
||||
Value: comms.DefaultHttpRpcApis,
|
||||
Value: rpc.DefaultHttpRpcApis,
|
||||
}
|
||||
IPCDisabledFlag = cli.BoolFlag{
|
||||
Name: "ipcdisable",
|
||||
@ -294,16 +289,36 @@ var (
|
||||
IPCApiFlag = cli.StringFlag{
|
||||
Name: "ipcapi",
|
||||
Usage: "API's offered over the IPC-RPC interface",
|
||||
Value: comms.DefaultIpcApis,
|
||||
Value: rpc.DefaultIpcApis,
|
||||
}
|
||||
IPCPathFlag = DirectoryFlag{
|
||||
Name: "ipcpath",
|
||||
Usage: "Filename for IPC socket/pipe",
|
||||
Value: DirectoryString{common.DefaultIpcPath()},
|
||||
}
|
||||
IPCExperimental = cli.BoolFlag{
|
||||
Name: "ipcexp",
|
||||
Usage: "Enable the new RPC implementation",
|
||||
WSEnabledFlag = cli.BoolFlag{
|
||||
Name: "ws",
|
||||
Usage: "Enable the WS-RPC server",
|
||||
}
|
||||
WSListenAddrFlag = cli.StringFlag{
|
||||
Name: "wsaddr",
|
||||
Usage: "WS-RPC server listening interface",
|
||||
Value: "127.0.0.1",
|
||||
}
|
||||
WSPortFlag = cli.IntFlag{
|
||||
Name: "wsport",
|
||||
Usage: "WS-RPC server listening port",
|
||||
Value: 8546,
|
||||
}
|
||||
WSApiFlag = cli.StringFlag{
|
||||
Name: "wsapi",
|
||||
Usage: "API's offered over the WS-RPC interface",
|
||||
Value: rpc.DefaultHttpRpcApis,
|
||||
}
|
||||
WSAllowedDomainsFlag = cli.StringFlag{
|
||||
Name: "wsdomains",
|
||||
Usage: "Domains from which to accept websockets requests",
|
||||
Value: "",
|
||||
}
|
||||
ExecFlag = cli.StringFlag{
|
||||
Name: "exec",
|
||||
@ -760,7 +775,7 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database
|
||||
return chain, chainDb
|
||||
}
|
||||
|
||||
func IpcSocketPath(ctx *cli.Context) (ipcpath string) {
|
||||
func IPCSocketPath(ctx *cli.Context) (ipcpath string) {
|
||||
if runtime.GOOS == "windows" {
|
||||
ipcpath = common.DefaultIpcPath()
|
||||
if ctx.GlobalIsSet(IPCPathFlag.Name) {
|
||||
@ -780,79 +795,83 @@ func IpcSocketPath(ctx *cli.Context) (ipcpath string) {
|
||||
}
|
||||
|
||||
func StartIPC(stack *node.Node, ctx *cli.Context) error {
|
||||
config := comms.IpcConfig{
|
||||
Endpoint: IpcSocketPath(ctx),
|
||||
}
|
||||
|
||||
var ethereum *eth.Ethereum
|
||||
if err := stack.Service(ðereum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.GlobalIsSet(IPCExperimental.Name) {
|
||||
listener, err := comms.CreateListener(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
endpoint := IPCSocketPath(ctx)
|
||||
listener, err := rpc.CreateIPCListener(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server := rpc.NewServer()
|
||||
server := rpc.NewServer()
|
||||
|
||||
// register package API's this node provides
|
||||
offered := stack.APIs()
|
||||
for _, api := range offered {
|
||||
server.RegisterName(api.Namespace, api.Service)
|
||||
glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace)
|
||||
}
|
||||
// register package API's this node provides
|
||||
offered := stack.APIs()
|
||||
for _, api := range offered {
|
||||
server.RegisterName(api.Namespace, api.Service)
|
||||
glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace)
|
||||
}
|
||||
|
||||
web3 := NewPublicWeb3API(stack)
|
||||
server.RegisterName("web3", web3)
|
||||
net := NewPublicNetAPI(stack.Server(), ethereum.NetVersion())
|
||||
server.RegisterName("net", net)
|
||||
|
||||
go func() {
|
||||
glog.V(logger.Info).Infof("Start IPC server on %s\n", config.Endpoint)
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Unable to accept connection - %v\n", err)
|
||||
}
|
||||
|
||||
codec := rpc.NewJSONCodec(conn)
|
||||
go server.ServeCodec(codec)
|
||||
go func() {
|
||||
glog.V(logger.Info).Infof("Start IPC server on %s\n", endpoint)
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Unable to accept connection - %v\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) {
|
||||
fe := useragent.NewRemoteFrontend(conn, ethereum.AccountManager())
|
||||
xeth := xeth.New(stack, fe)
|
||||
apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec.JSON, xeth, stack)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
codec := rpc.NewJSONCodec(conn)
|
||||
go server.ServeCodec(codec)
|
||||
}
|
||||
return xeth, api.Merge(apis...), nil
|
||||
}
|
||||
return comms.StartIpc(config, codec.JSON, initializer)
|
||||
}()
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// StartRPC starts a HTTP JSON-RPC API server.
|
||||
func StartRPC(stack *node.Node, ctx *cli.Context) error {
|
||||
config := comms.HttpConfig{
|
||||
ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name),
|
||||
ListenPort: uint(ctx.GlobalInt(RPCPortFlag.Name)),
|
||||
CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name),
|
||||
for _, api := range stack.APIs() {
|
||||
if adminApi, ok := api.Service.(*node.PrivateAdminAPI); ok {
|
||||
address := ctx.GlobalString(RPCListenAddrFlag.Name)
|
||||
port := ctx.GlobalInt(RPCPortFlag.Name)
|
||||
cors := ctx.GlobalString(RPCCORSDomainFlag.Name)
|
||||
apiStr := ""
|
||||
if ctx.GlobalIsSet(RPCApiFlag.Name) {
|
||||
apiStr = ctx.GlobalString(RPCApiFlag.Name)
|
||||
}
|
||||
|
||||
_, err := adminApi.StartRPC(address, port, cors, apiStr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
xeth := xeth.New(stack, nil)
|
||||
codec := codec.JSON
|
||||
glog.V(logger.Error).Infof("Unable to start RPC-HTTP interface, could not find admin API")
|
||||
return errors.New("Unable to start RPC-HTTP interface")
|
||||
}
|
||||
|
||||
apis, err := api.ParseApiString(ctx.GlobalString(RpcApiFlag.Name), codec, xeth, stack)
|
||||
if err != nil {
|
||||
return err
|
||||
// StartWS starts a websocket JSON-RPC API server.
|
||||
func StartWS(stack *node.Node, ctx *cli.Context) error {
|
||||
for _, api := range stack.APIs() {
|
||||
if adminApi, ok := api.Service.(*node.PrivateAdminAPI); ok {
|
||||
address := ctx.GlobalString(WSListenAddrFlag.Name)
|
||||
port := ctx.GlobalInt(WSAllowedDomainsFlag.Name)
|
||||
allowedDomains := ctx.GlobalString(WSAllowedDomainsFlag.Name)
|
||||
apiStr := ""
|
||||
if ctx.GlobalIsSet(WSApiFlag.Name) {
|
||||
apiStr = ctx.GlobalString(WSApiFlag.Name)
|
||||
}
|
||||
|
||||
_, err := adminApi.StartWS(address, port, allowedDomains, apiStr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return comms.StartHttp(config, codec, api.Merge(apis...))
|
||||
|
||||
glog.V(logger.Error).Infof("Unable to start RPC-WS interface, could not find admin API")
|
||||
return errors.New("Unable to start RPC-WS interface")
|
||||
}
|
||||
|
||||
func StartPProf(ctx *cli.Context) {
|
||||
|
323
cmd/utils/jeth.go
Normal file
323
cmd/utils/jeth.go
Normal file
@ -0,0 +1,323 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/jsre"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
type Jeth struct {
|
||||
re *jsre.JSRE
|
||||
client rpc.Client
|
||||
}
|
||||
|
||||
// NewJeth create a new backend for the JSRE console
|
||||
func NewJeth(re *jsre.JSRE, client rpc.Client) *Jeth {
|
||||
return &Jeth{re, client}
|
||||
}
|
||||
|
||||
func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id *int64) (response otto.Value) {
|
||||
m := rpc.JSONErrResponse{
|
||||
Version: "2.0",
|
||||
Id: id,
|
||||
Error: rpc.JSONError{
|
||||
Code: code,
|
||||
Message: msg,
|
||||
},
|
||||
}
|
||||
|
||||
errObj, _ := json.Marshal(m.Error)
|
||||
errRes, _ := json.Marshal(m)
|
||||
|
||||
call.Otto.Run("ret_error = " + string(errObj))
|
||||
res, _ := call.Otto.Run("ret_response = " + string(errRes))
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// UnlockAccount asks the user for the password and than executes the jeth.UnlockAccount callback in the jsre
|
||||
func (self *Jeth) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
|
||||
var cmd, account, passwd string
|
||||
timeout := int64(300)
|
||||
var ok bool
|
||||
|
||||
if len(call.ArgumentList) == 0 {
|
||||
fmt.Println("expected address of account to unlock")
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
if len(call.ArgumentList) >= 1 {
|
||||
if accountExport, err := call.Argument(0).Export(); err == nil {
|
||||
if account, ok = accountExport.(string); ok {
|
||||
if len(call.ArgumentList) == 1 {
|
||||
fmt.Printf("Unlock account %s\n", account)
|
||||
passwd, err = PromptPassword("Passphrase: ", true)
|
||||
if err != nil {
|
||||
return otto.FalseValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(call.ArgumentList) >= 2 {
|
||||
if passwdExport, err := call.Argument(1).Export(); err == nil {
|
||||
passwd, _ = passwdExport.(string)
|
||||
}
|
||||
}
|
||||
|
||||
if len(call.ArgumentList) >= 3 {
|
||||
if timeoutExport, err := call.Argument(2).Export(); err == nil {
|
||||
timeout, _ = timeoutExport.(int64)
|
||||
}
|
||||
}
|
||||
|
||||
cmd = fmt.Sprintf("jeth.unlockAccount('%s', '%s', %d)", account, passwd, timeout)
|
||||
if val, err := call.Otto.Run(cmd); err == nil {
|
||||
return val
|
||||
}
|
||||
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
// NewAccount asks the user for the password and than executes the jeth.newAccount callback in the jsre
|
||||
func (self *Jeth) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||
if len(call.ArgumentList) == 0 {
|
||||
passwd, err := PromptPassword("Passphrase: ", true)
|
||||
if err != nil {
|
||||
return otto.FalseValue()
|
||||
}
|
||||
passwd2, err := PromptPassword("Repeat passphrase: ", true)
|
||||
if err != nil {
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
if passwd != passwd2 {
|
||||
fmt.Println("Passphrases don't match")
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf("jeth.newAccount('%s')", passwd)
|
||||
if val, err := call.Otto.Run(cmd); err == nil {
|
||||
return val
|
||||
}
|
||||
} else {
|
||||
fmt.Println("New account doesn't expect argument(s), you will be prompted for a password")
|
||||
}
|
||||
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
|
||||
reqif, err := call.Argument(0).Export()
|
||||
if err != nil {
|
||||
return self.err(call, -32700, err.Error(), nil)
|
||||
}
|
||||
|
||||
jsonreq, err := json.Marshal(reqif)
|
||||
var reqs []rpc.JSONRequest
|
||||
batch := true
|
||||
err = json.Unmarshal(jsonreq, &reqs)
|
||||
if err != nil {
|
||||
reqs = make([]rpc.JSONRequest, 1)
|
||||
err = json.Unmarshal(jsonreq, &reqs[0])
|
||||
batch = false
|
||||
}
|
||||
|
||||
call.Otto.Set("response_len", len(reqs))
|
||||
call.Otto.Run("var ret_response = new Array(response_len);")
|
||||
|
||||
for i, req := range reqs {
|
||||
err := self.client.Send(&req)
|
||||
if err != nil {
|
||||
return self.err(call, -32603, err.Error(), req.Id)
|
||||
}
|
||||
|
||||
result := make(map[string]interface{})
|
||||
err = self.client.Recv(&result)
|
||||
if err != nil {
|
||||
return self.err(call, -32603, err.Error(), req.Id)
|
||||
}
|
||||
|
||||
_, isSuccessResponse := result["result"]
|
||||
_, isErrorResponse := result["error"]
|
||||
if !isSuccessResponse && !isErrorResponse {
|
||||
return self.err(call, -32603, fmt.Sprintf("Invalid response"), new(int64))
|
||||
}
|
||||
|
||||
id, _ := result["id"]
|
||||
call.Otto.Set("ret_id", id)
|
||||
|
||||
jsonver, _ := result["jsonrpc"]
|
||||
call.Otto.Set("ret_jsonrpc", jsonver)
|
||||
|
||||
var payload []byte
|
||||
if isSuccessResponse {
|
||||
payload, _ = json.Marshal(result["result"])
|
||||
} else if isErrorResponse {
|
||||
payload, _ = json.Marshal(result["error"])
|
||||
}
|
||||
call.Otto.Set("ret_result", string(payload))
|
||||
call.Otto.Set("response_idx", i)
|
||||
|
||||
response, err = call.Otto.Run(`
|
||||
ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) };
|
||||
`)
|
||||
}
|
||||
|
||||
if !batch {
|
||||
call.Otto.Run("ret_response = ret_response[0];")
|
||||
}
|
||||
|
||||
if call.Argument(1).IsObject() {
|
||||
call.Otto.Set("callback", call.Argument(1))
|
||||
call.Otto.Run(`
|
||||
if (Object.prototype.toString.call(callback) == '[object Function]') {
|
||||
callback(null, ret_response);
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
// handleRequest will handle user agent requests by interacting with the user and sending
|
||||
// the user response back to the geth service
|
||||
func (self *Jeth) handleRequest(req *shared.Request) bool {
|
||||
var err error
|
||||
var args []interface{}
|
||||
if err = json.Unmarshal(req.Params, &args); err != nil {
|
||||
glog.V(logger.Info).Infof("Unable to parse agent request - %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
switch req.Method {
|
||||
case useragent.AskPasswordMethod:
|
||||
return self.askPassword(req.Id, req.Jsonrpc, args)
|
||||
case useragent.ConfirmTransactionMethod:
|
||||
return self.confirmTransaction(req.Id, req.Jsonrpc, args)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// askPassword will ask the user to supply the password for a given account
|
||||
func (self *Jeth) askPassword(id interface{}, jsonrpc string, args []interface{}) bool {
|
||||
var err error
|
||||
var passwd string
|
||||
if len(args) >= 1 {
|
||||
if account, ok := args[0].(string); ok {
|
||||
fmt.Printf("Unlock account %s\n", account)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
passwd, err = PromptPassword("Passphrase: ", true)
|
||||
|
||||
if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil {
|
||||
glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err)
|
||||
}
|
||||
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (self *Jeth) confirmTransaction(id interface{}, jsonrpc string, args []interface{}) bool {
|
||||
// Accept all tx which are send from this console
|
||||
return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil
|
||||
}
|
||||
*/
|
||||
|
||||
// throwJSExeception panics on an otto value, the Otto VM will then throw msg as a javascript error.
|
||||
func throwJSExeception(msg interface{}) otto.Value {
|
||||
p, _ := otto.ToValue(msg)
|
||||
panic(p)
|
||||
return p
|
||||
}
|
||||
|
||||
// Sleep will halt the console for arg[0] seconds.
|
||||
func (self *Jeth) Sleep(call otto.FunctionCall) (response otto.Value) {
|
||||
if len(call.ArgumentList) >= 1 {
|
||||
if call.Argument(0).IsNumber() {
|
||||
sleep, _ := call.Argument(0).ToInteger()
|
||||
time.Sleep(time.Duration(sleep) * time.Second)
|
||||
return otto.TrueValue()
|
||||
}
|
||||
}
|
||||
return throwJSExeception("usage: sleep(<sleep in seconds>)")
|
||||
}
|
||||
|
||||
// SleepBlocks will wait for a specified number of new blocks or max for a
|
||||
// given of seconds. sleepBlocks(nBlocks[, maxSleep]).
|
||||
func (self *Jeth) SleepBlocks(call otto.FunctionCall) (response otto.Value) {
|
||||
nBlocks := int64(0)
|
||||
maxSleep := int64(9999999999999999) // indefinitely
|
||||
|
||||
nArgs := len(call.ArgumentList)
|
||||
|
||||
if nArgs == 0 {
|
||||
throwJSExeception("usage: sleepBlocks(<n blocks>[, max sleep in seconds])")
|
||||
}
|
||||
|
||||
if nArgs >= 1 {
|
||||
if call.Argument(0).IsNumber() {
|
||||
nBlocks, _ = call.Argument(0).ToInteger()
|
||||
} else {
|
||||
throwJSExeception("expected number as first argument")
|
||||
}
|
||||
}
|
||||
|
||||
if nArgs >= 2 {
|
||||
if call.Argument(1).IsNumber() {
|
||||
maxSleep, _ = call.Argument(1).ToInteger()
|
||||
} else {
|
||||
throwJSExeception("expected number as second argument")
|
||||
}
|
||||
}
|
||||
|
||||
// go through the console, this will allow web3 to call the appropriate
|
||||
// callbacks if a delayed response or notification is received.
|
||||
currentBlockNr := func() int64 {
|
||||
result, err := call.Otto.Run("eth.blockNumber")
|
||||
if err != nil {
|
||||
throwJSExeception(err.Error())
|
||||
}
|
||||
blockNr, err := result.ToInteger()
|
||||
if err != nil {
|
||||
throwJSExeception(err.Error())
|
||||
}
|
||||
return blockNr
|
||||
}
|
||||
|
||||
targetBlockNr := currentBlockNr() + nBlocks
|
||||
deadline := time.Now().Add(time.Duration(maxSleep) * time.Second)
|
||||
|
||||
for time.Now().Before(deadline) {
|
||||
if currentBlockNr() >= targetBlockNr {
|
||||
return otto.TrueValue()
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
return otto.FalseValue()
|
||||
}
|
Reference in New Issue
Block a user