From cdd34fcb166cdb90ee411d029e6851325e80c8d3 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Tue, 19 Jan 2016 09:26:17 +0100 Subject: [PATCH] console: add admin.sleep and admin.sleepBlocks --- cmd/geth/js.go | 9 ++++++ rpc/jeth.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 9329eaa0e..cdafab7fa 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -348,6 +348,15 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { persObj.Set("newAccount", jeth.NewAccount) } + // The admin.sleep and admin.sleepBlocks are offered by the console and not by the RPC layer. + // Bind these if the admin module is available. + if a, err := js.re.Get("admin"); err == nil { + if adminObj := a.Object(); adminObj != nil { + adminObj.Set("sleepBlocks", jeth.SleepBlocks) + adminObj.Set("sleep", jeth.Sleep) + } + } + return nil } diff --git a/rpc/jeth.go b/rpc/jeth.go index de7dd1e76..b195a4965 100644 --- a/rpc/jeth.go +++ b/rpc/jeth.go @@ -19,6 +19,7 @@ package rpc import ( "encoding/json" "fmt" + "time" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/jsre" @@ -247,3 +248,77 @@ func (self *Jeth) confirmTransaction(id interface{}, jsonrpc string, args []inte // Accept all tx which are send from this console return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil } + +// throwJSExeception panics on an otto value, the Otto VM will then throw msg as a javascript error. +func throwJSExeception(msg interface{}) otto.Value { + p, _ := otto.ToValue(msg) + panic(p) + return p +} + +// Sleep will halt the console for arg[0] seconds. +func (self *Jeth) Sleep(call otto.FunctionCall) (response otto.Value) { + if len(call.ArgumentList) >= 1 { + if call.Argument(0).IsNumber() { + sleep, _ := call.Argument(0).ToInteger() + time.Sleep(time.Duration(sleep) * time.Second) + return otto.TrueValue() + } + } + return throwJSExeception("usage: sleep()") +} + +// SleepBlocks will wait for a specified number of new blocks or max for a +// given of seconds. sleepBlocks(nBlocks[, maxSleep]). +func (self *Jeth) SleepBlocks(call otto.FunctionCall) (response otto.Value) { + nBlocks := int64(0) + maxSleep := int64(9999999999999999) // indefinitely + + nArgs := len(call.ArgumentList) + + if nArgs == 0 { + throwJSExeception("usage: sleepBlocks([, max sleep in seconds])") + } + + if nArgs >= 1 { + if call.Argument(0).IsNumber() { + nBlocks, _ = call.Argument(0).ToInteger() + } else { + throwJSExeception("expected number as first argument") + } + } + + if nArgs >= 2 { + if call.Argument(1).IsNumber() { + maxSleep, _ = call.Argument(1).ToInteger() + } else { + throwJSExeception("expected number as second argument") + } + } + + // go through the console, this will allow web3 to call the appropriate + // callbacks if a delayed response or notification is received. + currentBlockNr := func() int64 { + result, err := call.Otto.Run("eth.blockNumber") + if err != nil { + throwJSExeception(err.Error()) + } + blockNr, err := result.ToInteger() + if err != nil { + throwJSExeception(err.Error()) + } + return blockNr + } + + targetBlockNr := currentBlockNr() + nBlocks + deadline := time.Now().Add(time.Duration(maxSleep) * time.Second) + + for time.Now().Before(deadline) { + if currentBlockNr() >= targetBlockNr { + return otto.TrueValue() + } + time.Sleep(time.Second) + } + + return otto.FalseValue() +}