From 719a23c6f667871f9d015094aaaf3d9c754d8727 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Wed, 3 Jun 2015 12:27:05 +0200 Subject: [PATCH] added admin api --- cmd/console/admin.go | 803 +----------------------------- cmd/utils/flags.go | 3 +- miner/miner.go | 12 +- rpc/api/admin.go | 48 ++ rpc/api/admin_args.go | 1 + rpc/api/api.go | 4 +- rpc/api/errors.go | 11 - rpc/api/eth_args.go | 835 ++++++++++++++++++++++++++++++++ rpc/api/miner.go | 138 ++++++ rpc/api/miner_args.go | 47 ++ rpc/api/types.go | 1 + rpc/api/web3.go | 2 +- rpc/api/web3_args.go | 5 + rpc/shared/{api.go => types.go} | 0 14 files changed, 1108 insertions(+), 802 deletions(-) create mode 100644 rpc/api/admin.go create mode 100644 rpc/api/admin_args.go delete mode 100644 rpc/api/errors.go create mode 100644 rpc/api/eth_args.go create mode 100644 rpc/api/miner.go create mode 100644 rpc/api/miner_args.go create mode 100644 rpc/api/types.go create mode 100644 rpc/api/web3_args.go rename rpc/shared/{api.go => types.go} (100%) diff --git a/cmd/console/admin.go b/cmd/console/admin.go index 2fe5d02b43..46a4b349a8 100644 --- a/cmd/console/admin.go +++ b/cmd/console/admin.go @@ -5,6 +5,23 @@ node admin bindings */ func (js *jsre) adminBindings() { + + js.re.Set("admin", struct{}{}) + t, _ := js.re.Get("admin") + admin := t.Object() + + 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) + /* ethO, _ := js.re.Get("eth") eth := ethO.Object() @@ -40,17 +57,7 @@ func (js *jsre) adminBindings() { 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("debug", struct{}{}) t, _ = admin.Get("debug") @@ -67,777 +74,3 @@ func (js *jsre) adminBindings() { 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) 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 { - // no need to check err - 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() - } - - old := vm.Debug - vm.Debug = true - _, err = js.ethereum.BlockProcessor().RetryProcess(block) - if err != nil { - fmt.Println(err) - } - vm.Debug = old - - fmt.Println("ok") - return otto.UndefinedValue() -} - -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) downloadProgress(call otto.FunctionCall) otto.Value { - pending, cached := js.ethereum.Downloader().Stats() - v, _ := call.Otto.ToValue(map[string]interface{}{"pending": pending, "cached": cached}) - 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/utils/flags.go b/cmd/utils/flags.go index 5f177faef6..57bc17c569 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -392,8 +392,9 @@ func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error { web3Api := api.NewWeb3(xeth, codec) ethApi := api.NewEth(xeth, codec) netApi := api.NewNet(xeth, codec) + minerApi := api.NewMiner(eth, codec) - return comms.StartIpc(config, codec, web3Api, ethApi, netApi) + return comms.StartIpc(config, codec, web3Api, ethApi, netApi, minerApi) } func StartPProf(ctx *cli.Context) { diff --git a/miner/miner.go b/miner/miner.go index 20ca81648a..f6241d58c3 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -13,6 +13,11 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/pow" + "fmt" +) + +const ( + MAX_EXTRA_DATA_SIZE = 1024 ) type Miner struct { @@ -126,8 +131,13 @@ func (self *Miner) HashRate() int64 { return self.pow.GetHashrate() } -func (self *Miner) SetExtra(extra []byte) { +func (self *Miner) SetExtra(extra []byte) error { + if len(extra) > MAX_EXTRA_DATA_SIZE { + return fmt.Errorf("Miner extra data cannot exceed %d bytes", MAX_EXTRA_DATA_SIZE) + } + self.worker.extra = extra + return nil } func (self *Miner) PendingState() *state.StateDB { diff --git a/rpc/api/admin.go b/rpc/api/admin.go new file mode 100644 index 0000000000..c2f2dea41f --- /dev/null +++ b/rpc/api/admin.go @@ -0,0 +1,48 @@ +package api + +import ( + ethereum "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/rpc/codec" + "github.com/ethereum/go-ethereum/rpc/shared" +) + +const ( + AdminVersion = "1.0.0" +) + +var ( + // mapping between methods and handlers + AdminMapping = map[string]adminhandler{ + //"admin_startMiner": (*admin).StartMiner, + } +) + +// admin callback handler +type adminhandler func(*admin, *shared.Request) (interface{}, error) + +// admin api provider +type admin struct { + ethereum ethereum.Ethereum + methods map[string]adminhandler + codec codec.ApiCoder +} + +// create a new admin api instance +func NewAdmin(ethereum ethereum.Ethereum, coder codec.Codec) *admin { + return &admin{ + ethereum: ethereum, + methods: AdminMapping, + codec: coder.New(nil), + } +} + +// collection with supported methods +func (self *admin) Methods() []string { + methods := make([]string, len(self.methods)) + i := 0 + for k := range self.methods { + methods[i] = k + i++ + } + return methods +} diff --git a/rpc/api/admin_args.go b/rpc/api/admin_args.go new file mode 100644 index 0000000000..778f64ec17 --- /dev/null +++ b/rpc/api/admin_args.go @@ -0,0 +1 @@ +package api diff --git a/rpc/api/api.go b/rpc/api/api.go index 08ab75d2a8..0e1e844f76 100644 --- a/rpc/api/api.go +++ b/rpc/api/api.go @@ -1,8 +1,6 @@ package api -import ( - "github.com/ethereum/go-ethereum/rpc/shared" -) +import "github.com/ethereum/go-ethereum/rpc/shared" // Descriptor for all API implementations type Ethereum interface { diff --git a/rpc/api/errors.go b/rpc/api/errors.go deleted file mode 100644 index ede99a58e7..0000000000 --- a/rpc/api/errors.go +++ /dev/null @@ -1,11 +0,0 @@ -package api - -import "fmt" - -type NotImplementedError struct { - Method string -} - -func (e *NotImplementedError) Error() string { - return fmt.Sprintf("%s method not implemented", e.Method) -} diff --git a/rpc/api/eth_args.go b/rpc/api/eth_args.go new file mode 100644 index 0000000000..1ef6f9efbe --- /dev/null +++ b/rpc/api/eth_args.go @@ -0,0 +1,835 @@ +package api + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/rpc/shared" +) + +const ( + defaultLogLimit = 100 + defaultLogOffset = 0 +) + +type GetBalanceArgs struct { + Address string + BlockNumber int64 +} + +func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("address", "not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockHeight(obj[1], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type GetStorageArgs struct { + Address string + BlockNumber int64 +} + +func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("address", "not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockHeight(obj[1], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type GetStorageAtArgs struct { + Address string + BlockNumber int64 + Key string +} + +func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 2 { + return shared.NewInsufficientParamsError(len(obj), 2) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("address", "not a string") + } + args.Address = addstr + + keystr, ok := obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("key", "not a string") + } + args.Key = keystr + + if len(obj) > 2 { + if err := blockHeight(obj[2], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type GetTxCountArgs struct { + Address string + BlockNumber int64 +} + +func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("address", "not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockHeight(obj[1], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type HashArgs struct { + Hash string +} + +func (args *HashArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + arg0, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("hash", "not a string") + } + args.Hash = arg0 + + return nil +} + +type BlockNumArg struct { + BlockNumber int64 +} + +func (args *BlockNumArg) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + if err := blockHeight(obj[0], &args.BlockNumber); err != nil { + return err + } + + return nil +} + +type GetDataArgs struct { + Address string + BlockNumber int64 +} + +func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("address", "not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockHeight(obj[1], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type NewSignArgs struct { + From string + Data string +} + +func (args *NewSignArgs) UnmarshalJSON(b []byte) (err error) { + var obj []json.RawMessage + var ext struct { + From string + Data string + } + + // Decode byte slice to array of RawMessages + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + // Check for sufficient params + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + // Decode 0th RawMessage to temporary struct + if err := json.Unmarshal(obj[0], &ext); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(ext.From) == 0 { + return shared.NewValidationError("from", "is required") + } + + if len(ext.Data) == 0 { + return shared.NewValidationError("data", "is required") + } + + args.From = ext.From + args.Data = ext.Data + return nil +} + +type NewTxArgs struct { + From string + To string + Nonce *big.Int + Value *big.Int + Gas *big.Int + GasPrice *big.Int + Data string + + BlockNumber int64 +} + +func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { + var obj []json.RawMessage + var ext struct { + From string + To string + Nonce interface{} + Value interface{} + Gas interface{} + GasPrice interface{} + Data string + } + + // Decode byte slice to array of RawMessages + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + // Check for sufficient params + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + // Decode 0th RawMessage to temporary struct + if err := json.Unmarshal(obj[0], &ext); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(ext.From) == 0 { + return shared.NewValidationError("from", "is required") + } + + args.From = ext.From + args.To = ext.To + args.Data = ext.Data + + var num *big.Int + if ext.Nonce != nil { + num, err = numString(ext.Nonce) + if err != nil { + return err + } + } + args.Nonce = num + + if ext.Value == nil { + num = big.NewInt(0) + } else { + num, err = numString(ext.Value) + if err != nil { + return err + } + } + args.Value = num + + num = nil + if ext.Gas == nil { + num = big.NewInt(0) + } else { + if num, err = numString(ext.Gas); err != nil { + return err + } + } + args.Gas = num + + num = nil + if ext.GasPrice == nil { + num = big.NewInt(0) + } else { + if num, err = numString(ext.GasPrice); err != nil { + return err + } + } + args.GasPrice = num + + // Check for optional BlockNumber param + if len(obj) > 1 { + if err := blockHeightFromJson(obj[1], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type SourceArgs struct { + Source string +} + +func (args *SourceArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + arg0, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("source code", "not a string") + } + args.Source = arg0 + + return nil +} + +type CallArgs struct { + From string + To string + Value *big.Int + Gas *big.Int + GasPrice *big.Int + Data string + + BlockNumber int64 +} + +func (args *CallArgs) UnmarshalJSON(b []byte) (err error) { + var obj []json.RawMessage + var ext struct { + From string + To string + Value interface{} + Gas interface{} + GasPrice interface{} + Data string + } + + // Decode byte slice to array of RawMessages + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + // Check for sufficient params + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + // Decode 0th RawMessage to temporary struct + if err := json.Unmarshal(obj[0], &ext); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + args.From = ext.From + + if len(ext.To) == 0 { + return shared.NewValidationError("to", "is required") + } + args.To = ext.To + + var num *big.Int + if ext.Value == nil { + num = big.NewInt(0) + } else { + if num, err = numString(ext.Value); err != nil { + return err + } + } + args.Value = num + + if ext.Gas == nil { + num = big.NewInt(0) + } else { + if num, err = numString(ext.Gas); err != nil { + return err + } + } + args.Gas = num + + if ext.GasPrice == nil { + num = big.NewInt(0) + } else { + if num, err = numString(ext.GasPrice); err != nil { + return err + } + } + args.GasPrice = num + + args.Data = ext.Data + + // Check for optional BlockNumber param + if len(obj) > 1 { + if err := blockHeightFromJson(obj[1], &args.BlockNumber); err != nil { + return err + } + } else { + args.BlockNumber = -1 + } + + return nil +} + +type HashIndexArgs struct { + Hash string + Index int64 +} + +func (args *HashIndexArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 2 { + return shared.NewInsufficientParamsError(len(obj), 2) + } + + arg0, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("hash", "not a string") + } + args.Hash = arg0 + + arg1, ok := obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("index", "not a string") + } + args.Index = common.Big(arg1).Int64() + + return nil +} + +type BlockNumIndexArgs struct { + BlockNumber int64 + Index int64 +} + +func (args *BlockNumIndexArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 2 { + return shared.NewInsufficientParamsError(len(obj), 2) + } + + if err := blockHeight(obj[0], &args.BlockNumber); err != nil { + return err + } + + var arg1 *big.Int + if arg1, err = numString(obj[1]); err != nil { + return err + } + args.Index = arg1.Int64() + + return nil +} + +type GetBlockByHashArgs struct { + BlockHash string + IncludeTxs bool +} + +func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 2 { + return shared.NewInsufficientParamsError(len(obj), 2) + } + + argstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("blockHash", "not a string") + } + args.BlockHash = argstr + + args.IncludeTxs = obj[1].(bool) + + return nil +} + +type GetBlockByNumberArgs struct { + BlockNumber int64 + IncludeTxs bool +} + +func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 2 { + return shared.NewInsufficientParamsError(len(obj), 2) + } + + if err := blockHeight(obj[0], &args.BlockNumber); err != nil { + return err + } + + args.IncludeTxs = obj[1].(bool) + + return nil +} + +type BlockFilterArgs struct { + Earliest int64 + Latest int64 + Address []string + Topics [][]string + Skip int + Max int +} + +func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) { + var obj []struct { + FromBlock interface{} `json:"fromBlock"` + ToBlock interface{} `json:"toBlock"` + Limit interface{} `json:"limit"` + Offset interface{} `json:"offset"` + Address interface{} `json:"address"` + Topics interface{} `json:"topics"` + } + + if err = json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + // args.Earliest, err = toNumber(obj[0].ToBlock) + // if err != nil { + // return shared.NewDecodeParamError(fmt.Sprintf("FromBlock %v", err)) + // } + // args.Latest, err = toNumber(obj[0].FromBlock) + // if err != nil { + // return shared.NewDecodeParamError(fmt.Sprintf("ToBlock %v", err)) + + var num int64 + var numBig *big.Int + + // if blank then latest + if obj[0].FromBlock == nil { + num = -1 + } else { + if err := blockHeight(obj[0].FromBlock, &num); err != nil { + return err + } + } + // if -2 or other "silly" number, use latest + if num < 0 { + args.Earliest = -1 //latest block + } else { + args.Earliest = num + } + + // if blank than latest + if obj[0].ToBlock == nil { + num = -1 + } else { + if err := blockHeight(obj[0].ToBlock, &num); err != nil { + return err + } + } + args.Latest = num + + if obj[0].Limit == nil { + numBig = big.NewInt(defaultLogLimit) + } else { + if numBig, err = numString(obj[0].Limit); err != nil { + return err + } + } + args.Max = int(numBig.Int64()) + + if obj[0].Offset == nil { + numBig = big.NewInt(defaultLogOffset) + } else { + if numBig, err = numString(obj[0].Offset); err != nil { + return err + } + } + args.Skip = int(numBig.Int64()) + + if obj[0].Address != nil { + marg, ok := obj[0].Address.([]interface{}) + if ok { + v := make([]string, len(marg)) + for i, arg := range marg { + argstr, ok := arg.(string) + if !ok { + return shared.NewInvalidTypeError(fmt.Sprintf("address[%d]", i), "is not a string") + } + v[i] = argstr + } + args.Address = v + } else { + argstr, ok := obj[0].Address.(string) + if ok { + v := make([]string, 1) + v[0] = argstr + args.Address = v + } else { + return shared.NewInvalidTypeError("address", "is not a string or array") + } + } + } + + if obj[0].Topics != nil { + other, ok := obj[0].Topics.([]interface{}) + if ok { + topicdbl := make([][]string, len(other)) + for i, iv := range other { + if argstr, ok := iv.(string); ok { + // Found a string, push into first element of array + topicsgl := make([]string, 1) + topicsgl[0] = argstr + topicdbl[i] = topicsgl + } else if argarray, ok := iv.([]interface{}); ok { + // Found an array of other + topicdbl[i] = make([]string, len(argarray)) + for j, jv := range argarray { + if v, ok := jv.(string); ok { + topicdbl[i][j] = v + } else if jv == nil { + topicdbl[i][j] = "" + } else { + return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", i, j), "is not a string") + } + } + } else if iv == nil { + topicdbl[i] = []string{""} + } else { + return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d]", i), "not a string or array") + } + } + args.Topics = topicdbl + return nil + } else { + return shared.NewInvalidTypeError("topic", "is not a string or array") + } + } + + return nil +} + +type FilterIdArgs struct { + Id int +} + +func (args *FilterIdArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return shared.NewInsufficientParamsError(len(obj), 1) + } + + var num *big.Int + if num, err = numString(obj[0]); err != nil { + return err + } + args.Id = int(num.Int64()) + + return nil +} + +type LogRes struct { + Address *hexdata `json:"address"` + Topics []*hexdata `json:"topics"` + Data *hexdata `json:"data"` + BlockNumber *hexnum `json:"blockNumber"` + LogIndex *hexnum `json:"logIndex"` + BlockHash *hexdata `json:"blockHash"` + TransactionHash *hexdata `json:"transactionHash"` + TransactionIndex *hexnum `json:"transactionIndex"` +} + +func NewLogRes(log *state.Log) LogRes { + var l LogRes + l.Topics = make([]*hexdata, len(log.Topics)) + for j, topic := range log.Topics { + l.Topics[j] = newHexData(topic) + } + l.Address = newHexData(log.Address) + l.Data = newHexData(log.Data) + l.BlockNumber = newHexNum(log.Number) + l.LogIndex = newHexNum(log.Index) + l.TransactionHash = newHexData(log.TxHash) + l.TransactionIndex = newHexNum(log.TxIndex) + l.BlockHash = newHexData(log.BlockHash) + + return l +} + +func NewLogsRes(logs state.Logs) (ls []LogRes) { + ls = make([]LogRes, len(logs)) + + for i, log := range logs { + ls[i] = NewLogRes(log) + } + + return +} + +func NewHashesRes(hs []common.Hash) []string { + hashes := make([]string, len(hs)) + + for i, hash := range hs { + hashes[i] = hash.Hex() + } + + return hashes +} + +type SubmitWorkArgs struct { + Nonce uint64 + Header string + Digest string +} + +func (args *SubmitWorkArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err = json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) < 3 { + return shared.NewInsufficientParamsError(len(obj), 3) + } + + var objstr string + var ok bool + if objstr, ok = obj[0].(string); !ok { + return shared.NewInvalidTypeError("nonce", "not a string") + } + + args.Nonce = common.String2Big(objstr).Uint64() + if objstr, ok = obj[1].(string); !ok { + return shared.NewInvalidTypeError("header", "not a string") + } + + args.Header = objstr + + if objstr, ok = obj[2].(string); !ok { + return shared.NewInvalidTypeError("digest", "not a string") + } + + args.Digest = objstr + + return nil +} diff --git a/rpc/api/miner.go b/rpc/api/miner.go new file mode 100644 index 0000000000..058f682e98 --- /dev/null +++ b/rpc/api/miner.go @@ -0,0 +1,138 @@ +package api + +import ( + "github.com/ethereum/ethash" + "github.com/ethereum/go-ethereum/common" + ethereum "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/rpc/codec" + "github.com/ethereum/go-ethereum/rpc/shared" +) + +const ( + MinerVersion = "1.0.0" +) + +var ( + // mapping between methods and handlers + MinerMapping = map[string]minerhandler{ + "miner_hashrate": (*miner).Hashrate, + "miner_makeDAG": (*miner).MakeDAG, + "miner_setExtra": (*miner).SetExtra, + "miner_setGasPrice": (*miner).SetGasPrice, + "miner_startAutoDAG": (*miner).StartAutoDAG, + "miner_start": (*miner).StartMiner, + "miner_stopAutoDAG": (*miner).StopAutoDAG, + "miner_stop": (*miner).StopMiner, + } +) + +// miner callback handler +type minerhandler func(*miner, *shared.Request) (interface{}, error) + +// miner api provider +type miner struct { + ethereum *ethereum.Ethereum + methods map[string]minerhandler + codec codec.ApiCoder +} + +// create a new miner api instance +func NewMiner(ethereum *ethereum.Ethereum, coder codec.Codec) *miner { + return &miner{ + ethereum: ethereum, + methods: MinerMapping, + codec: coder.New(nil), + } +} + +// Execute given request +func (self *miner) Execute(req *shared.Request) (interface{}, error) { + if callback, ok := self.methods[req.Method]; ok { + return callback(self, req) + } + + return nil, &shared.NotImplementedError{req.Method} +} + +// collection with supported methods +func (self *miner) Methods() []string { + methods := make([]string, len(self.methods)) + i := 0 + for k := range self.methods { + methods[i] = k + i++ + } + return methods +} + +func (self *miner) StartMiner(req *shared.Request) (interface{}, error) { + args := new(StartMinerArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, err + } + if args.Threads == -1 { // (-1 is set in unmarshalljson when not specified in req) + args.Threads = self.ethereum.MinerThreads + } + + self.ethereum.StartAutoDAG() + err := self.ethereum.StartMining(args.Threads) + if err == nil { + return true, nil + } + + return false, err +} + +func (self *miner) StopMiner(req *shared.Request) (interface{}, error) { + self.ethereum.StopMining() + return true, nil +} + +func (self *miner) Hashrate(req *shared.Request) (interface{}, error) { + return self.ethereum.Miner().HashRate(), nil +} + +func (self *miner) SetExtra(req *shared.Request) (interface{}, error) { + args := new(SetExtraArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, err + } + err := self.ethereum.Miner().SetExtra([]byte(args.Data)) + if err == nil { + return true, nil + } + return false, err +} + +func (self *miner) SetGasPrice(req *shared.Request) (interface{}, error) { + args := new(GasPriceArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, err + } + + self.ethereum.Miner().SetGasPrice(common.String2Big(args.Price)) + return nil, nil +} + +func (self *miner) StartAutoDAG(req *shared.Request) (interface{}, error) { + self.ethereum.StartAutoDAG() + return nil, nil +} + +func (self *miner) StopAutoDAG(req *shared.Request) (interface{}, error) { + self.ethereum.StopAutoDAG() + return nil, nil +} + +func (self *miner) MakeDAG(req *shared.Request) (interface{}, error) { + args := new(MakeDAGArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, err + } + + err := ethash.MakeDAG(args.BlockNumber, "") + if err == nil { + return true, nil + } + return false, err +} diff --git a/rpc/api/miner_args.go b/rpc/api/miner_args.go new file mode 100644 index 0000000000..b5fc01ae47 --- /dev/null +++ b/rpc/api/miner_args.go @@ -0,0 +1,47 @@ +package api +import ( + "encoding/json" + "github.com/ethereum/go-ethereum/rpc/shared" + "math/big" + "fmt" +) + +type StartMinerArgs struct { + Threads int `json:"threads"` +} + +func (args *StartMinerArgs) UnmarshalJSON(b []byte) (err error) { + fmt.Printf("b=%s\n", string(b)) + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return shared.NewDecodeParamError(err.Error()) + } + + if len(obj) == 0 { + args.Threads = -1 + return nil + } + + var arg0 *big.Int + if arg0, err = numString(obj[0]); err != nil { + return err + } + + if arg0.Int64() >= 0 && arg0.Int64() <= 256 { + args.Threads = int(arg0.Int64()) + } + + return shared.NewValidationError("threads", "Must be in range [0...256]") +} + +type SetExtraArgs struct { + Data string `json:"data"` +} + +type GasPriceArgs struct { + Price string `json:"price"` +} + +type MakeDAGArgs struct { + BlockNumber uint64 `json:"blockNumber"` +} diff --git a/rpc/api/types.go b/rpc/api/types.go new file mode 100644 index 0000000000..778f64ec17 --- /dev/null +++ b/rpc/api/types.go @@ -0,0 +1 @@ +package api diff --git a/rpc/api/web3.go b/rpc/api/web3.go index 0e68ff7d65..69d63b26e8 100644 --- a/rpc/api/web3.go +++ b/rpc/api/web3.go @@ -56,7 +56,7 @@ func (self *web3) Execute(req *shared.Request) (interface{}, error) { return callback(self, req) } - return nil, &NotImplementedError{req.Method} + return nil, &shared.NotImplementedError{req.Method} } // Version of the API this instance provides diff --git a/rpc/api/web3_args.go b/rpc/api/web3_args.go new file mode 100644 index 0000000000..5455a6c8e5 --- /dev/null +++ b/rpc/api/web3_args.go @@ -0,0 +1,5 @@ +package api + +type Sha3Args struct { + Data string +} diff --git a/rpc/shared/api.go b/rpc/shared/types.go similarity index 100% rename from rpc/shared/api.go rename to rpc/shared/types.go