diff options
-rw-r--r-- | cmd/geth/js.go | 9 | ||||
-rw-r--r-- | core/chain_makers.go | 19 | ||||
-rw-r--r-- | core/state/statedb.go | 3 | ||||
-rw-r--r-- | core/vm/contract.go | 7 | ||||
-rw-r--r-- | core/vm/environment.go | 1 | ||||
-rw-r--r-- | core/vm/jit_test.go | 17 | ||||
-rw-r--r-- | core/vm/vm.go | 9 | ||||
-rw-r--r-- | docker/Dockerfile | 21 | ||||
-rw-r--r-- | docker/develop/Dockerfile | 17 | ||||
-rw-r--r-- | docker/master/Dockerfile | 17 | ||||
-rw-r--r-- | eth/handler.go | 12 | ||||
-rw-r--r-- | rpc/jeth.go | 75 |
12 files changed, 153 insertions, 54 deletions
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/core/chain_makers.go b/core/chain_makers.go index 5a8f380a3..c62618e6c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -91,15 +91,10 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) - _, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.gasPool) + receipt, _, _, err := ApplyTransaction(nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed) if err != nil { panic(err) } - root := b.statedb.IntermediateRoot() - b.header.GasUsed.Add(b.header.GasUsed, gas) - receipt := types.NewReceipt(root.Bytes(), b.header.GasUsed) - receipt.Logs = b.statedb.GetLogs(tx.Hash()) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) b.txs = append(b.txs, tx) b.receipts = append(b.receipts, receipt) } @@ -169,12 +164,8 @@ func (b *BlockGen) OffsetTime(seconds int64) { // values. Inserting them into BlockChain requires use of FakePow or // a similar non-validating proof of work implementation. func GenerateChain(parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) { - statedb, err := state.New(parent.Root(), db) - if err != nil { - panic(err) - } blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) - genblock := func(i int, h *types.Header) (*types.Block, types.Receipts) { + genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) { b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb} if gen != nil { gen(i, b) @@ -188,8 +179,12 @@ func GenerateChain(parent *types.Block, db ethdb.Database, n int, gen func(int, return types.NewBlock(h, b.txs, b.uncles, b.receipts), b.receipts } for i := 0; i < n; i++ { + statedb, err := state.New(parent.Root(), db) + if err != nil { + panic(err) + } header := makeHeader(parent, statedb) - block, receipt := genblock(i, header) + block, receipt := genblock(i, header, statedb) blocks[i] = block receipts[i] = receipt parent = block diff --git a/core/state/statedb.go b/core/state/statedb.go index 413321057..8093472b5 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -353,7 +353,8 @@ func (s *StateDB) IntermediateRoot() common.Hash { // Commit commits all state changes to the database. func (s *StateDB) Commit() (root common.Hash, err error) { - return s.commit(s.db) + root, batch := s.CommitBatch() + return root, batch.Write() } // CommitBatch commits all state changes to a write batch but does not diff --git a/core/vm/contract.go b/core/vm/contract.go index 95417e747..5981dcca0 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -27,6 +27,7 @@ type ContractRef interface { ReturnGas(*big.Int, *big.Int) Address() common.Address SetCode([]byte) + EachStorage(cb func(key, value []byte)) } // Contract represents an ethereum contract in the state database. It contains @@ -124,3 +125,9 @@ func (self *Contract) SetCallCode(addr *common.Address, code []byte) { self.Code = code self.CodeAddr = addr } + +// EachStorage iterates the contract's storage and calls a method for every key +// value pair. +func (self *Contract) EachStorage(cb func(key, value []byte)) { + self.caller.EachStorage(cb) +} diff --git a/core/vm/environment.go b/core/vm/environment.go index 299d12674..4fee583bf 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -121,4 +121,5 @@ type Account interface { Address() common.Address ReturnGas(*big.Int, *big.Int) SetCode([]byte) + EachStorage(cb func(key, value []byte)) } diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go index aa97e5184..8c50ed0f5 100644 --- a/core/vm/jit_test.go +++ b/core/vm/jit_test.go @@ -125,14 +125,15 @@ type vmBench struct { type account struct{} -func (account) SubBalance(amount *big.Int) {} -func (account) AddBalance(amount *big.Int) {} -func (account) SetBalance(*big.Int) {} -func (account) SetNonce(uint64) {} -func (account) Balance() *big.Int { return nil } -func (account) Address() common.Address { return common.Address{} } -func (account) ReturnGas(*big.Int, *big.Int) {} -func (account) SetCode([]byte) {} +func (account) SubBalance(amount *big.Int) {} +func (account) AddBalance(amount *big.Int) {} +func (account) SetBalance(*big.Int) {} +func (account) SetNonce(uint64) {} +func (account) Balance() *big.Int { return nil } +func (account) Address() common.Address { return common.Address{} } +func (account) ReturnGas(*big.Int, *big.Int) {} +func (account) SetCode([]byte) {} +func (account) EachStorage(cb func(key, value []byte)) {} func runVmBench(test vmBench, b *testing.B) { var sender account diff --git a/core/vm/vm.go b/core/vm/vm.go index 4b03e55f0..8e07aaa89 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -376,12 +376,9 @@ func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, st stck[i] = new(big.Int).Set(item) } storage := make(map[common.Hash][]byte) - /* - object := contract.self.(*state.StateObject) - object.EachStorage(func(k, v []byte) { - storage[common.BytesToHash(k)] = v - }) - */ + contract.self.EachStorage(func(k, v []byte) { + storage[common.BytesToHash(k)] = v + }) self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, err}) } } diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index ba5b05d14..000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ubuntu:wily -MAINTAINER caktux - -ENV DEBIAN_FRONTEND noninteractive - -# Usual update / upgrade -RUN apt-get update -RUN apt-get upgrade -q -y -RUN apt-get dist-upgrade -q -y - -# Install Ethereum -RUN apt-get install -q -y software-properties-common -RUN add-apt-repository ppa:ethereum/ethereum -RUN add-apt-repository ppa:ethereum/ethereum-dev -RUN apt-get update -RUN apt-get install -q -y geth - -EXPOSE 8545 -EXPOSE 30303 - -ENTRYPOINT ["/usr/bin/geth"] diff --git a/docker/develop/Dockerfile b/docker/develop/Dockerfile new file mode 100644 index 000000000..98b4aadf8 --- /dev/null +++ b/docker/develop/Dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:wily +MAINTAINER caktux + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get upgrade -q -y && \ + apt-get dist-upgrade -q -y && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 923F6CA9 && \ + echo "deb http://ppa.launchpad.net/ethereum/ethereum-dev/ubuntu wily main" | tee -a /etc/apt/sources.list.d/ethereum.list && \ + apt-get update && \ + apt-get install -q -y geth + +EXPOSE 8545 +EXPOSE 30303 + +ENTRYPOINT ["/usr/bin/geth"] diff --git a/docker/master/Dockerfile b/docker/master/Dockerfile new file mode 100644 index 000000000..2c6de28c9 --- /dev/null +++ b/docker/master/Dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:wily +MAINTAINER caktux + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get upgrade -q -y && \ + apt-get dist-upgrade -q -y && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 923F6CA9 && \ + echo "deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu wily main" | tee -a /etc/apt/sources.list.d/ethereum.list && \ + apt-get update && \ + apt-get install -q -y geth + +EXPOSE 8545 +EXPOSE 30303 + +ENTRYPOINT ["/usr/bin/geth"] diff --git a/eth/handler.go b/eth/handler.go index 108a6679c..e8bac23c3 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -750,10 +750,10 @@ func (self *ProtocolManager) txBroadcastLoop() { // EthNodeInfo represents a short summary of the Ethereum sub-protocol metadata known // about the host peer. type EthNodeInfo struct { - Network int `json:"network"` // Ethereum network ID (0=Olympic, 1=Frontier, 2=Morden) - Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain - Genesis string `json:"genesis"` // SHA3 hash of the host's genesis block - Head string `json:"head"` // SHA3 hash of the host's best owned block + Network int `json:"network"` // Ethereum network ID (0=Olympic, 1=Frontier, 2=Morden) + Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain + Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block + Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block } // NodeInfo retrieves some protocol metadata about the running host node. @@ -761,7 +761,7 @@ func (self *ProtocolManager) NodeInfo() *EthNodeInfo { return &EthNodeInfo{ Network: self.networkId, Difficulty: self.blockchain.GetTd(self.blockchain.CurrentBlock().Hash()), - Genesis: fmt.Sprintf("%x", self.blockchain.Genesis().Hash()), - Head: fmt.Sprintf("%x", self.blockchain.CurrentBlock().Hash()), + Genesis: self.blockchain.Genesis().Hash(), + Head: self.blockchain.CurrentBlock().Hash(), } } 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(<sleep in seconds>)") +} + +// SleepBlocks will wait for a specified number of new blocks or max for a +// given of seconds. sleepBlocks(nBlocks[, maxSleep]). +func (self *Jeth) SleepBlocks(call otto.FunctionCall) (response otto.Value) { + nBlocks := int64(0) + maxSleep := int64(9999999999999999) // indefinitely + + nArgs := len(call.ArgumentList) + + if nArgs == 0 { + throwJSExeception("usage: sleepBlocks(<n blocks>[, max sleep in seconds])") + } + + if nArgs >= 1 { + if call.Argument(0).IsNumber() { + nBlocks, _ = call.Argument(0).ToInteger() + } else { + throwJSExeception("expected number as first argument") + } + } + + if nArgs >= 2 { + if call.Argument(1).IsNumber() { + maxSleep, _ = call.Argument(1).ToInteger() + } else { + throwJSExeception("expected number as second argument") + } + } + + // go through the console, this will allow web3 to call the appropriate + // callbacks if a delayed response or notification is received. + currentBlockNr := func() int64 { + result, err := call.Otto.Run("eth.blockNumber") + if err != nil { + throwJSExeception(err.Error()) + } + blockNr, err := result.ToInteger() + if err != nil { + throwJSExeception(err.Error()) + } + return blockNr + } + + targetBlockNr := currentBlockNr() + nBlocks + deadline := time.Now().Add(time.Duration(maxSleep) * time.Second) + + for time.Now().Before(deadline) { + if currentBlockNr() >= targetBlockNr { + return otto.TrueValue() + } + time.Sleep(time.Second) + } + + return otto.FalseValue() +} |