aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/geth/admin.go
diff options
context:
space:
mode:
authorzelig <viktor.tron@gmail.com>2015-04-23 06:11:11 +0800
committerzelig <viktor.tron@gmail.com>2015-05-07 18:58:21 +0800
commit009b2216921b15962f2612687c1460a8342d49d6 (patch)
tree4adbbaccdb83a3ea55034f1681d01132452ff48d /cmd/geth/admin.go
parent97c37356fdcfac8b704c3d75b33e322a737c4e55 (diff)
downloadgo-tangerine-009b2216921b15962f2612687c1460a8342d49d6.tar.gz
go-tangerine-009b2216921b15962f2612687c1460a8342d49d6.tar.zst
go-tangerine-009b2216921b15962f2612687c1460a8342d49d6.zip
solidity compiler and contract metadocs integration
* common/compiler: solidity compiler + tests * rpc: eth_compilers, eth_compileSolidity + tests * fix natspec test using keystore API, notice exp dynamically changes addr, cleanup * resolver implements registrars and needs to create reg contract (temp) * xeth: solidity compiler. expose getter Solc() and paths setter SetSolc(solcPath) * ethereumApi: implement compiler related RPC calls using XEth - json struct tests * admin: make use of XEth.SetSolc to allow runtime setting of compiler paths * cli: command line flags solc to set custom solc bin path * js admin api with new features debug and contractInfo modules * wiki is the doc https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions
Diffstat (limited to 'cmd/geth/admin.go')
-rw-r--r--cmd/geth/admin.go346
1 files changed, 285 insertions, 61 deletions
diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go
index f15ce89a0..49e2dc6f8 100644
--- a/cmd/geth/admin.go
+++ b/cmd/geth/admin.go
@@ -1,16 +1,22 @@
package main
import (
+ "encoding/json"
"errors"
"fmt"
+ "math/big"
"strconv"
"time"
"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"
@@ -43,6 +49,19 @@ func (js *jsre) adminBindings() {
admin.Set("export", js.exportChain)
admin.Set("verbosity", js.verbosity)
admin.Set("progress", js.downloadProgress)
+ 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")
@@ -55,14 +74,21 @@ func (js *jsre) adminBindings() {
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)
+ // 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 {
@@ -75,10 +101,14 @@ func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
} else {
return nil, errors.New("invalid argument for dump. Either hex string or number")
}
- return block, nil
+ } else {
+ block = js.ethereum.ChainManager().CurrentBlock()
}
- return nil, errors.New("requires block number or block hash as argument")
+ if block == nil {
+ return nil, errors.New("block not found")
+ }
+ return block, nil
}
func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
@@ -152,11 +182,6 @@ func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
return otto.UndefinedValue()
}
- if block == nil {
- fmt.Println("block not found")
- return otto.UndefinedValue()
- }
-
old := vm.Debug
vm.Debug = true
_, err = js.ethereum.BlockProcessor().RetryProcess(block)
@@ -175,11 +200,6 @@ func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
return otto.UndefinedValue()
}
- if block == nil {
- fmt.Println("block not found")
- return otto.UndefinedValue()
- }
-
js.ethereum.ChainManager().SetHead(block)
return otto.UndefinedValue()
}
@@ -196,12 +216,6 @@ func (js *jsre) getBlockRlp(call otto.FunctionCall) otto.Value {
fmt.Println(err)
return otto.UndefinedValue()
}
-
- if block == nil {
- fmt.Println("block not found")
- return otto.UndefinedValue()
- }
-
encoded, _ := rlp.EncodeToBytes(block)
return js.re.ToVal(fmt.Sprintf("%x", encoded))
}
@@ -255,11 +269,13 @@ func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
return otto.FalseValue()
}
// threads now ignored
+
err = js.ethereum.StartMining()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
+
return otto.TrueValue()
}
@@ -298,9 +314,8 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
xeth := xeth.New(js.ethereum, nil)
err = rpc.Start(xeth, config)
-
if err != nil {
- fmt.Printf(err.Error())
+ fmt.Println(err)
return otto.FalseValue()
}
@@ -345,7 +360,8 @@ func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
fmt.Println("Please enter a passphrase now.")
passphrase, err = readPassword("Passphrase: ", true)
if err != nil {
- utils.Fatalf("%v", err)
+ fmt.Println(err)
+ return otto.FalseValue()
}
} else {
passphrase, err = arg.ToString()
@@ -371,14 +387,17 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
fmt.Println("Please enter a passphrase now.")
auth, err := readPassword("Passphrase: ", true)
if err != nil {
- utils.Fatalf("%v", err)
+ fmt.Println(err)
+ return otto.FalseValue()
}
confirm, err := readPassword("Repeat Passphrase: ", false)
if err != nil {
- utils.Fatalf("%v", err)
+ fmt.Println(err)
+ return otto.FalseValue()
}
if auth != confirm {
- utils.Fatalf("Passphrases did not match.")
+ fmt.Println("Passphrases did not match.")
+ return otto.FalseValue()
}
passphrase = auth
} else {
@@ -394,7 +413,7 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
fmt.Printf("Could not create the account: %v", err)
return otto.UndefinedValue()
}
- return js.re.ToVal("0x" + common.Bytes2Hex(acct.Address))
+ return js.re.ToVal(common.ToHex(acct.Address))
}
func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
@@ -407,7 +426,7 @@ func (js *jsre) peers(call otto.FunctionCall) otto.Value {
func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) == 0 {
- fmt.Println("err: require file name")
+ fmt.Println("require file name. admin.importChain(filename)")
return otto.FalseValue()
}
fn, err := call.Argument(0).ToString()
@@ -424,7 +443,7 @@ func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) == 0 {
- fmt.Println("err: require file name")
+ fmt.Println("require file name: admin.exportChain(filename)")
return otto.FalseValue()
}
@@ -441,23 +460,9 @@ func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
}
func (js *jsre) printBlock(call otto.FunctionCall) otto.Value {
- var block *types.Block
- if len(call.ArgumentList) > 0 {
- if call.Argument(0).IsNumber() {
- num, _ := call.Argument(0).ToInteger()
- block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
- } else if call.Argument(0).IsString() {
- hash, _ := call.Argument(0).ToString()
- block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
- } else {
- fmt.Println("invalid argument for dump. Either hex string or number")
- }
-
- } else {
- block = js.ethereum.ChainManager().CurrentBlock()
- }
- if block == nil {
- fmt.Println("block not found")
+ block, err := js.getBlock(call)
+ if err != nil {
+ fmt.Println(err)
return otto.UndefinedValue()
}
@@ -467,30 +472,249 @@ func (js *jsre) printBlock(call otto.FunctionCall) otto.Value {
}
func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
- var block *types.Block
- if len(call.ArgumentList) > 0 {
- if call.Argument(0).IsNumber() {
- num, _ := call.Argument(0).ToInteger()
- block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
- } else if call.Argument(0).IsString() {
- hash, _ := call.Argument(0).ToString()
- block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
- } else {
- fmt.Println("invalid argument for dump. Either hex string or number")
- }
-
- } else {
- block = js.ethereum.ChainManager().CurrentBlock()
- }
- if block == nil {
- fmt.Println("block not found")
+ 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()
return js.re.ToVal(dump)
+}
+
+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:
+ }
+ return js.re.ToVal(height.Uint64())
+}
+
+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()
+ }
+
+ return js.re.ToVal(contenthash.Hex())
+
+}
+
+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()
+ }
+ return js.re.ToVal(info)
+}
+
+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`