Merge branch 'develop' into bzz

This commit is contained in:
Daniel A. Nagy 2015-03-27 17:32:15 +01:00
commit 26b8e0fe52
31 changed files with 800 additions and 455 deletions

View file

@ -20,7 +20,7 @@ Mist (GUI):
`go get github.com/ethereum/go-ethereum/cmd/mist` `go get github.com/ethereum/go-ethereum/cmd/mist`
Ethereum (CLI): Geth (CLI):
`go get github.com/ethereum/go-ethereum/cmd/ethereum` `go get github.com/ethereum/go-ethereum/cmd/ethereum`
@ -32,10 +32,10 @@ Mist (GUI):
godep go build -v ./cmd/mist godep go build -v ./cmd/mist
``` ```
Ethereum (CLI): Geth (CLI):
``` ```
godep go build -v ./cmd/ethereum godep go build -v ./cmd/geth
``` ```
Instead of `build`, you can use `install` which will also install the resulting binary. Instead of `build`, you can use `install` which will also install the resulting binary.
@ -61,7 +61,7 @@ Go Ethereum comes with several wrappers/executables found in
[the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd): [the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd):
* `mist` Official Ethereum Browser (ethereum GUI client) * `mist` Official Ethereum Browser (ethereum GUI client)
* `ethereum` Ethereum CLI (ethereum command line interface client) * `geth` Ethereum CLI (ethereum command line interface client)
* `bootnode` runs a bootstrap node for the Discovery Protocol * `bootnode` runs a bootstrap node for the Discovery Protocol
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite: * `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite:
`cat file | ethtest`. `cat file | ethtest`.
@ -73,12 +73,12 @@ Go Ethereum comes with several wrappers/executables found in
Command line options Command line options
============================ ============================
Both `mist` and `ethereum` can be configured via command line options, environment variables and config files. Both `mist` and `geth` can be configured via command line options, environment variables and config files.
To get the options available: To get the options available:
``` ```
ethereum -help geth -help
``` ```
For further details on options, see the [wiki](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) For further details on options, see the [wiki](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)

View file

@ -36,9 +36,8 @@ import (
"bytes" "bytes"
"crypto/ecdsa" "crypto/ecdsa"
crand "crypto/rand" crand "crypto/rand"
"os"
"errors" "errors"
"os"
"sync" "sync"
"time" "time"
@ -82,13 +81,7 @@ func (am *Manager) HasAccount(addr []byte) bool {
return false return false
} }
// Coinbase returns the account address that mining rewards are sent to. func (am *Manager) Primary() (addr []byte, err error) {
func (am *Manager) Coinbase() (addr []byte, err error) {
// TODO: persist coinbase address on disk
return am.firstAddr()
}
func (am *Manager) firstAddr() ([]byte, error) {
addrs, err := am.keyStore.GetKeyAddresses() addrs, err := am.keyStore.GetKeyAddresses()
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, ErrNoKeys return nil, ErrNoKeys
@ -208,3 +201,37 @@ func zeroKey(k *ecdsa.PrivateKey) {
b[i] = 0 b[i] = 0
} }
} }
// USE WITH CAUTION = this will save an unencrypted private key on disk
// no cli or js interface
func (am *Manager) Export(path string, addr []byte, keyAuth string) error {
key, err := am.keyStore.GetKey(addr, keyAuth)
if err != nil {
return err
}
return crypto.SaveECDSA(path, key.PrivateKey)
}
func (am *Manager) Import(path string, keyAuth string) (Account, error) {
privateKeyECDSA, err := crypto.LoadECDSA(path)
if err != nil {
return Account{}, err
}
key := crypto.NewKeyFromECDSA(privateKeyECDSA)
if err = am.keyStore.StoreKey(key, keyAuth); err != nil {
return Account{}, err
}
return Account{Address: key.Address}, nil
}
func (am *Manager) ImportPreSaleKey(keyJSON []byte, password string) (acc Account, err error) {
var key *crypto.Key
key, err = crypto.ImportPreSaleKey(am.keyStore, keyJSON, password)
if err != nil {
return
}
if err = am.keyStore.StoreKey(key, password); err != nil {
return
}
return Account{Address: key.Address}, nil
}

View file

@ -1,7 +1,7 @@
package blockpool package blockpool
import ( import (
// "fmt" "fmt"
"testing" "testing"
"time" "time"
@ -45,17 +45,15 @@ func getStatusValues(s *Status) []int {
func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err error) { func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err error) {
s := bp.Status() s := bp.Status()
if s.Syncing != syncing { if s.Syncing != syncing {
t.Errorf("status for Syncing incorrect. expected %v, got %v", syncing, s.Syncing) err = fmt.Errorf("status for Syncing incorrect. expected %v, got %v", syncing, s.Syncing)
return
} }
got := getStatusValues(s) got := getStatusValues(s)
for i, v := range expected { for i, v := range expected {
if i == 0 || i == 7 {
continue //hack
}
err = test.CheckInt(statusFields[i], got[i], v, t) err = test.CheckInt(statusFields[i], got[i], v, t)
// fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v) // fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v)
if err != nil { if err != nil {
return err return
} }
} }
return return
@ -63,6 +61,25 @@ func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err
func TestBlockPoolStatus(t *testing.T) { func TestBlockPoolStatus(t *testing.T) {
test.LogInit() test.LogInit()
var err error
n := 3
for n > 0 {
n--
err = testBlockPoolStatus(t)
if err != nil {
t.Log(err)
continue
} else {
return
}
}
if err != nil {
t.Errorf("no pass out of 3: %v", err)
}
}
func testBlockPoolStatus(t *testing.T) (err error) {
_, blockPool, blockPoolTester := newTestBlockPool(t) _, blockPool, blockPoolTester := newTestBlockPool(t)
blockPoolTester.blockChain[0] = nil blockPoolTester.blockChain[0] = nil
blockPoolTester.initRefBlockChain(12) blockPoolTester.initRefBlockChain(12)
@ -70,6 +87,7 @@ func TestBlockPoolStatus(t *testing.T) {
delete(blockPoolTester.refBlockChain, 6) delete(blockPoolTester.refBlockChain, 6)
blockPool.Start() blockPool.Start()
defer blockPool.Stop()
blockPoolTester.tds = make(map[int]int) blockPoolTester.tds = make(map[int]int)
blockPoolTester.tds[9] = 1 blockPoolTester.tds[9] = 1
blockPoolTester.tds[11] = 3 blockPoolTester.tds[11] = 3
@ -79,73 +97,67 @@ func TestBlockPoolStatus(t *testing.T) {
peer2 := blockPoolTester.newPeer("peer2", 2, 6) peer2 := blockPoolTester.newPeer("peer2", 2, 6)
peer3 := blockPoolTester.newPeer("peer3", 3, 11) peer3 := blockPoolTester.newPeer("peer3", 3, 11)
peer4 := blockPoolTester.newPeer("peer4", 1, 9) peer4 := blockPoolTester.newPeer("peer4", 1, 9)
// peer1 := blockPoolTester.newPeer("peer1", 1, 9)
// peer2 := blockPoolTester.newPeer("peer2", 2, 6)
// peer3 := blockPoolTester.newPeer("peer3", 3, 11)
// peer4 := blockPoolTester.newPeer("peer4", 1, 9)
peer2.blocksRequestsMap = peer1.blocksRequestsMap peer2.blocksRequestsMap = peer1.blocksRequestsMap
var expected []int var expected []int
var err error
expected = []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} expected = []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
err = checkStatus(t, blockPool, false, expected) err = checkStatus(nil, blockPool, false, expected)
if err != nil { if err != nil {
return return
} }
peer1.AddPeer() peer1.AddPeer()
expected = []int{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0} expected = []int{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlocks(8, 9) peer1.serveBlocks(8, 9)
expected = []int{0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} expected = []int{1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0}
// err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlockHashes(9, 8, 7, 3, 2) peer1.serveBlockHashes(9, 8, 7, 3, 2)
expected = []int{6, 5, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} expected = []int{6, 5, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0}
// expected = []int{5, 5, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0} err = checkStatus(nil, blockPool, true, expected)
err = checkStatus(t, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlocks(3, 7, 8) peer1.serveBlocks(3, 7, 8)
expected = []int{6, 5, 3, 3, 0, 1, 0, 0, 1, 1, 1, 1, 0} expected = []int{6, 5, 3, 3, 0, 1, 0, 0, 1, 1, 1, 1, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlocks(2, 3) peer1.serveBlocks(2, 3)
expected = []int{6, 5, 4, 4, 0, 1, 0, 0, 1, 1, 1, 1, 0} expected = []int{6, 5, 4, 4, 0, 1, 0, 0, 1, 1, 1, 1, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer4.AddPeer() peer4.AddPeer()
expected = []int{6, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0} expected = []int{6, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer4.sendBlockHashes(12, 11) peer4.sendBlockHashes(12, 11)
expected = []int{6, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0} expected = []int{6, 5, 4, 4, 0, 2, 0, 0, 2, 2, 1, 1, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer2.AddPeer() peer2.AddPeer()
expected = []int{6, 5, 4, 4, 0, 3, 0, 0, 3, 3, 1, 2, 0} expected = []int{6, 5, 4, 4, 0, 3, 0, 0, 3, 3, 1, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
@ -153,76 +165,76 @@ func TestBlockPoolStatus(t *testing.T) {
peer2.serveBlocks(5, 6) peer2.serveBlocks(5, 6)
peer2.serveBlockHashes(6, 5, 4, 3, 2) peer2.serveBlockHashes(6, 5, 4, 3, 2)
expected = []int{10, 8, 5, 5, 0, 3, 1, 0, 3, 3, 2, 2, 0} expected = []int{10, 8, 5, 5, 0, 3, 1, 0, 3, 3, 2, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer2.serveBlocks(2, 3, 4) peer2.serveBlocks(2, 3, 4)
expected = []int{10, 8, 6, 6, 0, 3, 1, 0, 3, 3, 2, 2, 0} expected = []int{10, 8, 6, 6, 0, 3, 1, 0, 3, 3, 2, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
blockPool.RemovePeer("peer2") blockPool.RemovePeer("peer2")
expected = []int{10, 8, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0} expected = []int{10, 8, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlockHashes(2, 1, 0) peer1.serveBlockHashes(2, 1, 0)
expected = []int{11, 9, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0} expected = []int{11, 9, 6, 6, 0, 3, 1, 0, 3, 2, 2, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlocks(1, 2) peer1.serveBlocks(1, 2)
expected = []int{11, 9, 7, 7, 0, 3, 1, 0, 3, 2, 2, 2, 0} expected = []int{11, 9, 7, 7, 0, 3, 1, 0, 3, 2, 2, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer1.serveBlocks(4, 5) peer1.serveBlocks(4, 5)
expected = []int{11, 9, 8, 8, 0, 3, 1, 0, 3, 2, 2, 2, 0} expected = []int{11, 9, 8, 8, 0, 3, 1, 0, 3, 2, 2, 2, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer3.AddPeer() peer3.AddPeer()
expected = []int{11, 9, 8, 8, 0, 4, 1, 0, 4, 3, 2, 3, 0} expected = []int{11, 9, 8, 8, 0, 4, 1, 0, 4, 3, 2, 3, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer3.serveBlocks(10, 11) peer3.serveBlocks(10, 11)
expected = []int{12, 9, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0} expected = []int{12, 9, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer3.serveBlockHashes(11, 10, 9) peer3.serveBlockHashes(11, 10, 9)
expected = []int{14, 11, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0} expected = []int{14, 11, 9, 9, 0, 4, 1, 0, 4, 3, 3, 3, 0}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer4.sendBlocks(11, 12) peer4.sendBlocks(11, 12)
expected = []int{14, 11, 9, 9, 0, 4, 1, 0, 4, 3, 4, 3, 1} expected = []int{14, 11, 9, 9, 0, 4, 1, 0, 4, 3, 4, 3, 1}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
peer3.serveBlocks(9, 10) peer3.serveBlocks(9, 10)
expected = []int{14, 11, 10, 10, 0, 4, 1, 0, 4, 3, 4, 3, 1} expected = []int{14, 11, 10, 10, 0, 4, 1, 0, 4, 3, 4, 3, 1}
err = checkStatus(t, blockPool, true, expected) err = checkStatus(nil, blockPool, true, expected)
if err != nil { if err != nil {
return return
} }
@ -231,10 +243,9 @@ func TestBlockPoolStatus(t *testing.T) {
blockPool.Wait(waitTimeout) blockPool.Wait(waitTimeout)
time.Sleep(200 * time.Millisecond) time.Sleep(200 * time.Millisecond)
expected = []int{14, 3, 11, 3, 8, 4, 1, 8, 4, 3, 4, 3, 1} expected = []int{14, 3, 11, 3, 8, 4, 1, 8, 4, 3, 4, 3, 1}
err = checkStatus(t, blockPool, false, expected) err = checkStatus(nil, blockPool, false, expected)
if err != nil { if err != nil {
return return
} }
return nil
blockPool.Stop()
} }

View file

@ -10,16 +10,20 @@ import (
func CheckInt(name string, got int, expected int, t *testing.T) (err error) { func CheckInt(name string, got int, expected int, t *testing.T) (err error) {
if got != expected { if got != expected {
t.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got) err = fmt.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got)
err = fmt.Errorf("") if t != nil {
t.Error(err)
}
} }
return return
} }
func CheckDuration(name string, got time.Duration, expected time.Duration, t *testing.T) (err error) { func CheckDuration(name string, got time.Duration, expected time.Duration, t *testing.T) (err error) {
if got != expected { if got != expected {
t.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got) err = fmt.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got)
err = fmt.Errorf("") if t != nil {
t.Error(err)
}
} }
return return
} }

View file

@ -9,10 +9,10 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
) )
@ -69,14 +69,13 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
fmt.Println(err) fmt.Println(err)
return otto.FalseValue() return otto.FalseValue()
} }
dataDir := js.ethereum.DataDir
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port)) l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
if err != nil { if err != nil {
fmt.Printf("Can't listen on %s:%d: %v", addr, port, err) fmt.Printf("Can't listen on %s:%d: %v", addr, port, err)
return otto.FalseValue() return otto.FalseValue()
} }
go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil), dataDir)) go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil)))
return otto.TrueValue() return otto.TrueValue()
} }

View file

@ -67,14 +67,14 @@ type jsre struct {
prompter prompter
} }
func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre { func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool) *jsre {
js := &jsre{ethereum: ethereum, ps1: "> "} js := &jsre{ethereum: ethereum, ps1: "> "}
js.xeth = xeth.New(ethereum, js) js.xeth = xeth.New(ethereum, js)
js.re = re.New(libPath) js.re = re.New(libPath)
js.apiBindings() js.apiBindings()
js.adminBindings() js.adminBindings()
if !liner.TerminalSupported() { if !liner.TerminalSupported() || !interactive {
js.prompter = dumbterm{bufio.NewReader(os.Stdin)} js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
} else { } else {
lr := liner.NewLiner() lr := liner.NewLiner()
@ -91,8 +91,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
func (js *jsre) apiBindings() { func (js *jsre) apiBindings() {
ethApi := rpc.NewEthereumApi(js.xeth, js.ethereum.DataDir) ethApi := rpc.NewEthereumApi(js.xeth)
ethApi.Close()
//js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal)) //js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal))
jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re) jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re)
@ -102,7 +101,7 @@ func (js *jsre) apiBindings() {
jethObj := t.Object() jethObj := t.Object()
jethObj.Set("send", jeth.Send) jethObj.Set("send", jeth.Send)
err := js.re.Compile("bignum.js", re.BigNumber_JS) err := js.re.Compile("bignumber.js", re.BigNumber_JS)
if err != nil { if err != nil {
utils.Fatalf("Error loading bignumber.js: %v", err) utils.Fatalf("Error loading bignumber.js: %v", err)
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path" "path"
"testing" "testing"
@ -9,7 +10,6 @@ import (
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
) )
@ -30,8 +30,8 @@ func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) {
} }
// FIXME: this does not work ATM // FIXME: this does not work ATM
ks := crypto.NewKeyStorePlain("/tmp/eth/keys") ks := crypto.NewKeyStorePlain("/tmp/eth/keys")
common.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d", ioutil.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d",
[]byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`)) []byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`), os.ModePerm)
port++ port++
ethereum, err = eth.New(&eth.Config{ ethereum, err = eth.New(&eth.Config{
@ -47,7 +47,7 @@ func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) {
return return
} }
assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
repl = newJSRE(ethereum, assetPath) repl = newJSRE(ethereum, assetPath, false)
return return
} }

View file

@ -23,14 +23,15 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/ethereum/ethash" "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -41,8 +42,8 @@ import (
) )
const ( const (
ClientIdentifier = "Ethereum(G)" ClientIdentifier = "Geth"
Version = "0.9.3" Version = "0.9.4"
) )
var ( var (
@ -74,10 +75,44 @@ Regular users do not need to execute it.
The output of this command is supposed to be machine-readable. The output of this command is supposed to be machine-readable.
`, `,
}, },
{
Name: "wallet",
Usage: "ethereum presale wallet",
Subcommands: []cli.Command{
{
Action: importWallet,
Name: "import",
Usage: "import ethereum presale wallet",
},
},
},
{ {
Action: accountList, Action: accountList,
Name: "account", Name: "account",
Usage: "manage accounts", Usage: "manage accounts",
Description: `
Manage accounts lets you create new accounts, list all existing accounts,
import a private key into a new account.
It supports interactive mode, when you are prompted for password as well as
non-interactive mode where passwords are supplied via a given password file.
Non-interactive mode is only meant for scripted use on test networks or known
safe environments.
Make sure you remember the password you gave when creating a new account (with
either new or import). Without it you are not able to unlock your account.
Note that exporting your key in unencrypted format is NOT supported.
Keys are stored under <DATADIR>/keys.
It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes.
Make sure you backup your keys regularly.
And finally. DO NOT FORGET YOUR PASSWORD.
`,
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Action: accountList, Action: accountList,
@ -88,6 +123,51 @@ The output of this command is supposed to be machine-readable.
Action: accountCreate, Action: accountCreate,
Name: "new", Name: "new",
Usage: "create a new account", Usage: "create a new account",
Description: `
ethereum account new
Creates a new account. Prints the address.
The account is saved in encrypted format, you are prompted for a passphrase.
You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the --password flag:
ethereum --password <passwordfile> account new
Note, this is meant to be used for testing only, it is a bad idea to save your
password to file or expose in any other way.
`,
},
{
Action: accountImport,
Name: "import",
Usage: "import a private key into a new account",
Description: `
ethereum account import <keyfile>
Imports an unencrypted private key from <keyfile> and creates a new account.
Prints the address.
The keyfile is assumed to contain an unencrypted private key in canonical EC
raw bytes format.
The account is saved in encrypted format, you are prompted for a passphrase.
You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the -password flag:
ethereum --password <passwordfile> account import <keyfile>
Note:
As you can directly copy your encrypted accounts to another ethereum instance,
this import mechanism is not needed when you transfer an account between
nodes.
`,
}, },
}, },
}, },
@ -103,18 +183,20 @@ Use "ethereum dump 0" to dump the genesis block.
{ {
Action: console, Action: console,
Name: "console", Name: "console",
Usage: `Ethereum Console: interactive JavaScript environment`, Usage: `Geth Console: interactive JavaScript environment`,
Description: ` Description: `
Console is an interactive shell for the Ethereum JavaScript runtime environment which exposes a node admin interface as well as the DAPP JavaScript API. The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the DAPP JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
`, `,
}, },
{ {
Action: execJSFiles, Action: execJSFiles,
Name: "js", Name: "js",
Usage: `executes the given JavaScript files in the Ethereum Frontier JavaScript VM`, Usage: `executes the given JavaScript files in the Geth JavaScript VM`,
Description: ` Description: `
The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console The JavaScript VM exposes a node admin interface as well as the DAPP
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
`, `,
}, },
{ {
@ -130,6 +212,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
} }
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
utils.UnlockedAccountFlag, utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
utils.BootnodesFlag, utils.BootnodesFlag,
utils.DataDirFlag, utils.DataDirFlag,
utils.JSpathFlag, utils.JSpathFlag,
@ -138,6 +221,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
utils.LogJSONFlag, utils.LogJSONFlag,
utils.LogLevelFlag, utils.LogLevelFlag,
utils.MaxPeersFlag, utils.MaxPeersFlag,
utils.EtherbaseFlag,
utils.MinerThreadsFlag, utils.MinerThreadsFlag,
utils.MiningEnabledFlag, utils.MiningEnabledFlag,
utils.NATFlag, utils.NATFlag,
@ -146,7 +230,6 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
utils.RPCEnabledFlag, utils.RPCEnabledFlag,
utils.RPCListenAddrFlag, utils.RPCListenAddrFlag,
utils.RPCPortFlag, utils.RPCPortFlag,
utils.UnencryptedKeysFlag,
utils.VMDebugFlag, utils.VMDebugFlag,
utils.ProtocolVersionFlag, utils.ProtocolVersionFlag,
utils.NetworkIdFlag, utils.NetworkIdFlag,
@ -194,7 +277,7 @@ func console(ctx *cli.Context) {
} }
startEth(ctx, ethereum) startEth(ctx, ethereum)
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name)) repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true)
repl.interactive() repl.interactive()
ethereum.Stop() ethereum.Stop()
@ -209,7 +292,7 @@ func execJSFiles(ctx *cli.Context) {
} }
startEth(ctx, ethereum) startEth(ctx, ethereum)
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name)) repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false)
for _, file := range ctx.Args() { for _, file := range ctx.Args() {
repl.exec(file) repl.exec(file)
} }
@ -218,22 +301,36 @@ func execJSFiles(ctx *cli.Context) {
ethereum.WaitForShutdown() ethereum.WaitForShutdown()
} }
func startEth(ctx *cli.Context, eth *eth.Ethereum) { func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
utils.StartEthereum(eth) var err error
// Load startup keys. XXX we are going to need a different format // Load startup keys. XXX we are going to need a different format
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
if len(account) > 0 {
split := strings.Split(account, ":")
if len(split) != 2 {
utils.Fatalf("Illegal 'unlock' format (address:password)")
}
am := eth.AccountManager()
// Attempt to unlock the account // Attempt to unlock the account
err := am.Unlock(common.FromHex(split[0]), split[1]) passphrase = getPassPhrase(ctx, "", false)
accbytes := common.FromHex(account)
if len(accbytes) == 0 {
utils.Fatalf("Invalid account address '%s'", account)
}
err = am.Unlock(accbytes, passphrase)
if err != nil { if err != nil {
utils.Fatalf("Unlock account failed '%v'", err) utils.Fatalf("Unlock account failed '%v'", err)
} }
return
}
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
utils.StartEthereum(eth)
am := eth.AccountManager()
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
if len(account) > 0 {
if account == "primary" {
accbytes, err := am.Primary()
if err != nil {
utils.Fatalf("no primary account: %v", err)
}
account = common.ToHex(accbytes)
}
unlockAccount(ctx, am, account)
} }
// Start auxiliary services if enabled. // Start auxiliary services if enabled.
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
@ -255,16 +352,15 @@ func accountList(ctx *cli.Context) {
} }
} }
func accountCreate(ctx *cli.Context) { func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) {
am := utils.GetAccountManager(ctx) passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
passphrase := "" if len(passfile) == 0 {
if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) { fmt.Println(desc)
fmt.Println("The new account will be encrypted with a passphrase.")
fmt.Println("Please enter a passphrase now.")
auth, err := readPassword("Passphrase: ", true) auth, err := readPassword("Passphrase: ", true)
if err != nil { if err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
if confirmation {
confirm, err := readPassword("Repeat Passphrase: ", false) confirm, err := readPassword("Repeat Passphrase: ", false)
if err != nil { if err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
@ -272,13 +368,61 @@ func accountCreate(ctx *cli.Context) {
if auth != confirm { if auth != confirm {
utils.Fatalf("Passphrases did not match.") utils.Fatalf("Passphrases did not match.")
} }
passphrase = auth
} }
passphrase = auth
} else {
passbytes, err := ioutil.ReadFile(passfile)
if err != nil {
utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
}
passphrase = string(passbytes)
}
return
}
func accountCreate(ctx *cli.Context) {
am := utils.GetAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
acct, err := am.NewAccount(passphrase) acct, err := am.NewAccount(passphrase)
if err != nil { if err != nil {
utils.Fatalf("Could not create the account: %v", err) utils.Fatalf("Could not create the account: %v", err)
} }
fmt.Printf("Address: %x\n", acct.Address) fmt.Printf("Address: %x\n", acct)
}
func importWallet(ctx *cli.Context) {
keyfile := ctx.Args().First()
if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument")
}
keyJson, err := ioutil.ReadFile(keyfile)
if err != nil {
utils.Fatalf("Could not read wallet file: %v", err)
}
am := utils.GetAccountManager(ctx)
passphrase := getPassPhrase(ctx, "", false)
acct, err := am.ImportPreSaleKey(keyJson, passphrase)
if err != nil {
utils.Fatalf("Could not create the account: %v", err)
}
fmt.Printf("Address: %x\n", acct)
}
func accountImport(ctx *cli.Context) {
keyfile := ctx.Args().First()
if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument")
}
am := utils.GetAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
acct, err := am.Import(keyfile, passphrase)
if err != nil {
utils.Fatalf("Could not create the account: %v", err)
}
fmt.Printf("Address: %x\n", acct)
} }
func importchain(ctx *cli.Context) { func importchain(ctx *cli.Context) {
@ -325,7 +469,6 @@ func dump(ctx *cli.Context) {
} else { } else {
statedb := state.New(block.Root(), stateDb) statedb := state.New(block.Root(), stateDb)
fmt.Printf("%s\n", statedb.Dump()) fmt.Printf("%s\n", statedb.Dump())
// fmt.Println(block)
} }
} }
} }

View file

@ -22,13 +22,14 @@ package main
import ( import (
"encoding/json" "encoding/json"
"io/ioutil"
"os" "os"
"strconv" "strconv"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
) )
type plugin struct { type plugin struct {
@ -46,14 +47,14 @@ func (self *Gui) AddPlugin(pluginPath string) {
self.plugins[pluginPath] = plugin{Name: pluginPath, Path: pluginPath} self.plugins[pluginPath] = plugin{Name: pluginPath, Path: pluginPath}
json, _ := json.MarshalIndent(self.plugins, "", " ") json, _ := json.MarshalIndent(self.plugins, "", " ")
common.WriteFile(self.eth.DataDir+"/plugins.json", json) ioutil.WriteFile(self.eth.DataDir+"/plugins.json", json, os.ModePerm)
} }
func (self *Gui) RemovePlugin(pluginPath string) { func (self *Gui) RemovePlugin(pluginPath string) {
delete(self.plugins, pluginPath) delete(self.plugins, pluginPath)
json, _ := json.MarshalIndent(self.plugins, "", " ") json, _ := json.MarshalIndent(self.plugins, "", " ")
common.WriteFile(self.eth.DataDir+"/plugins.json", json) ioutil.WriteFile(self.eth.DataDir+"/plugins.json", json, os.ModePerm)
} }
func (self *Gui) DumpState(hash, path string) { func (self *Gui) DumpState(hash, path string) {

View file

@ -25,6 +25,7 @@ import "C"
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"math/big" "math/big"
"path" "path"
"runtime" "runtime"
@ -91,8 +92,8 @@ func NewWindow(ethereum *eth.Ethereum) *Gui {
plugins: make(map[string]plugin), plugins: make(map[string]plugin),
serviceEvents: make(chan ServEv, 1), serviceEvents: make(chan ServEv, 1),
} }
data, _ := common.ReadAllFile(path.Join(ethereum.DataDir, "plugins.json")) data, _ := ioutil.ReadFile(path.Join(ethereum.DataDir, "plugins.json"))
json.Unmarshal([]byte(data), &gui.plugins) json.Unmarshal(data, &gui.plugins)
return gui return gui
} }

View file

@ -96,15 +96,21 @@ var (
Name: "mine", Name: "mine",
Usage: "Enable mining", Usage: "Enable mining",
} }
EtherbaseFlag = cli.StringFlag{
// key settings Name: "etherbase",
UnencryptedKeysFlag = cli.BoolFlag{ Usage: "public address for block mining rewards. By default the address of your primary account is used",
Name: "unencrypted-keys", Value: "primary",
Usage: "disable private key disk encryption (for testing)",
} }
UnlockedAccountFlag = cli.StringFlag{ UnlockedAccountFlag = cli.StringFlag{
Name: "unlock", Name: "unlock",
Usage: "Unlock a given account untill this programs exits (address:password)", Usage: "unlock the account given until this program exits (prompts for password). '--unlock primary' unlocks the primary account",
Value: "",
}
PasswordFileFlag = cli.StringFlag{
Name: "password",
Usage: "Path to password file for (un)locking an existing account.",
Value: "",
} }
// logging and debug settings // logging and debug settings
@ -214,6 +220,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
LogFile: ctx.GlobalString(LogFileFlag.Name), LogFile: ctx.GlobalString(LogFileFlag.Name),
LogLevel: ctx.GlobalInt(LogLevelFlag.Name), LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
LogJSON: ctx.GlobalString(LogJSONFlag.Name), LogJSON: ctx.GlobalString(LogJSONFlag.Name),
Etherbase: ctx.GlobalString(EtherbaseFlag.Name),
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name), MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
AccountManager: GetAccountManager(ctx), AccountManager: GetAccountManager(ctx),
VmDebug: ctx.GlobalBool(VMDebugFlag.Name), VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
@ -243,23 +250,17 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Dat
func GetAccountManager(ctx *cli.Context) *accounts.Manager { func GetAccountManager(ctx *cli.Context) *accounts.Manager {
dataDir := ctx.GlobalString(DataDirFlag.Name) dataDir := ctx.GlobalString(DataDirFlag.Name)
var ks crypto.KeyStore2 ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
if ctx.GlobalBool(UnencryptedKeysFlag.Name) {
ks = crypto.NewKeyStorePlain(path.Join(dataDir, "plainkeys"))
} else {
ks = crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
}
return accounts.NewManager(ks) return accounts.NewManager(ks)
} }
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) { func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
addr := ctx.GlobalString(RPCListenAddrFlag.Name) addr := ctx.GlobalString(RPCListenAddrFlag.Name)
port := ctx.GlobalInt(RPCPortFlag.Name) port := ctx.GlobalInt(RPCPortFlag.Name)
dataDir := ctx.GlobalString(DataDirFlag.Name)
fmt.Println("Starting RPC on port: ", port) fmt.Println("Starting RPC on port: ", port)
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port)) l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
if err != nil { if err != nil {
Fatalf("Can't listen on %s:%d: %v", addr, port, err) Fatalf("Can't listen on %s:%d: %v", addr, port, err)
} }
go http.Serve(l, rpc.JSONRPC(xeth.New(eth, nil), dataDir)) go http.Serve(l, rpc.JSONRPC(xeth.New(eth, nil)))
} }

View file

@ -2,7 +2,6 @@ package common
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/user" "os/user"
"path" "path"
@ -43,35 +42,6 @@ func FileExist(filePath string) bool {
return true return true
} }
func ReadAllFile(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
data, err := ioutil.ReadAll(file)
if err != nil {
return "", err
}
return string(data), nil
}
func WriteFile(filePath string, content []byte) error {
fh, err := os.OpenFile(filePath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
return err
}
defer fh.Close()
_, err = fh.Write(content)
if err != nil {
return err
}
return nil
}
func AbsolutePath(Datadir string, filename string) string { func AbsolutePath(Datadir string, filename string) string {
if path.IsAbs(filename) { if path.IsAbs(filename) {
return filename return filename

View file

@ -2,56 +2,11 @@ package common
import ( import (
"os" "os"
"testing" // "testing"
checker "gopkg.in/check.v1" checker "gopkg.in/check.v1"
) )
func TestGoodFile(t *testing.T) {
goodpath := "~/goethereumtest.pass"
path := ExpandHomePath(goodpath)
contentstring := "3.14159265358979323846"
err := WriteFile(path, []byte(contentstring))
if err != nil {
t.Error("Could not write file")
}
if !FileExist(path) {
t.Error("File not found at", path)
}
v, err := ReadAllFile(path)
if err != nil {
t.Error("Could not read file", path)
}
if v != contentstring {
t.Error("Expected", contentstring, "Got", v)
}
}
func TestBadFile(t *testing.T) {
badpath := "/this/path/should/not/exist/goethereumtest.fail"
path := ExpandHomePath(badpath)
contentstring := "3.14159265358979323846"
err := WriteFile(path, []byte(contentstring))
if err == nil {
t.Error("Wrote file, but should not be able to", path)
}
if FileExist(path) {
t.Error("Found file, but should not be able to", path)
}
v, err := ReadAllFile(path)
if err == nil {
t.Error("Read file, but should not be able to", v)
}
}
type CommonSuite struct{} type CommonSuite struct{}
var _ = checker.Suite(&CommonSuite{}) var _ = checker.Suite(&CommonSuite{})

View file

@ -1,11 +1,9 @@
package vm package vm
import "math/big" import (
"fmt"
type req struct { "math/big"
stack int )
gas *big.Int
}
var ( var (
GasQuickStep = big.NewInt(2) GasQuickStep = big.NewInt(2)
@ -56,75 +54,30 @@ var (
GasCopyWord = big.NewInt(3) GasCopyWord = big.NewInt(3)
) )
var _baseCheck = map[OpCode]req{ func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
// Req stack Gas price // PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
ADD: {2, GasFastestStep}, // PUSH is also allowed to calculate the same price for all PUSHes
LT: {2, GasFastestStep}, // DUP requirements are handled elsewhere (except for the stack limit check)
GT: {2, GasFastestStep}, if op >= PUSH1 && op <= PUSH32 {
SLT: {2, GasFastestStep}, op = PUSH1
SGT: {2, GasFastestStep}, }
EQ: {2, GasFastestStep}, if op >= DUP1 && op <= DUP16 {
ISZERO: {1, GasFastestStep}, op = DUP1
SUB: {2, GasFastestStep}, }
AND: {2, GasFastestStep},
OR: {2, GasFastestStep},
XOR: {2, GasFastestStep},
NOT: {1, GasFastestStep},
BYTE: {2, GasFastestStep},
CALLDATALOAD: {1, GasFastestStep},
CALLDATACOPY: {3, GasFastestStep},
MLOAD: {1, GasFastestStep},
MSTORE: {2, GasFastestStep},
MSTORE8: {2, GasFastestStep},
CODECOPY: {3, GasFastestStep},
MUL: {2, GasFastStep},
DIV: {2, GasFastStep},
SDIV: {2, GasFastStep},
MOD: {2, GasFastStep},
SMOD: {2, GasFastStep},
SIGNEXTEND: {2, GasFastStep},
ADDMOD: {3, GasMidStep},
MULMOD: {3, GasMidStep},
JUMP: {1, GasMidStep},
JUMPI: {2, GasSlowStep},
EXP: {2, GasSlowStep},
ADDRESS: {0, GasQuickStep},
ORIGIN: {0, GasQuickStep},
CALLER: {0, GasQuickStep},
CALLVALUE: {0, GasQuickStep},
CODESIZE: {0, GasQuickStep},
GASPRICE: {0, GasQuickStep},
COINBASE: {0, GasQuickStep},
TIMESTAMP: {0, GasQuickStep},
NUMBER: {0, GasQuickStep},
CALLDATASIZE: {0, GasQuickStep},
DIFFICULTY: {0, GasQuickStep},
GASLIMIT: {0, GasQuickStep},
POP: {0, GasQuickStep},
PC: {0, GasQuickStep},
MSIZE: {0, GasQuickStep},
GAS: {0, GasQuickStep},
BLOCKHASH: {1, GasExtStep},
BALANCE: {0, GasExtStep},
EXTCODESIZE: {1, GasExtStep},
EXTCODECOPY: {4, GasExtStep},
SLOAD: {1, GasStorageGet},
SSTORE: {2, Zero},
SHA3: {1, GasSha3Base},
CREATE: {3, GasCreate},
CALL: {7, GasCall},
CALLCODE: {7, GasCall},
JUMPDEST: {0, GasJumpDest},
SUICIDE: {1, Zero},
RETURN: {2, Zero},
}
func baseCheck(op OpCode, stack *stack, gas *big.Int) {
if r, ok := _baseCheck[op]; ok { if r, ok := _baseCheck[op]; ok {
stack.require(r.stack) err := stack.require(r.stackPop)
if err != nil {
return err
}
if r.stackPush && len(stack.data)-r.stackPop+1 > 1024 {
return fmt.Errorf("stack limit reached (%d)", maxStack)
}
gas.Add(gas, r.gas) gas.Add(gas, r.gas)
} }
return nil
} }
func toWordSize(size *big.Int) *big.Int { func toWordSize(size *big.Int) *big.Int {
@ -133,3 +86,74 @@ func toWordSize(size *big.Int) *big.Int {
tmp.Div(tmp, u256(32)) tmp.Div(tmp, u256(32))
return tmp return tmp
} }
type req struct {
stackPop int
gas *big.Int
stackPush bool
}
var _baseCheck = map[OpCode]req{
// opcode | stack pop | gas price | stack push
ADD: {2, GasFastestStep, true},
LT: {2, GasFastestStep, true},
GT: {2, GasFastestStep, true},
SLT: {2, GasFastestStep, true},
SGT: {2, GasFastestStep, true},
EQ: {2, GasFastestStep, true},
ISZERO: {1, GasFastestStep, true},
SUB: {2, GasFastestStep, true},
AND: {2, GasFastestStep, true},
OR: {2, GasFastestStep, true},
XOR: {2, GasFastestStep, true},
NOT: {1, GasFastestStep, true},
BYTE: {2, GasFastestStep, true},
CALLDATALOAD: {1, GasFastestStep, true},
CALLDATACOPY: {3, GasFastestStep, true},
MLOAD: {1, GasFastestStep, true},
MSTORE: {2, GasFastestStep, false},
MSTORE8: {2, GasFastestStep, false},
CODECOPY: {3, GasFastestStep, false},
MUL: {2, GasFastStep, true},
DIV: {2, GasFastStep, true},
SDIV: {2, GasFastStep, true},
MOD: {2, GasFastStep, true},
SMOD: {2, GasFastStep, true},
SIGNEXTEND: {2, GasFastStep, true},
ADDMOD: {3, GasMidStep, true},
MULMOD: {3, GasMidStep, true},
JUMP: {1, GasMidStep, false},
JUMPI: {2, GasSlowStep, false},
EXP: {2, GasSlowStep, true},
ADDRESS: {0, GasQuickStep, true},
ORIGIN: {0, GasQuickStep, true},
CALLER: {0, GasQuickStep, true},
CALLVALUE: {0, GasQuickStep, true},
CODESIZE: {0, GasQuickStep, true},
GASPRICE: {0, GasQuickStep, true},
COINBASE: {0, GasQuickStep, true},
TIMESTAMP: {0, GasQuickStep, true},
NUMBER: {0, GasQuickStep, true},
CALLDATASIZE: {0, GasQuickStep, true},
DIFFICULTY: {0, GasQuickStep, true},
GASLIMIT: {0, GasQuickStep, true},
POP: {1, GasQuickStep, false},
PC: {0, GasQuickStep, true},
MSIZE: {0, GasQuickStep, true},
GAS: {0, GasQuickStep, true},
BLOCKHASH: {1, GasExtStep, true},
BALANCE: {0, GasExtStep, true},
EXTCODESIZE: {1, GasExtStep, true},
EXTCODECOPY: {4, GasExtStep, false},
SLOAD: {1, GasStorageGet, true},
SSTORE: {2, Zero, false},
SHA3: {1, GasSha3Base, true},
CREATE: {3, GasCreate, true},
CALL: {7, GasCall, true},
CALLCODE: {7, GasCall, true},
JUMPDEST: {0, GasJumpDest, false},
SUICIDE: {1, Zero, false},
RETURN: {2, Zero, false},
PUSH1: {0, GasFastestStep, true},
DUP1: {0, Zero, true},
}

View file

@ -15,21 +15,17 @@ func NewMemory() *Memory {
} }
func (m *Memory) Set(offset, size uint64, value []byte) { func (m *Memory) Set(offset, size uint64, value []byte) {
value = common.RightPadBytes(value, int(size)) // length of store may never be less than offset + size.
// The store should be resized PRIOR to setting the memory
if size > uint64(len(m.store)) {
panic("INVALID memory: store empty")
}
totSize := offset + size // It's possible the offset is greater than 0 and size equals 0. This is because
lenSize := uint64(len(m.store) - 1) // the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
if totSize > lenSize { if size > 0 {
// Calculate the diff between the sizes copy(m.store[offset:offset+size], common.RightPadBytes(value, int(size)))
diff := totSize - lenSize
if diff > 0 {
// Create a new empty slice and append it
newSlice := make([]byte, diff-1)
// Resize slice
m.store = append(m.store, newSlice...)
} }
}
copy(m.store[offset:offset+size], value)
} }
func (m *Memory) Resize(size uint64) { func (m *Memory) Resize(size uint64) {

View file

@ -5,6 +5,8 @@ import (
"math/big" "math/big"
) )
const maxStack = 1024
func newStack() *stack { func newStack() *stack {
return &stack{} return &stack{}
} }
@ -15,6 +17,7 @@ type stack struct {
} }
func (st *stack) push(d *big.Int) { func (st *stack) push(d *big.Int) {
// NOTE push limit (1024) is checked in baseCheck
stackItem := new(big.Int).Set(d) stackItem := new(big.Int).Set(d)
if len(st.data) > st.ptr { if len(st.data) > st.ptr {
st.data[st.ptr] = stackItem st.data[st.ptr] = stackItem
@ -46,10 +49,11 @@ func (st *stack) peek() *big.Int {
return st.data[st.len()-1] return st.data[st.len()-1]
} }
func (st *stack) require(n int) { func (st *stack) require(n int) error {
if st.len() < n { if st.len() < n {
panic(fmt.Sprintf("stack underflow (%d <=> %d)", len(st.data), n)) return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
} }
return nil
} }
func (st *stack) Print() { func (st *stack) Print() {

View file

@ -45,20 +45,16 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl() self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl()
if self.Recoverable { // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
// Recover from any require exception
defer func() { defer func() {
if r := recover(); r != nil { if err != nil {
self.Printf(" %v", r).Endl() self.Printf(" %v", err).Endl()
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
context.UseGas(context.Gas) context.UseGas(context.Gas)
ret = context.Return(nil) ret = context.Return(nil)
err = fmt.Errorf("%v", r)
} }
}() }()
}
if context.CodeAddr != nil { if context.CodeAddr != nil {
if p := Precompiled[context.CodeAddr.Str()]; p != nil { if p := Precompiled[context.CodeAddr.Str()]; p != nil {
@ -76,18 +72,20 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
step = 0 step = 0
statedb = self.env.State() statedb = self.env.State()
jump = func(from uint64, to *big.Int) { jump = func(from uint64, to *big.Int) error {
p := to.Uint64() p := to.Uint64()
nop := context.GetOp(p) nop := context.GetOp(p)
if !destinations.Has(p) { if !destinations.Has(p) {
panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p)) return fmt.Errorf("invalid jump destination (%v) %v", nop, p)
} }
self.Printf(" ~> %v", to) self.Printf(" ~> %v", to)
pc = to.Uint64() pc = to.Uint64()
self.Endl() self.Endl()
return nil
} }
) )
@ -105,7 +103,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
op = context.GetOp(pc) op = context.GetOp(pc)
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len()) self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack) newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
if err != nil {
return nil, err
}
self.Printf("(g) %-3v (%v)", gas, context.Gas) self.Printf("(g) %-3v (%v)", gas, context.Gas)
@ -600,14 +601,18 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
case JUMP: case JUMP:
jump(pc, stack.pop()) if err := jump(pc, stack.pop()); err != nil {
return nil, err
}
continue continue
case JUMPI: case JUMPI:
pos, cond := stack.pop(), stack.pop() pos, cond := stack.pop(), stack.pop()
if cond.Cmp(common.BigTrue) >= 0 { if cond.Cmp(common.BigTrue) >= 0 {
jump(pc, pos) if err := jump(pc, pos); err != nil {
return nil, err
}
continue continue
} }
@ -720,7 +725,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
default: default:
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl() self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
panic(fmt.Errorf("Invalid opcode %x", op)) return nil, fmt.Errorf("Invalid opcode %x", op)
} }
pc++ pc++
@ -729,28 +734,38 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
} }
} }
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int) { func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
var ( var (
gas = new(big.Int) gas = new(big.Int)
newMemSize *big.Int = new(big.Int) newMemSize *big.Int = new(big.Int)
) )
baseCheck(op, stack, gas) err := baseCheck(op, stack, gas)
if err != nil {
return nil, nil, err
}
// stack Check, memory resize & gas phase // stack Check, memory resize & gas phase
switch op { switch op {
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
gas.Set(GasFastestStep)
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2) n := int(op - SWAP1 + 2)
stack.require(n) err := stack.require(n)
if err != nil {
return nil, nil, err
}
gas.Set(GasFastestStep) gas.Set(GasFastestStep)
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1) n := int(op - DUP1 + 1)
stack.require(n) err := stack.require(n)
if err != nil {
return nil, nil, err
}
gas.Set(GasFastestStep) gas.Set(GasFastestStep)
case LOG0, LOG1, LOG2, LOG3, LOG4: case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0) n := int(op - LOG0)
stack.require(n + 2) err := stack.require(n + 2)
if err != nil {
return nil, nil, err
}
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
@ -762,7 +777,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
case EXP: case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte)) gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
case SSTORE: case SSTORE:
stack.require(2) err := stack.require(2)
if err != nil {
return nil, nil, err
}
var g *big.Int var g *big.Int
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
@ -853,7 +871,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
} }
} }
return newMemSize, gas return newMemSize, gas, nil
} }
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) { func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
@ -869,7 +887,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
tmp := new(big.Int).Set(context.Gas) tmp := new(big.Int).Set(context.Gas)
panic(OOG(gas, tmp).Error()) return nil, OOG(gas, tmp)
} }
} }

View file

@ -9,6 +9,7 @@ import (
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"encoding/hex" "encoding/hex"
@ -139,6 +140,12 @@ func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
return ToECDSA(buf), nil return ToECDSA(buf), nil
} }
// SaveECDSA saves a secp256k1 private key to the given file with restrictive
// permissions
func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
return ioutil.WriteFile(file, FromECDSA(key), 0600)
}
func GenerateKey() (*ecdsa.PrivateKey, error) { func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(S256(), rand.Reader) return ecdsa.GenerateKey(S256(), rand.Reader)
} }

View file

@ -85,6 +85,16 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
return err return err
} }
func NewKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {
id := uuid.NewRandom()
key := &Key{
Id: id,
Address: PubkeyToAddress(privateKeyECDSA.PublicKey),
PrivateKey: privateKeyECDSA,
}
return key
}
func NewKey(rand io.Reader) *Key { func NewKey(rand io.Reader) *Key {
randBytes := make([]byte, 64) randBytes := make([]byte, 64)
_, err := rand.Read(randBytes) _, err := rand.Read(randBytes)
@ -97,11 +107,5 @@ func NewKey(rand io.Reader) *Key {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
} }
id := uuid.NewRandom() return NewKeyFromECDSA(privateKeyECDSA)
key := &Key{
Id: id,
Address: PubkeyToAddress(privateKeyECDSA.PublicKey),
PrivateKey: privateKeyECDSA,
}
return key
} }

View file

@ -63,6 +63,7 @@ type Config struct {
Shh bool Shh bool
Dial bool Dial bool
Etherbase string
MinerThreads int MinerThreads int
AccountManager *accounts.Manager AccountManager *accounts.Manager
@ -140,6 +141,7 @@ type Ethereum struct {
Mining bool Mining bool
DataDir string DataDir string
etherbase common.Address
clientVersion string clientVersion string
ethVersionId int ethVersionId int
netVersionId int netVersionId int
@ -185,6 +187,7 @@ func New(config *Config) (*Ethereum, error) {
eventMux: &event.TypeMux{}, eventMux: &event.TypeMux{},
accountManager: config.AccountManager, accountManager: config.AccountManager,
DataDir: config.DataDir, DataDir: config.DataDir,
etherbase: common.HexToAddress(config.Etherbase),
clientVersion: config.Name, // TODO should separate from Name clientVersion: config.Name, // TODO should separate from Name
ethVersionId: config.ProtocolVersion, ethVersionId: config.ProtocolVersion,
netVersionId: config.NetworkId, netVersionId: config.NetworkId,
@ -297,15 +300,31 @@ func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
} }
func (s *Ethereum) StartMining() error { func (s *Ethereum) StartMining() error {
cb, err := s.accountManager.Coinbase() eb, err := s.Etherbase()
if err != nil { if err != nil {
servlogger.Errorf("Cannot start mining without coinbase: %v\n", err) err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
return fmt.Errorf("no coinbase: %v", err) servlogger.Errorln(err)
return err
} }
s.miner.Start(common.BytesToAddress(cb))
s.miner.Start(eb)
return nil return nil
} }
func (s *Ethereum) Etherbase() (eb common.Address, err error) {
eb = s.etherbase
if (eb == common.Address{}) {
var ebbytes []byte
ebbytes, err = s.accountManager.Primary()
eb = common.BytesToAddress(ebbytes)
if (eb == common.Address{}) {
err = fmt.Errorf("no accounts found")
}
}
return
}
func (s *Ethereum) StopMining() { s.miner.Stop() } func (s *Ethereum) StopMining() { s.miner.Stop() }
func (s *Ethereum) IsMining() bool { return s.miner.Mining() } func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) Miner() *miner.Miner { return s.miner }

View file

@ -2,9 +2,9 @@ package jsre
import ( import (
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"io/ioutil"
"os"
"testing" "testing"
"github.com/ethereum/go-ethereum/common"
) )
type testNativeObjectBinding struct { type testNativeObjectBinding struct {
@ -26,7 +26,7 @@ func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value
func TestExec(t *testing.T) { func TestExec(t *testing.T) {
jsre := New("/tmp") jsre := New("/tmp")
common.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`)) ioutil.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`), os.ModePerm)
err := jsre.Exec("test.js") err := jsre.Exec("test.js")
if err != nil { if err != nil {
t.Errorf("expected no error, got %v", err) t.Errorf("expected no error, got %v", err)
@ -64,7 +64,7 @@ func TestBind(t *testing.T) {
func TestLoadScript(t *testing.T) { func TestLoadScript(t *testing.T) {
jsre := New("/tmp") jsre := New("/tmp")
common.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`)) ioutil.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`), os.ModePerm)
_, err := jsre.Run(`loadScript("test.js")`) _, err := jsre.Run(`loadScript("test.js")`)
if err != nil { if err != nil {
t.Errorf("expected no error, got %v", err) t.Errorf("expected no error, got %v", err)

View file

@ -1,12 +1,15 @@
package miner package miner
import ( import (
"sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
) )
type CpuMiner struct { type CpuMiner struct {
chMu sync.Mutex
c chan *types.Block c chan *types.Block
quit chan struct{} quit chan struct{}
quitCurrentOp chan struct{} quitCurrentOp chan struct{}
@ -43,16 +46,13 @@ func (self *CpuMiner) Start() {
} }
func (self *CpuMiner) update() { func (self *CpuMiner) update() {
justStarted := true
out: out:
for { for {
select { select {
case block := <-self.c: case block := <-self.c:
if justStarted { self.chMu.Lock()
justStarted = true
} else {
self.quitCurrentOp <- struct{}{} self.quitCurrentOp <- struct{}{}
} self.chMu.Unlock()
go self.mine(block) go self.mine(block)
case <-self.quit: case <-self.quit:
@ -60,6 +60,7 @@ out:
} }
} }
close(self.quitCurrentOp)
done: done:
// Empty channel // Empty channel
for { for {
@ -75,12 +76,20 @@ done:
func (self *CpuMiner) mine(block *types.Block) { func (self *CpuMiner) mine(block *types.Block) {
minerlogger.Debugf("(re)started agent[%d]. mining...\n", self.index) minerlogger.Debugf("(re)started agent[%d]. mining...\n", self.index)
// Reset the channel
self.chMu.Lock()
self.quitCurrentOp = make(chan struct{}, 1)
self.chMu.Unlock()
// Mine
nonce, mixDigest, _ := self.pow.Search(block, self.quitCurrentOp) nonce, mixDigest, _ := self.pow.Search(block, self.quitCurrentOp)
if nonce != 0 { if nonce != 0 {
block.SetNonce(nonce) block.SetNonce(nonce)
block.Header().MixDigest = common.BytesToHash(mixDigest) block.Header().MixDigest = common.BytesToHash(mixDigest)
self.returnCh <- block self.returnCh <- block
//self.returnCh <- Work{block.Number().Uint64(), nonce, mixDigest, seedHash} } else {
self.returnCh <- nil
} }
} }

View file

@ -50,6 +50,7 @@ out:
break out break out
case work := <-a.workCh: case work := <-a.workCh:
a.work = work a.work = work
a.returnCh <- nil
} }
} }
} }

View file

@ -5,6 +5,7 @@ import (
"math/big" "math/big"
"sort" "sort"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -59,12 +60,13 @@ type Agent interface {
type worker struct { type worker struct {
mu sync.Mutex mu sync.Mutex
agents []Agent agents []Agent
recv chan *types.Block recv chan *types.Block
mux *event.TypeMux mux *event.TypeMux
quit chan struct{} quit chan struct{}
pow pow.PoW pow pow.PoW
atWork int atWork int64
eth core.Backend eth core.Backend
chain *core.ChainManager chain *core.ChainManager
@ -107,7 +109,7 @@ func (self *worker) start() {
func (self *worker) stop() { func (self *worker) stop() {
self.mining = false self.mining = false
self.atWork = 0 atomic.StoreInt64(&self.atWork, 0)
close(self.quit) close(self.quit)
} }
@ -135,9 +137,6 @@ out:
self.uncleMu.Unlock() self.uncleMu.Unlock()
} }
if self.atWork == 0 {
self.commitNewWork()
}
case <-self.quit: case <-self.quit:
// stop all agents // stop all agents
for _, agent := range self.agents { for _, agent := range self.agents {
@ -146,6 +145,11 @@ out:
break out break out
case <-timer.C: case <-timer.C:
minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash") minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")
// XXX In case all mined a possible uncle
if atomic.LoadInt64(&self.atWork) == 0 {
self.commitNewWork()
}
} }
} }
@ -155,6 +159,12 @@ out:
func (self *worker) wait() { func (self *worker) wait() {
for { for {
for block := range self.recv { for block := range self.recv {
atomic.AddInt64(&self.atWork, -1)
if block == nil {
continue
}
if err := self.chain.InsertChain(types.Blocks{block}); err == nil { if err := self.chain.InsertChain(types.Blocks{block}); err == nil {
for _, uncle := range block.Uncles() { for _, uncle := range block.Uncles() {
delete(self.possibleUncles, uncle.Hash()) delete(self.possibleUncles, uncle.Hash())
@ -170,7 +180,6 @@ func (self *worker) wait() {
} else { } else {
self.commitNewWork() self.commitNewWork()
} }
self.atWork--
} }
} }
} }
@ -182,8 +191,9 @@ func (self *worker) push() {
// push new work to agents // push new work to agents
for _, agent := range self.agents { for _, agent := range self.agents {
atomic.AddInt64(&self.atWork, 1)
agent.Work() <- self.current.block.Copy() agent.Work() <- self.current.block.Copy()
self.atWork++
} }
} }
} }

View file

@ -3,13 +3,11 @@ package rpc
import ( import (
"encoding/json" "encoding/json"
"math/big" "math/big"
"path"
"sync" "sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
) )
@ -19,15 +17,9 @@ type EthereumApi struct {
db common.Database db common.Database
} }
func NewEthereumApi(xeth *xeth.XEth, dataDir string) *EthereumApi { func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
// What about when dataDir is empty?
db, err := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
if err != nil {
panic(err)
}
api := &EthereumApi{ api := &EthereumApi{
eth: xeth, eth: xeth,
db: db,
} }
return api return api
@ -44,10 +36,6 @@ func (api *EthereumApi) xethAtStateNum(num int64) *xeth.XEth {
return api.xeth().AtStateNum(num) return api.xeth().AtStateNum(num)
} }
func (api *EthereumApi) Close() {
api.db.Close()
}
func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/JSON-RPC // Spec at https://github.com/ethereum/wiki/wiki/JSON-RPC
rpclogger.Debugf("%s %s", req.Method, req.Params) rpclogger.Debugf("%s %s", req.Method, req.Params)
@ -370,7 +358,8 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
api.db.Put([]byte(args.Database+args.Key), args.Value) api.xeth().DbPut([]byte(args.Database+args.Key), args.Value)
*reply = true *reply = true
case "db_getString": case "db_getString":
args := new(DbArgs) args := new(DbArgs)
@ -382,7 +371,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
res, _ := api.db.Get([]byte(args.Database + args.Key)) res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
*reply = string(res) *reply = string(res)
case "db_putHex": case "db_putHex":
args := new(DbHexArgs) args := new(DbHexArgs)
@ -394,7 +383,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
api.db.Put([]byte(args.Database+args.Key), args.Value) api.xeth().DbPut([]byte(args.Database+args.Key), args.Value)
*reply = true *reply = true
case "db_getHex": case "db_getHex":
args := new(DbHexArgs) args := new(DbHexArgs)
@ -406,7 +395,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
res, _ := api.db.Get([]byte(args.Database + args.Key)) res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
*reply = common.ToHex(res) *reply = common.ToHex(res)
case "shh_version": case "shh_version":
*reply = api.xeth().WhisperVersion() *reply = api.xeth().WhisperVersion()

View file

@ -6,7 +6,7 @@ import (
"testing" "testing"
// "time" // "time"
"github.com/ethereum/go-ethereum/xeth" // "github.com/ethereum/go-ethereum/xeth"
) )
func TestWeb3Sha3(t *testing.T) { func TestWeb3Sha3(t *testing.T) {
@ -26,49 +26,48 @@ func TestWeb3Sha3(t *testing.T) {
} }
} }
func TestDbStr(t *testing.T) { // func TestDbStr(t *testing.T) {
jsonput := `{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":64}` // jsonput := `{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":64}`
jsonget := `{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":64}` // jsonget := `{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":64}`
expected := "myString" // expected := "myString"
xeth := &xeth.XEth{} // xeth := &xeth.XEth{}
api := NewEthereumApi(xeth, "") // api := NewEthereumApi(xeth)
defer api.db.Close() // var response interface{}
var response interface{}
var req RpcRequest // var req RpcRequest
json.Unmarshal([]byte(jsonput), &req) // json.Unmarshal([]byte(jsonput), &req)
_ = api.GetRequestReply(&req, &response) // _ = api.GetRequestReply(&req, &response)
json.Unmarshal([]byte(jsonget), &req) // json.Unmarshal([]byte(jsonget), &req)
_ = api.GetRequestReply(&req, &response) // _ = api.GetRequestReply(&req, &response)
if response.(string) != expected { // if response.(string) != expected {
t.Errorf("Expected %s got %s", expected, response) // t.Errorf("Expected %s got %s", expected, response)
} // }
} // }
func TestDbHexStr(t *testing.T) { // func TestDbHexStr(t *testing.T) {
jsonput := `{"jsonrpc":"2.0","method":"db_putHex","params":["testDB","beefKey","0xbeef"],"id":64}` // jsonput := `{"jsonrpc":"2.0","method":"db_putHex","params":["testDB","beefKey","0xbeef"],"id":64}`
jsonget := `{"jsonrpc":"2.0","method":"db_getHex","params":["testDB","beefKey"],"id":64}` // jsonget := `{"jsonrpc":"2.0","method":"db_getHex","params":["testDB","beefKey"],"id":64}`
expected := "0xbeef" // expected := "0xbeef"
xeth := &xeth.XEth{} // xeth := &xeth.XEth{}
api := NewEthereumApi(xeth, "") // api := NewEthereumApi(xeth)
defer api.db.Close() // defer api.db.Close()
var response interface{} // var response interface{}
var req RpcRequest // var req RpcRequest
json.Unmarshal([]byte(jsonput), &req) // json.Unmarshal([]byte(jsonput), &req)
_ = api.GetRequestReply(&req, &response) // _ = api.GetRequestReply(&req, &response)
json.Unmarshal([]byte(jsonget), &req) // json.Unmarshal([]byte(jsonget), &req)
_ = api.GetRequestReply(&req, &response) // _ = api.GetRequestReply(&req, &response)
if response.(string) != expected { // if response.(string) != expected {
t.Errorf("Expected %s got %s", expected, response) // t.Errorf("Expected %s got %s", expected, response)
} // }
} // }
// func TestFilterClose(t *testing.T) { // func TestFilterClose(t *testing.T) {
// t.Skip() // t.Skip()

View file

@ -18,8 +18,8 @@ const (
) )
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API. // JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler { func JSONRPC(pipe *xeth.XEth) http.Handler {
api := NewEthereumApi(pipe, dataDir) api := NewEthereumApi(pipe)
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// TODO this needs to be configurable // TODO this needs to be configurable

View file

@ -6,14 +6,14 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
) )
type BlockRes struct { type BlockRes struct {
fullTx bool fullTx bool
BlockNumber int64 `json:"number"` BlockNumber *big.Int `json:"number"`
BlockHash common.Hash `json:"hash"` BlockHash common.Hash `json:"hash"`
ParentHash common.Hash `json:"parentHash"` ParentHash common.Hash `json:"parentHash"`
Nonce [8]byte `json:"nonce"` Nonce [8]byte `json:"nonce"`
@ -22,13 +22,13 @@ type BlockRes struct {
TransactionRoot common.Hash `json:"transactionRoot"` TransactionRoot common.Hash `json:"transactionRoot"`
StateRoot common.Hash `json:"stateRoot"` StateRoot common.Hash `json:"stateRoot"`
Miner common.Address `json:"miner"` Miner common.Address `json:"miner"`
Difficulty int64 `json:"difficulty"` Difficulty *big.Int `json:"difficulty"`
TotalDifficulty int64 `json:"totalDifficulty"` TotalDifficulty *big.Int `json:"totalDifficulty"`
Size int64 `json:"size"` Size *big.Int `json:"size"`
ExtraData []byte `json:"extraData"` ExtraData []byte `json:"extraData"`
GasLimit int64 `json:"gasLimit"` GasLimit *big.Int `json:"gasLimit"`
MinGasPrice int64 `json:"minGasPrice"` MinGasPrice int64 `json:"minGasPrice"`
GasUsed int64 `json:"gasUsed"` GasUsed *big.Int `json:"gasUsed"`
UnixTimestamp int64 `json:"timestamp"` UnixTimestamp int64 `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"` Transactions []*TransactionRes `json:"transactions"`
Uncles []common.Hash `json:"uncles"` Uncles []common.Hash `json:"uncles"`
@ -58,7 +58,7 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
} }
// convert strict types to hexified strings // convert strict types to hexified strings
ext.BlockNumber = common.ToHex(big.NewInt(b.BlockNumber).Bytes()) ext.BlockNumber = common.ToHex(b.BlockNumber.Bytes())
ext.BlockHash = b.BlockHash.Hex() ext.BlockHash = b.BlockHash.Hex()
ext.ParentHash = b.ParentHash.Hex() ext.ParentHash = b.ParentHash.Hex()
ext.Nonce = common.ToHex(b.Nonce[:]) ext.Nonce = common.ToHex(b.Nonce[:])
@ -67,13 +67,13 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
ext.TransactionRoot = b.TransactionRoot.Hex() ext.TransactionRoot = b.TransactionRoot.Hex()
ext.StateRoot = b.StateRoot.Hex() ext.StateRoot = b.StateRoot.Hex()
ext.Miner = b.Miner.Hex() ext.Miner = b.Miner.Hex()
ext.Difficulty = common.ToHex(big.NewInt(b.Difficulty).Bytes()) ext.Difficulty = common.ToHex(b.Difficulty.Bytes())
ext.TotalDifficulty = common.ToHex(big.NewInt(b.TotalDifficulty).Bytes()) ext.TotalDifficulty = common.ToHex(b.TotalDifficulty.Bytes())
ext.Size = common.ToHex(big.NewInt(b.Size).Bytes()) ext.Size = common.ToHex(b.Size.Bytes())
// ext.ExtraData = common.ToHex(b.ExtraData) // ext.ExtraData = common.ToHex(b.ExtraData)
ext.GasLimit = common.ToHex(big.NewInt(b.GasLimit).Bytes()) ext.GasLimit = common.ToHex(b.GasLimit.Bytes())
// ext.MinGasPrice = common.ToHex(big.NewInt(b.MinGasPrice).Bytes()) // ext.MinGasPrice = common.ToHex(big.NewInt(b.MinGasPrice).Bytes())
ext.GasUsed = common.ToHex(big.NewInt(b.GasUsed).Bytes()) ext.GasUsed = common.ToHex(b.GasUsed.Bytes())
ext.UnixTimestamp = common.ToHex(big.NewInt(b.UnixTimestamp).Bytes()) ext.UnixTimestamp = common.ToHex(big.NewInt(b.UnixTimestamp).Bytes())
ext.Transactions = make([]interface{}, len(b.Transactions)) ext.Transactions = make([]interface{}, len(b.Transactions))
if b.fullTx { if b.fullTx {
@ -99,7 +99,7 @@ func NewBlockRes(block *types.Block) *BlockRes {
} }
res := new(BlockRes) res := new(BlockRes)
res.BlockNumber = block.Number().Int64() res.BlockNumber = block.Number()
res.BlockHash = block.Hash() res.BlockHash = block.Hash()
res.ParentHash = block.ParentHash() res.ParentHash = block.ParentHash()
res.Nonce = block.Header().Nonce res.Nonce = block.Header().Nonce
@ -108,15 +108,13 @@ func NewBlockRes(block *types.Block) *BlockRes {
res.TransactionRoot = block.Header().TxHash res.TransactionRoot = block.Header().TxHash
res.StateRoot = block.Root() res.StateRoot = block.Root()
res.Miner = block.Header().Coinbase res.Miner = block.Header().Coinbase
res.Difficulty = block.Difficulty().Int64() res.Difficulty = block.Difficulty()
if block.Td != nil { res.TotalDifficulty = block.Td
res.TotalDifficulty = block.Td.Int64() res.Size = big.NewInt(int64(block.Size()))
}
res.Size = int64(block.Size())
// res.ExtraData = // res.ExtraData =
res.GasLimit = block.GasLimit().Int64() res.GasLimit = block.GasLimit()
// res.MinGasPrice = // res.MinGasPrice =
res.GasUsed = block.GasUsed().Int64() res.GasUsed = block.GasUsed()
res.UnixTimestamp = block.Time() res.UnixTimestamp = block.Time()
res.Transactions = make([]*TransactionRes, len(block.Transactions())) res.Transactions = make([]*TransactionRes, len(block.Transactions()))
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
@ -135,15 +133,15 @@ func NewBlockRes(block *types.Block) *BlockRes {
type TransactionRes struct { type TransactionRes struct {
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
Nonce int64 `json:"nonce"` Nonce uint64 `json:"nonce"`
BlockHash common.Hash `json:"blockHash,omitempty"` BlockHash common.Hash `json:"blockHash,omitempty"`
BlockNumber int64 `json:"blockNumber,omitempty"` BlockNumber int64 `json:"blockNumber,omitempty"`
TxIndex int64 `json:"transactionIndex,omitempty"` TxIndex int64 `json:"transactionIndex,omitempty"`
From common.Address `json:"from"` From common.Address `json:"from"`
To *common.Address `json:"to"` To *common.Address `json:"to"`
Value int64 `json:"value"` Value *big.Int `json:"value"`
Gas int64 `json:"gas"` Gas *big.Int `json:"gas"`
GasPrice int64 `json:"gasPrice"` GasPrice *big.Int `json:"gasPrice"`
Input []byte `json:"input"` Input []byte `json:"input"`
} }
@ -155,7 +153,7 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
BlockNumber string `json:"blockNumber,omitempty"` BlockNumber string `json:"blockNumber,omitempty"`
TxIndex string `json:"transactionIndex,omitempty"` TxIndex string `json:"transactionIndex,omitempty"`
From string `json:"from"` From string `json:"from"`
To string `json:"to"` To interface{} `json:"to"`
Value string `json:"value"` Value string `json:"value"`
Gas string `json:"gas"` Gas string `json:"gas"`
GasPrice string `json:"gasPrice"` GasPrice string `json:"gasPrice"`
@ -163,19 +161,19 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
} }
ext.Hash = t.Hash.Hex() ext.Hash = t.Hash.Hex()
ext.Nonce = common.ToHex(big.NewInt(t.Nonce).Bytes()) ext.Nonce = common.ToHex(big.NewInt(int64(t.Nonce)).Bytes())
ext.BlockHash = t.BlockHash.Hex() ext.BlockHash = t.BlockHash.Hex()
ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes()) ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes())
ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes()) ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes())
ext.From = t.From.Hex() ext.From = t.From.Hex()
if t.To == nil { if t.To == nil {
ext.To = "0x00" ext.To = nil
} else { } else {
ext.To = t.To.Hex() ext.To = t.To.Hex()
} }
ext.Value = common.ToHex(big.NewInt(t.Value).Bytes()) ext.Value = common.ToHex(t.Value.Bytes())
ext.Gas = common.ToHex(big.NewInt(t.Gas).Bytes()) ext.Gas = common.ToHex(t.Gas.Bytes())
ext.GasPrice = common.ToHex(big.NewInt(t.GasPrice).Bytes()) ext.GasPrice = common.ToHex(t.GasPrice.Bytes())
ext.Input = common.ToHex(t.Input) ext.Input = common.ToHex(t.Input)
return json.Marshal(ext) return json.Marshal(ext)
@ -184,12 +182,12 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
func NewTransactionRes(tx *types.Transaction) *TransactionRes { func NewTransactionRes(tx *types.Transaction) *TransactionRes {
var v = new(TransactionRes) var v = new(TransactionRes)
v.Hash = tx.Hash() v.Hash = tx.Hash()
v.Nonce = int64(tx.Nonce()) v.Nonce = tx.Nonce()
v.From, _ = tx.From() v.From, _ = tx.From()
v.To = tx.To() v.To = tx.To()
v.Value = tx.Value().Int64() v.Value = tx.Value()
v.Gas = tx.Gas().Int64() v.Gas = tx.Gas()
v.GasPrice = tx.GasPrice().Int64() v.GasPrice = tx.GasPrice()
v.Input = tx.Data() v.Input = tx.Data()
return v return v
} }
@ -218,25 +216,48 @@ type FilterWhisperRes struct {
} }
type LogRes struct { type LogRes struct {
Address common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data []byte `json:"data"`
Number uint64 `json:"number"`
}
func NewLogRes(log state.Log) LogRes {
var l LogRes
l.Topics = make([]common.Hash, len(log.Topics()))
l.Address = log.Address()
l.Data = log.Data()
l.Number = log.Number()
for j, topic := range log.Topics() {
l.Topics[j] = topic
}
return l
}
func (l *LogRes) MarshalJSON() ([]byte, error) {
var ext struct {
Address string `json:"address"` Address string `json:"address"`
Topics []string `json:"topics"` Topics []string `json:"topics"`
Data string `json:"data"` Data string `json:"data"`
Number uint64 `json:"number"` Number string `json:"number"`
}
ext.Address = l.Address.Hex()
ext.Data = common.Bytes2Hex(l.Data)
ext.Number = common.Bytes2Hex(big.NewInt(int64(l.Number)).Bytes())
ext.Topics = make([]string, len(l.Topics))
for i, v := range l.Topics {
ext.Topics[i] = v.Hex()
}
return json.Marshal(ext)
} }
func NewLogsRes(logs state.Logs) (ls []LogRes) { func NewLogsRes(logs state.Logs) (ls []LogRes) {
ls = make([]LogRes, len(logs)) ls = make([]LogRes, len(logs))
for i, log := range logs { for i, log := range logs {
var l LogRes ls[i] = NewLogRes(log)
l.Topics = make([]string, len(log.Topics()))
l.Address = log.Address().Hex()
l.Data = common.ToHex(log.Data())
l.Number = log.Number()
for j, topic := range log.Topics() {
l.Topics[j] = topic.Hex()
}
ls[i] = l
} }
return return

123
rpc/responses_test.go Normal file
View file

@ -0,0 +1,123 @@
package rpc
import (
"encoding/json"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
)
func TestNewBlockRes(t *testing.T) {
parentHash := common.HexToHash("0x01")
coinbase := common.HexToAddress("0x01")
root := common.HexToHash("0x01")
difficulty := common.Big1
nonce := uint64(1)
extra := ""
block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, extra)
_ = NewBlockRes(block)
}
func TestBlockRes(t *testing.T) {
v := &BlockRes{
BlockNumber: big.NewInt(0),
BlockHash: common.HexToHash("0x0"),
ParentHash: common.HexToHash("0x0"),
Nonce: [8]byte{0, 0, 0, 0, 0, 0, 0, 0},
Sha3Uncles: common.HexToHash("0x0"),
LogsBloom: types.BytesToBloom([]byte{0}),
TransactionRoot: common.HexToHash("0x0"),
StateRoot: common.HexToHash("0x0"),
Miner: common.HexToAddress("0x0"),
Difficulty: big.NewInt(0),
TotalDifficulty: big.NewInt(0),
Size: big.NewInt(0),
ExtraData: []byte{},
GasLimit: big.NewInt(0),
MinGasPrice: int64(0),
GasUsed: big.NewInt(0),
UnixTimestamp: int64(0),
// Transactions []*TransactionRes `json:"transactions"`
// Uncles []common.Hash `json:"uncles"`
}
_, _ = json.Marshal(v)
// fmt.Println(string(j))
}
func TestTransactionRes(t *testing.T) {
a := common.HexToAddress("0x0")
v := &TransactionRes{
Hash: common.HexToHash("0x0"),
Nonce: uint64(0),
BlockHash: common.HexToHash("0x0"),
BlockNumber: int64(0),
TxIndex: int64(0),
From: common.HexToAddress("0x0"),
To: &a,
Value: big.NewInt(0),
Gas: big.NewInt(0),
GasPrice: big.NewInt(0),
Input: []byte{0},
}
_, _ = json.Marshal(v)
}
func TestNewTransactionRes(t *testing.T) {
to := common.HexToAddress("0x02")
amount := big.NewInt(1)
gasAmount := big.NewInt(1)
gasPrice := big.NewInt(1)
data := []byte{1, 2, 3}
tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data)
_ = NewTransactionRes(tx)
}
func TestLogRes(t *testing.T) {
topics := make([]common.Hash, 3)
topics = append(topics, common.HexToHash("0x00"))
topics = append(topics, common.HexToHash("0x10"))
topics = append(topics, common.HexToHash("0x20"))
v := &LogRes{
Topics: topics,
Address: common.HexToAddress("0x0"),
Data: []byte{1, 2, 3},
Number: uint64(5),
}
_, _ = json.Marshal(v)
}
func MakeStateLog(num int) state.Log {
address := common.HexToAddress("0x0")
data := []byte{1, 2, 3}
number := uint64(num)
topics := make([]common.Hash, 3)
topics = append(topics, common.HexToHash("0x00"))
topics = append(topics, common.HexToHash("0x10"))
topics = append(topics, common.HexToHash("0x20"))
log := state.NewLog(address, topics, data, number)
return log
}
func TestNewLogRes(t *testing.T) {
log := MakeStateLog(0)
_ = NewLogRes(log)
}
func TestNewLogsRes(t *testing.T) {
logs := make([]state.Log, 3)
logs[0] = MakeStateLog(1)
logs[1] = MakeStateLog(2)
logs[2] = MakeStateLog(3)
_ = NewLogsRes(logs)
}

View file

@ -209,6 +209,16 @@ func (self *XEth) Accounts() []string {
return accountAddresses return accountAddresses
} }
func (self *XEth) DbPut(key, val []byte) bool {
self.backend.ExtraDb().Put(key, val)
return true
}
func (self *XEth) DbGet(key []byte) ([]byte, error) {
val, err := self.backend.ExtraDb().Get(key)
return val, err
}
func (self *XEth) PeerCount() int { func (self *XEth) PeerCount() int {
return self.backend.PeerCount() return self.backend.PeerCount()
} }
@ -250,8 +260,8 @@ func (self *XEth) IsListening() bool {
} }
func (self *XEth) Coinbase() string { func (self *XEth) Coinbase() string {
cb, _ := self.backend.AccountManager().Coinbase() eb, _ := self.backend.Etherbase()
return common.ToHex(cb) return eb.Hex()
} }
func (self *XEth) NumberToHuman(balance string) string { func (self *XEth) NumberToHuman(balance string) string {