aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/geth
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/geth')
-rw-r--r--cmd/geth/admin.go937
-rw-r--r--cmd/geth/js.go189
-rw-r--r--cmd/geth/main.go9
3 files changed, 193 insertions, 942 deletions
diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go
deleted file mode 100644
index 33ef69792..000000000
--- a/cmd/geth/admin.go
+++ /dev/null
@@ -1,937 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "math/big"
- "strconv"
- "time"
-
- "github.com/ethereum/ethash"
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/cmd/utils"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/compiler"
- "github.com/ethereum/go-ethereum/common/natspec"
- "github.com/ethereum/go-ethereum/common/resolver"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger/glog"
- "github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/ethereum/go-ethereum/xeth"
- "github.com/robertkrimen/otto"
- "gopkg.in/fatih/set.v0"
-)
-
-/*
-node admin bindings
-*/
-
-func (js *jsre) adminBindings() {
- ethO, _ := js.re.Get("eth")
- eth := ethO.Object()
- eth.Set("pendingTransactions", js.pendingTransactions)
- eth.Set("resend", js.resend)
- eth.Set("sign", js.sign)
-
- js.re.Set("admin", struct{}{})
- t, _ := js.re.Get("admin")
- admin := t.Object()
- admin.Set("addPeer", js.addPeer)
- admin.Set("startRPC", js.startRPC)
- admin.Set("stopRPC", js.stopRPC)
- 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("verbosity", js.verbosity)
- admin.Set("progress", js.syncProgress)
- admin.Set("setSolc", js.setSolc)
-
- admin.Set("contractInfo", struct{}{})
- t, _ = admin.Get("contractInfo")
- cinfo := t.Object()
- // newRegistry officially not documented temporary option
- cinfo.Set("start", js.startNatSpec)
- cinfo.Set("stop", js.stopNatSpec)
- cinfo.Set("newRegistry", js.newRegistry)
- cinfo.Set("get", js.getContractInfo)
- cinfo.Set("register", js.register)
- cinfo.Set("registerUrl", js.registerUrl)
- // cinfo.Set("verify", js.verify)
-
- admin.Set("miner", struct{}{})
- t, _ = admin.Get("miner")
- miner := t.Object()
- miner.Set("start", js.startMining)
- miner.Set("stop", js.stopMining)
- miner.Set("hashrate", js.hashrate)
- miner.Set("setExtra", js.setExtra)
- miner.Set("setGasPrice", js.setGasPrice)
- miner.Set("startAutoDAG", js.startAutoDAG)
- miner.Set("stopAutoDAG", js.stopAutoDAG)
- miner.Set("makeDAG", js.makeDAG)
-
- admin.Set("txPool", struct{}{})
- t, _ = admin.Get("txPool")
- txPool := t.Object()
- txPool.Set("pending", js.allPendingTransactions)
- txPool.Set("queued", js.allQueuedTransactions)
-
- admin.Set("debug", struct{}{})
- t, _ = admin.Get("debug")
- debug := t.Object()
- js.re.Set("sleep", js.sleep)
- debug.Set("backtrace", js.backtrace)
- debug.Set("printBlock", js.printBlock)
- debug.Set("dumpBlock", js.dumpBlock)
- debug.Set("getBlockRlp", js.getBlockRlp)
- debug.Set("setHead", js.setHead)
- debug.Set("processBlock", js.debugBlock)
- debug.Set("seedhash", js.seedHash)
- debug.Set("insertBlock", js.insertBlockRlp)
- // undocumented temporary
- debug.Set("waitForBlocks", js.waitForBlocks)
-}
-
-// generic helper to getBlock by Number/Height or Hex depending on autodetected input
-// if argument is missing the current block is returned
-// if block is not found or there is problem with decoding
-// the appropriate value is returned and block is guaranteed to be nil
-func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
- 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 {
- return nil, errors.New("invalid argument for dump. Either hex string or number")
- }
- } else {
- block = js.ethereum.ChainManager().CurrentBlock()
- }
-
- if block == nil {
- return nil, errors.New("block not found")
- }
- return block, nil
-}
-
-func (js *jsre) seedHash(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) > 0 {
- if call.Argument(0).IsNumber() {
- num, _ := call.Argument(0).ToInteger()
- hash, err := ethash.GetSeedHash(uint64(num))
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(fmt.Sprintf("0x%x", hash))
- return v
- } else {
- fmt.Println("arg not a number")
- }
- } else {
- fmt.Println("requires number argument")
- }
-
- return otto.UndefinedValue()
-}
-
-func (js *jsre) allPendingTransactions(call otto.FunctionCall) otto.Value {
- txs := js.ethereum.TxPool().GetTransactions()
-
- ltxs := make([]*tx, len(txs))
- for i, tx := range txs {
- // no need to check err
- ltxs[i] = newTx(tx)
- }
-
- v, _ := call.Otto.ToValue(ltxs)
- return v
-}
-
-func (js *jsre) allQueuedTransactions(call otto.FunctionCall) otto.Value {
- txs := js.ethereum.TxPool().GetQueuedTransactions()
-
- ltxs := make([]*tx, len(txs))
- for i, tx := range txs {
- // no need to check err
- ltxs[i] = newTx(tx)
- }
-
- v, _ := call.Otto.ToValue(ltxs)
- return v
-}
-
-func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
- txs := js.ethereum.TxPool().GetTransactions()
-
- // grab the accounts from the account manager. This will help with determening which
- // transactions should be returned.
- accounts, err := js.ethereum.AccountManager().Accounts()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- // Add the accouns to a new set
- accountSet := set.New()
- for _, account := range accounts {
- accountSet.Add(account.Address)
- }
-
- //ltxs := make([]*tx, len(txs))
- var ltxs []*tx
- for _, tx := range txs {
- if from, _ := tx.From(); accountSet.Has(from) {
- ltxs = append(ltxs, newTx(tx))
- }
- }
-
- v, _ := call.Otto.ToValue(ltxs)
- return v
-}
-
-func (js *jsre) resend(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("first argument must be a transaction")
- return otto.FalseValue()
- }
-
- v, err := call.Argument(0).Export()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- if tx, ok := v.(*tx); ok {
- gl, gp := tx.GasLimit, tx.GasPrice
- if len(call.ArgumentList) > 1 {
- gp = call.Argument(1).String()
- }
- if len(call.ArgumentList) > 2 {
- gl = call.Argument(2).String()
- }
-
- ret, err := js.xeth.Transact(tx.From, tx.To, tx.Nonce, tx.Value, gl, gp, tx.Data)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- js.ethereum.TxPool().RemoveTransactions(types.Transactions{tx.tx})
-
- v, _ := call.Otto.ToValue(ret)
- return v
- }
-
- fmt.Println("first argument must be a transaction")
- return otto.FalseValue()
-}
-
-func (js *jsre) sign(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 2 {
- fmt.Println("requires 2 arguments: eth.sign(signer, data)")
- return otto.UndefinedValue()
- }
- signer, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- data, err := call.Argument(1).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- signed, err := js.xeth.Sign(signer, data, false)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(signed)
- return v
-}
-
-func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- tstart := time.Now()
- old := vm.Debug
-
- if len(call.ArgumentList) > 1 {
- vm.Debug, _ = call.Argument(1).ToBoolean()
- }
-
- _, err = js.ethereum.BlockProcessor().RetryProcess(block)
- if err != nil {
- fmt.Println(err)
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": false, "time": time.Since(tstart).Seconds()})
- return r
- }
- vm.Debug = old
-
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": true, "time": time.Since(tstart).Seconds()})
- return r
-}
-
-func (js *jsre) insertBlockRlp(call otto.FunctionCall) otto.Value {
- tstart := time.Now()
-
- var block types.Block
- if call.Argument(0).IsString() {
- blockRlp, _ := call.Argument(0).ToString()
- err := rlp.DecodeBytes(common.Hex2Bytes(blockRlp), &block)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- }
-
- old := vm.Debug
- vm.Debug = true
- _, err := js.ethereum.BlockProcessor().RetryProcess(&block)
- if err != nil {
- fmt.Println(err)
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": false, "time": time.Since(tstart).Seconds()})
- return r
- }
- vm.Debug = old
-
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": true, "time": time.Since(tstart).Seconds()})
- return r
-}
-
-func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- js.ethereum.ChainManager().SetHead(block)
- return otto.UndefinedValue()
-}
-
-func (js *jsre) syncProgress(call otto.FunctionCall) otto.Value {
- pending, cached, importing, eta := js.ethereum.Downloader().Stats()
- v, _ := call.Otto.ToValue(map[string]interface{}{
- "pending": pending,
- "cached": cached,
- "importing": importing,
- "estimate": (eta / time.Second * time.Second).String(),
- })
- return v
-}
-
-func (js *jsre) getBlockRlp(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- encoded, _ := rlp.EncodeToBytes(block)
- v, _ := call.Otto.ToValue(fmt.Sprintf("%x", encoded))
- return v
-}
-
-func (js *jsre) setExtra(call otto.FunctionCall) otto.Value {
- extra, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- if len(extra) > 1024 {
- fmt.Println("error: cannot exceed 1024 bytes")
- return otto.UndefinedValue()
- }
-
- js.ethereum.Miner().SetExtra([]byte(extra))
- return otto.UndefinedValue()
-}
-
-func (js *jsre) setGasPrice(call otto.FunctionCall) otto.Value {
- gasPrice, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- js.ethereum.Miner().SetGasPrice(common.String2Big(gasPrice))
- return otto.UndefinedValue()
-}
-
-func (js *jsre) hashrate(call otto.FunctionCall) otto.Value {
- v, _ := call.Otto.ToValue(js.ethereum.Miner().HashRate())
- return v
-}
-
-func (js *jsre) makeDAG(call otto.FunctionCall) otto.Value {
- blockNumber, err := call.Argument(1).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- err = ethash.MakeDAG(uint64(blockNumber), "")
- if err != nil {
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) startAutoDAG(otto.FunctionCall) otto.Value {
- js.ethereum.StartAutoDAG()
- return otto.TrueValue()
-}
-
-func (js *jsre) stopAutoDAG(otto.FunctionCall) otto.Value {
- js.ethereum.StopAutoDAG()
- return otto.TrueValue()
-}
-
-func (js *jsre) backtrace(call otto.FunctionCall) otto.Value {
- tracestr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- glog.GetTraceLocation().Set(tracestr)
-
- return otto.UndefinedValue()
-}
-
-func (js *jsre) verbosity(call otto.FunctionCall) otto.Value {
- v, err := call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- glog.SetV(int(v))
- return otto.UndefinedValue()
-}
-
-func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
- var (
- threads int64
- err error
- )
-
- if len(call.ArgumentList) > 0 {
- threads, err = call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- } else {
- threads = int64(js.ethereum.MinerThreads)
- }
-
- // switch on DAG autogeneration when miner starts
- js.ethereum.StartAutoDAG()
-
- err = js.ethereum.StartMining(int(threads))
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
- js.ethereum.StopMining()
- js.ethereum.StopAutoDAG()
- 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()
- }
-
- corsDomain := js.corsDomain
- if len(call.ArgumentList) > 2 {
- corsDomain, err = call.Argument(2).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- }
-
- config := rpc.RpcConfig{
- ListenAddress: addr,
- ListenPort: uint(port),
- CorsDomain: corsDomain,
- }
-
- xeth := xeth.New(js.ethereum, nil)
- err = rpc.Start(xeth, config)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-func (js *jsre) stopRPC(call otto.FunctionCall) otto.Value {
- if rpc.Stop() == nil {
- return otto.TrueValue()
- }
- return otto.FalseValue()
-}
-
-func (js *jsre) addPeer(call otto.FunctionCall) otto.Value {
- nodeURL, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- err = js.ethereum.AddPeer(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()
- }
- if seconds == 0 {
- seconds = accounts.DefaultAccountUnlockDuration
- }
-
- arg := call.Argument(1)
- var passphrase string
- if arg.IsUndefined() {
- fmt.Println("Please enter a passphrase now.")
- passphrase, err = utils.PromptPassword("Passphrase: ", true)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- } else {
- passphrase, err = arg.ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- }
- am := js.ethereum.AccountManager()
- err = am.TimedUnlock(common.HexToAddress(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 := utils.PromptPassword("Passphrase: ", true)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- confirm, err := utils.PromptPassword("Repeat Passphrase: ", false)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if auth != confirm {
- fmt.Println("Passphrases did not match.")
- return otto.FalseValue()
- }
- 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()
- }
- v, _ := call.Otto.ToValue(acct.Address.Hex())
- return v
-}
-
-func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
- v, _ := call.Otto.ToValue(js.ethereum.NodeInfo())
- return v
-}
-
-func (js *jsre) peers(call otto.FunctionCall) otto.Value {
- v, _ := call.Otto.ToValue(js.ethereum.PeersInfo())
- return v
-}
-
-func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("require file name. admin.importChain(filename)")
- return otto.FalseValue()
- }
- fn, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if err := utils.ImportChain(js.ethereum.ChainManager(), fn); err != nil {
- fmt.Println("Import error: ", err)
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("require file name: admin.exportChain(filename)")
- return otto.FalseValue()
- }
-
- fn, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) printBlock(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- fmt.Println(block)
-
- return otto.UndefinedValue()
-}
-
-func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- statedb := state.New(block.Root(), js.ethereum.StateDb())
- dump := statedb.RawDump()
- v, _ := call.Otto.ToValue(dump)
- return v
-}
-
-func (js *jsre) waitForBlocks(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) > 2 {
- fmt.Println("requires 0, 1 or 2 arguments: admin.debug.waitForBlock(minHeight, timeout)")
- return otto.FalseValue()
- }
- var n, timeout int64
- var timer <-chan time.Time
- var height *big.Int
- var err error
- args := len(call.ArgumentList)
- if args == 2 {
- timeout, err = call.Argument(1).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- timer = time.NewTimer(time.Duration(timeout) * time.Second).C
- }
- if args >= 1 {
- n, err = call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- height = big.NewInt(n)
- }
-
- if args == 0 {
- height = js.xeth.CurrentBlock().Number()
- height.Add(height, common.Big1)
- }
-
- wait := js.wait
- js.wait <- height
- select {
- case <-timer:
- // if times out make sure the xeth loop does not block
- go func() {
- select {
- case wait <- nil:
- case <-wait:
- }
- }()
- return otto.UndefinedValue()
- case height = <-wait:
- }
- v, _ := call.Otto.ToValue(height.Uint64())
- return v
-}
-
-func (js *jsre) sleep(call otto.FunctionCall) otto.Value {
- sec, err := call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- time.Sleep(time.Duration(sec) * time.Second)
- return otto.UndefinedValue()
-}
-
-func (js *jsre) setSolc(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 1 {
- fmt.Println("needs 1 argument: admin.contractInfo.setSolc(solcPath)")
- return otto.FalseValue()
- }
- solcPath, err := call.Argument(0).ToString()
- if err != nil {
- return otto.FalseValue()
- }
- solc, err := js.xeth.SetSolc(solcPath)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- fmt.Println(solc.Info())
- return otto.TrueValue()
-}
-
-func (js *jsre) register(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 4 {
- fmt.Println("requires 4 arguments: admin.contractInfo.register(fromaddress, contractaddress, contract, filename)")
- return otto.UndefinedValue()
- }
- sender, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- address, err := call.Argument(1).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- raw, err := call.Argument(2).Export()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- jsonraw, err := json.Marshal(raw)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- var contract compiler.Contract
- err = json.Unmarshal(jsonraw, &contract)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- filename, err := call.Argument(3).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- contenthash, err := compiler.ExtractInfo(&contract, filename)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- // sender and contract address are passed as hex strings
- codeb := js.xeth.CodeAtBytes(address)
- codehash := common.BytesToHash(crypto.Sha3(codeb))
-
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- registry := resolver.New(js.xeth)
-
- _, err = registry.RegisterContentHash(common.HexToAddress(sender), codehash, contenthash)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- v, _ := call.Otto.ToValue(contenthash.Hex())
- return v
-}
-
-func (js *jsre) registerUrl(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 3 {
- fmt.Println("requires 3 arguments: admin.contractInfo.register(fromaddress, contenthash, filename)")
- return otto.FalseValue()
- }
- sender, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- contenthash, err := call.Argument(1).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- url, err := call.Argument(2).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- registry := resolver.New(js.xeth)
-
- _, err = registry.RegisterUrl(common.HexToAddress(sender), common.HexToHash(contenthash), url)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-func (js *jsre) getContractInfo(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 1 {
- fmt.Println("requires 1 argument: admin.contractInfo.register(contractaddress)")
- return otto.FalseValue()
- }
- addr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- infoDoc, err := natspec.FetchDocsForContract(addr, js.xeth, ds)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- var info compiler.ContractInfo
- err = json.Unmarshal(infoDoc, &info)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(info)
- return v
-}
-
-func (js *jsre) startNatSpec(call otto.FunctionCall) otto.Value {
- js.ethereum.NatSpec = true
- return otto.TrueValue()
-}
-
-func (js *jsre) stopNatSpec(call otto.FunctionCall) otto.Value {
- js.ethereum.NatSpec = false
- return otto.TrueValue()
-}
-
-func (js *jsre) newRegistry(call otto.FunctionCall) otto.Value {
-
- if len(call.ArgumentList) != 1 {
- fmt.Println("requires 1 argument: admin.contractInfo.newRegistry(adminaddress)")
- return otto.FalseValue()
- }
- addr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- registry := resolver.New(js.xeth)
- err = registry.CreateContracts(common.HexToAddress(addr))
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-// internal transaction type which will allow us to resend transactions using `eth.resend`
-type tx struct {
- tx *types.Transaction
-
- To string
- From string
- Nonce string
- Value string
- Data string
- GasLimit string
- GasPrice string
-}
-
-func newTx(t *types.Transaction) *tx {
- from, _ := t.From()
- var to string
- if t := t.To(); t != nil {
- to = t.Hex()
- }
-
- return &tx{
- tx: t,
- To: to,
- From: from.Hex(),
- Value: t.Amount.String(),
- Nonce: strconv.Itoa(int(t.Nonce())),
- Data: "0x" + common.Bytes2Hex(t.Data()),
- GasLimit: t.GasLimit.String(),
- GasPrice: t.GasPrice().String(),
- }
-}
diff --git a/cmd/geth/js.go b/cmd/geth/js.go
index 7e6e10ca9..2ae4817b3 100644
--- a/cmd/geth/js.go
+++ b/cmd/geth/js.go
@@ -33,6 +33,10 @@ import (
"github.com/ethereum/go-ethereum/eth"
re "github.com/ethereum/go-ethereum/jsre"
"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"
@@ -70,10 +74,70 @@ type jsre struct {
ps1 string
atexit func()
corsDomain string
+ client comms.EthereumClient
prompter
}
-func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, interactive bool, f xeth.Frontend) *jsre {
+var (
+ loadedModulesMethods map[string][]string
+)
+
+func keywordCompleter(line string) []string {
+ results := make([]string, 0)
+
+ 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)
+ }
+ }
+ }
+ }
+ } 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)
+ }
+ }
+ }
+ return results
+}
+
+func apiWordCompleter(line string, pos int) (head string, completions []string, tail string) {
+ if len(line) == 0 {
+ return "", nil, ""
+ }
+
+ 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
+}
+
+func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
js := &jsre{ethereum: ethereum, ps1: "> "}
// set default cors domain used by startRpc from CLI flag
js.corsDomain = corsDomain
@@ -82,10 +146,16 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, intera
}
js.xeth = xeth.New(ethereum, f)
js.wait = js.xeth.UpdateState()
+ js.client = client
+ if clt, ok := js.client.(*comms.InProcClient); ok {
+ clt.Initialize(js.xeth, ethereum)
+ }
+
// update state in separare forever blocks
js.re = re.New(libPath)
- js.apiBindings(ipcpath, f)
- js.adminBindings()
+ if err := js.apiBindings(f); err != nil {
+ utils.Fatalf("Unable to connect - %v", err)
+ }
if !liner.TerminalSupported() || !interactive {
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
@@ -93,6 +163,9 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, intera
lr := liner.NewLiner()
js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
lr.SetCtrlCAborts(true)
+ js.loadAutoCompletion()
+ lr.SetWordCompleter(apiWordCompleter)
+ lr.SetTabCompletionStyle(liner.TabPrints)
js.prompter = lr
js.atexit = func() {
js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
@@ -103,8 +176,117 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, intera
return js
}
+func (self *jsre) loadAutoCompletion() {
+ if modules, err := self.suportedApis(); err == nil {
+ loadedModulesMethods = make(map[string][]string)
+ for module, _ := range modules {
+ loadedModulesMethods[module] = api.AutoCompletion[module]
+ }
+ }
+}
+
+func (self *jsre) suportedApis() (map[string]string, error) {
+ req := shared.Request{
+ Id: 1,
+ Jsonrpc: "2.0",
+ Method: "modules",
+ }
+
+ err := self.client.Send(&req)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := self.client.Recv()
+ if err != nil {
+ return nil, err
+ }
+
+ if sucRes, ok := res.(map[string]string); ok {
+ if err == nil {
+ return sucRes, nil
+ }
+ }
+
+ return nil, fmt.Errorf("Unable to determine supported API's")
+}
+
+func (js *jsre) apiBindings(f xeth.Frontend) error {
+ apis, err := js.suportedApis()
+ if err != nil {
+ return err
+ }
+
+ apiNames := make([]string, 0, len(apis))
+ for a, _ := range apis {
+ apiNames = append(apiNames, a)
+ }
+
+ apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum)
+ if err != nil {
+ utils.Fatalf("Unable to determine supported api's: %v", err)
+ }
+
+ jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client)
+ js.re.Set("jeth", struct{}{})
+ t, _ := js.re.Get("jeth")
+ jethObj := t.Object()
+
+ jethObj.Set("send", jeth.Send)
+ jethObj.Set("sendAsync", jeth.Send)
+
+ err = js.re.Compile("bignumber.js", re.BigNumber_JS)
+ if err != nil {
+ utils.Fatalf("Error loading bignumber.js: %v", err)
+ }
+
+ err = js.re.Compile("ethereum.js", re.Web3_JS)
+ if err != nil {
+ utils.Fatalf("Error loading web3.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)
+ }
+
+ // load only supported API's in javascript runtime
+ shortcuts := "var eth = web3.eth; "
+ for _, apiName := range apiNames {
+ if apiName == api.Web3ApiName || apiName == api.EthApiName {
+ continue // manually mapped
+ }
+
+ 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)
+ }
+ }
+
+ _, err = js.re.Eval(shortcuts)
+
+ if err != nil {
+ utils.Fatalf("Error setting namespaces: %v", err)
+ }
+
+ js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");")
+ return nil
+}
+
+/*
func (js *jsre) apiBindings(ipcpath string, f xeth.Frontend) {
xe := xeth.New(js.ethereum, f)
+ apiNames, err := js.suportedApis(ipcpath)
+ if err != nil {
+ return
+ }
+
ethApi := rpc.NewEthereumApi(xe)
jeth := rpc.NewJeth(ethApi, js.re, ipcpath)
@@ -146,6 +328,7 @@ var net = web3.net;
js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");")
}
+*/
var ds, _ = docserver.New("/")
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 43e45f6cc..5c4c33cea 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -38,6 +38,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/rpc/codec"
+ "github.com/ethereum/go-ethereum/rpc/comms"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
)
@@ -310,12 +312,14 @@ func console(ctx *cli.Context) {
utils.Fatalf("%v", err)
}
+ client := comms.NewInProcClient(codec.JSON)
+
startEth(ctx, ethereum)
repl := newJSRE(
ethereum,
ctx.String(utils.JSpathFlag.Name),
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
- utils.IpcSocketPath(ctx),
+ client,
true,
nil,
)
@@ -332,12 +336,13 @@ func execJSFiles(ctx *cli.Context) {
utils.Fatalf("%v", err)
}
+ client := comms.NewInProcClient(codec.JSON)
startEth(ctx, ethereum)
repl := newJSRE(
ethereum,
ctx.String(utils.JSpathFlag.Name),
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
- utils.IpcSocketPath(ctx),
+ client,
false,
nil,
)