mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
Merge branch 'develop' into bzz
This commit is contained in:
commit
26b8e0fe52
31 changed files with 800 additions and 455 deletions
12
README.md
12
README.md
|
|
@ -20,7 +20,7 @@ Mist (GUI):
|
|||
|
||||
`go get github.com/ethereum/go-ethereum/cmd/mist`
|
||||
|
||||
Ethereum (CLI):
|
||||
Geth (CLI):
|
||||
|
||||
`go get github.com/ethereum/go-ethereum/cmd/ethereum`
|
||||
|
||||
|
|
@ -32,10 +32,10 @@ Mist (GUI):
|
|||
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.
|
||||
|
|
@ -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):
|
||||
|
||||
* `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
|
||||
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite:
|
||||
`cat file | ethtest`.
|
||||
|
|
@ -73,12 +73,12 @@ Go Ethereum comes with several wrappers/executables found in
|
|||
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:
|
||||
|
||||
```
|
||||
ethereum -help
|
||||
geth -help
|
||||
```
|
||||
|
||||
For further details on options, see the [wiki](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)
|
||||
|
|
|
|||
|
|
@ -36,9 +36,8 @@ import (
|
|||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"os"
|
||||
|
||||
"errors"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -82,13 +81,7 @@ func (am *Manager) HasAccount(addr []byte) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Coinbase returns the account address that mining rewards are sent to.
|
||||
func (am *Manager) Coinbase() (addr []byte, err error) {
|
||||
// TODO: persist coinbase address on disk
|
||||
return am.firstAddr()
|
||||
}
|
||||
|
||||
func (am *Manager) firstAddr() ([]byte, error) {
|
||||
func (am *Manager) Primary() (addr []byte, err error) {
|
||||
addrs, err := am.keyStore.GetKeyAddresses()
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrNoKeys
|
||||
|
|
@ -208,3 +201,37 @@ func zeroKey(k *ecdsa.PrivateKey) {
|
|||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package blockpool
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -45,17 +45,15 @@ func getStatusValues(s *Status) []int {
|
|||
func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err error) {
|
||||
s := bp.Status()
|
||||
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)
|
||||
for i, v := range expected {
|
||||
if i == 0 || i == 7 {
|
||||
continue //hack
|
||||
}
|
||||
err = test.CheckInt(statusFields[i], got[i], v, t)
|
||||
// fmt.Printf("%v: %v (%v)\n", statusFields[i], got[i], v)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
@ -63,6 +61,25 @@ func checkStatus(t *testing.T, bp *BlockPool, syncing bool, expected []int) (err
|
|||
|
||||
func TestBlockPoolStatus(t *testing.T) {
|
||||
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)
|
||||
blockPoolTester.blockChain[0] = nil
|
||||
blockPoolTester.initRefBlockChain(12)
|
||||
|
|
@ -70,6 +87,7 @@ func TestBlockPoolStatus(t *testing.T) {
|
|||
delete(blockPoolTester.refBlockChain, 6)
|
||||
|
||||
blockPool.Start()
|
||||
defer blockPool.Stop()
|
||||
blockPoolTester.tds = make(map[int]int)
|
||||
blockPoolTester.tds[9] = 1
|
||||
blockPoolTester.tds[11] = 3
|
||||
|
|
@ -79,73 +97,67 @@ func TestBlockPoolStatus(t *testing.T) {
|
|||
peer2 := blockPoolTester.newPeer("peer2", 2, 6)
|
||||
peer3 := blockPoolTester.newPeer("peer3", 3, 11)
|
||||
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
|
||||
|
||||
var expected []int
|
||||
var err error
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.AddPeer()
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlocks(8, 9)
|
||||
expected = []int{0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0}
|
||||
// err = checkStatus(t, blockPool, true, expected)
|
||||
expected = []int{1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0}
|
||||
err = checkStatus(nil, blockPool, true, expected)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlockHashes(9, 8, 7, 3, 2)
|
||||
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(t, blockPool, true, expected)
|
||||
err = checkStatus(nil, blockPool, true, expected)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlocks(3, 7, 8)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlocks(2, 3)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer4.AddPeer()
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer4.sendBlockHashes(12, 11)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer2.AddPeer()
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
|
@ -153,76 +165,76 @@ func TestBlockPoolStatus(t *testing.T) {
|
|||
peer2.serveBlocks(5, 6)
|
||||
peer2.serveBlockHashes(6, 5, 4, 3, 2)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer2.serveBlocks(2, 3, 4)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
blockPool.RemovePeer("peer2")
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlockHashes(2, 1, 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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlocks(1, 2)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer1.serveBlocks(4, 5)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer3.AddPeer()
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer3.serveBlocks(10, 11)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer3.serveBlockHashes(11, 10, 9)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
peer4.sendBlocks(11, 12)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
peer3.serveBlocks(9, 10)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
|
@ -231,10 +243,9 @@ func TestBlockPoolStatus(t *testing.T) {
|
|||
blockPool.Wait(waitTimeout)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
blockPool.Stop()
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,16 +10,20 @@ import (
|
|||
|
||||
func CheckInt(name string, got int, expected int, t *testing.T) (err error) {
|
||||
if got != expected {
|
||||
t.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got)
|
||||
err = fmt.Errorf("")
|
||||
err = fmt.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got)
|
||||
if t != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CheckDuration(name string, got time.Duration, expected time.Duration, t *testing.T) (err error) {
|
||||
if got != expected {
|
||||
t.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got)
|
||||
err = fmt.Errorf("")
|
||||
err = fmt.Errorf("status for %v incorrect. expected %v, got %v", name, expected, got)
|
||||
if t != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"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/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
|
@ -69,14 +69,13 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
|
|||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
}
|
||||
dataDir := js.ethereum.DataDir
|
||||
|
||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
||||
if err != nil {
|
||||
fmt.Printf("Can't listen on %s:%d: %v", addr, port, err)
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
@ -67,14 +67,14 @@ type jsre struct {
|
|||
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.xeth = xeth.New(ethereum, js)
|
||||
js.re = re.New(libPath)
|
||||
js.apiBindings()
|
||||
js.adminBindings()
|
||||
|
||||
if !liner.TerminalSupported() {
|
||||
if !liner.TerminalSupported() || !interactive {
|
||||
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
||||
} else {
|
||||
lr := liner.NewLiner()
|
||||
|
|
@ -91,8 +91,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
|
|||
|
||||
func (js *jsre) apiBindings() {
|
||||
|
||||
ethApi := rpc.NewEthereumApi(js.xeth, js.ethereum.DataDir)
|
||||
ethApi.Close()
|
||||
ethApi := rpc.NewEthereumApi(js.xeth)
|
||||
//js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal))
|
||||
|
||||
jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re)
|
||||
|
|
@ -102,7 +101,7 @@ func (js *jsre) apiBindings() {
|
|||
jethObj := t.Object()
|
||||
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 {
|
||||
utils.Fatalf("Error loading bignumber.js: %v", err)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
|
@ -9,7 +10,6 @@ import (
|
|||
"github.com/robertkrimen/otto"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"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
|
||||
ks := crypto.NewKeyStorePlain("/tmp/eth/keys")
|
||||
common.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d",
|
||||
[]byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`))
|
||||
ioutil.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d",
|
||||
[]byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`), os.ModePerm)
|
||||
|
||||
port++
|
||||
ethereum, err = eth.New(ð.Config{
|
||||
|
|
@ -47,7 +47,7 @@ func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) {
|
|||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -23,14 +23,15 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
|
|
@ -41,8 +42,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ClientIdentifier = "Ethereum(G)"
|
||||
Version = "0.9.3"
|
||||
ClientIdentifier = "Geth"
|
||||
Version = "0.9.4"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -74,10 +75,44 @@ Regular users do not need to execute it.
|
|||
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,
|
||||
Name: "account",
|
||||
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{
|
||||
{
|
||||
Action: accountList,
|
||||
|
|
@ -88,6 +123,51 @@ The output of this command is supposed to be machine-readable.
|
|||
Action: accountCreate,
|
||||
Name: "new",
|
||||
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,
|
||||
Name: "console",
|
||||
Usage: `Ethereum Console: interactive JavaScript environment`,
|
||||
Usage: `Geth Console: interactive JavaScript environment`,
|
||||
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
|
||||
`,
|
||||
},
|
||||
{
|
||||
Action: execJSFiles,
|
||||
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: `
|
||||
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{
|
||||
utils.UnlockedAccountFlag,
|
||||
utils.PasswordFileFlag,
|
||||
utils.BootnodesFlag,
|
||||
utils.DataDirFlag,
|
||||
utils.JSpathFlag,
|
||||
|
|
@ -138,6 +221,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
|
|||
utils.LogJSONFlag,
|
||||
utils.LogLevelFlag,
|
||||
utils.MaxPeersFlag,
|
||||
utils.EtherbaseFlag,
|
||||
utils.MinerThreadsFlag,
|
||||
utils.MiningEnabledFlag,
|
||||
utils.NATFlag,
|
||||
|
|
@ -146,7 +230,6 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
|
|||
utils.RPCEnabledFlag,
|
||||
utils.RPCListenAddrFlag,
|
||||
utils.RPCPortFlag,
|
||||
utils.UnencryptedKeysFlag,
|
||||
utils.VMDebugFlag,
|
||||
utils.ProtocolVersionFlag,
|
||||
utils.NetworkIdFlag,
|
||||
|
|
@ -194,7 +277,7 @@ func console(ctx *cli.Context) {
|
|||
}
|
||||
|
||||
startEth(ctx, ethereum)
|
||||
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name))
|
||||
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true)
|
||||
repl.interactive()
|
||||
|
||||
ethereum.Stop()
|
||||
|
|
@ -209,7 +292,7 @@ func execJSFiles(ctx *cli.Context) {
|
|||
}
|
||||
|
||||
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() {
|
||||
repl.exec(file)
|
||||
}
|
||||
|
|
@ -218,22 +301,36 @@ func execJSFiles(ctx *cli.Context) {
|
|||
ethereum.WaitForShutdown()
|
||||
}
|
||||
|
||||
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
||||
utils.StartEthereum(eth)
|
||||
|
||||
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
|
||||
var err error
|
||||
// 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
|
||||
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 {
|
||||
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.
|
||||
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
||||
|
|
@ -255,16 +352,15 @@ func accountList(ctx *cli.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func accountCreate(ctx *cli.Context) {
|
||||
am := utils.GetAccountManager(ctx)
|
||||
passphrase := ""
|
||||
if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) {
|
||||
fmt.Println("The new account will be encrypted with a passphrase.")
|
||||
fmt.Println("Please enter a passphrase now.")
|
||||
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) {
|
||||
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
|
||||
if len(passfile) == 0 {
|
||||
fmt.Println(desc)
|
||||
auth, err := readPassword("Passphrase: ", true)
|
||||
if err != nil {
|
||||
utils.Fatalf("%v", err)
|
||||
}
|
||||
if confirmation {
|
||||
confirm, err := readPassword("Repeat Passphrase: ", false)
|
||||
if err != nil {
|
||||
utils.Fatalf("%v", err)
|
||||
|
|
@ -272,13 +368,61 @@ func accountCreate(ctx *cli.Context) {
|
|||
if auth != confirm {
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
|
|
@ -325,7 +469,6 @@ func dump(ctx *cli.Context) {
|
|||
} else {
|
||||
statedb := state.New(block.Root(), stateDb)
|
||||
fmt.Printf("%s\n", statedb.Dump())
|
||||
// fmt.Println(block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,13 +22,14 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"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/types"
|
||||
)
|
||||
|
||||
type plugin struct {
|
||||
|
|
@ -46,14 +47,14 @@ func (self *Gui) AddPlugin(pluginPath string) {
|
|||
self.plugins[pluginPath] = plugin{Name: pluginPath, Path: pluginPath}
|
||||
|
||||
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) {
|
||||
delete(self.plugins, pluginPath)
|
||||
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import "C"
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"path"
|
||||
"runtime"
|
||||
|
|
@ -91,8 +92,8 @@ func NewWindow(ethereum *eth.Ethereum) *Gui {
|
|||
plugins: make(map[string]plugin),
|
||||
serviceEvents: make(chan ServEv, 1),
|
||||
}
|
||||
data, _ := common.ReadAllFile(path.Join(ethereum.DataDir, "plugins.json"))
|
||||
json.Unmarshal([]byte(data), &gui.plugins)
|
||||
data, _ := ioutil.ReadFile(path.Join(ethereum.DataDir, "plugins.json"))
|
||||
json.Unmarshal(data, &gui.plugins)
|
||||
|
||||
return gui
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,15 +96,21 @@ var (
|
|||
Name: "mine",
|
||||
Usage: "Enable mining",
|
||||
}
|
||||
|
||||
// key settings
|
||||
UnencryptedKeysFlag = cli.BoolFlag{
|
||||
Name: "unencrypted-keys",
|
||||
Usage: "disable private key disk encryption (for testing)",
|
||||
EtherbaseFlag = cli.StringFlag{
|
||||
Name: "etherbase",
|
||||
Usage: "public address for block mining rewards. By default the address of your primary account is used",
|
||||
Value: "primary",
|
||||
}
|
||||
|
||||
UnlockedAccountFlag = cli.StringFlag{
|
||||
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
|
||||
|
|
@ -214,6 +220,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
|||
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
||||
LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
|
||||
LogJSON: ctx.GlobalString(LogJSONFlag.Name),
|
||||
Etherbase: ctx.GlobalString(EtherbaseFlag.Name),
|
||||
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
||||
AccountManager: GetAccountManager(ctx),
|
||||
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 {
|
||||
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
||||
var ks crypto.KeyStore2
|
||||
if ctx.GlobalBool(UnencryptedKeysFlag.Name) {
|
||||
ks = crypto.NewKeyStorePlain(path.Join(dataDir, "plainkeys"))
|
||||
} else {
|
||||
ks = crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
|
||||
}
|
||||
ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
|
||||
return accounts.NewManager(ks)
|
||||
}
|
||||
|
||||
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
|
||||
addr := ctx.GlobalString(RPCListenAddrFlag.Name)
|
||||
port := ctx.GlobalInt(RPCPortFlag.Name)
|
||||
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
||||
fmt.Println("Starting RPC on port: ", port)
|
||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
||||
if err != nil {
|
||||
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)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package common
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
|
|
@ -43,35 +42,6 @@ func FileExist(filePath string) bool {
|
|||
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 {
|
||||
if path.IsAbs(filename) {
|
||||
return filename
|
||||
|
|
|
|||
|
|
@ -2,56 +2,11 @@ package common
|
|||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
// "testing"
|
||||
|
||||
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{}
|
||||
|
||||
var _ = checker.Suite(&CommonSuite{})
|
||||
|
|
|
|||
164
core/vm/gas.go
164
core/vm/gas.go
|
|
@ -1,11 +1,9 @@
|
|||
package vm
|
||||
|
||||
import "math/big"
|
||||
|
||||
type req struct {
|
||||
stack int
|
||||
gas *big.Int
|
||||
}
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
GasQuickStep = big.NewInt(2)
|
||||
|
|
@ -56,75 +54,30 @@ var (
|
|||
GasCopyWord = big.NewInt(3)
|
||||
)
|
||||
|
||||
var _baseCheck = map[OpCode]req{
|
||||
// Req stack Gas price
|
||||
ADD: {2, GasFastestStep},
|
||||
LT: {2, GasFastestStep},
|
||||
GT: {2, GasFastestStep},
|
||||
SLT: {2, GasFastestStep},
|
||||
SGT: {2, GasFastestStep},
|
||||
EQ: {2, GasFastestStep},
|
||||
ISZERO: {1, GasFastestStep},
|
||||
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) error {
|
||||
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
||||
// PUSH is also allowed to calculate the same price for all PUSHes
|
||||
// DUP requirements are handled elsewhere (except for the stack limit check)
|
||||
if op >= PUSH1 && op <= PUSH32 {
|
||||
op = PUSH1
|
||||
}
|
||||
if op >= DUP1 && op <= DUP16 {
|
||||
op = DUP1
|
||||
}
|
||||
|
||||
func baseCheck(op OpCode, stack *stack, gas *big.Int) {
|
||||
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)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toWordSize(size *big.Int) *big.Int {
|
||||
|
|
@ -133,3 +86,74 @@ func toWordSize(size *big.Int) *big.Int {
|
|||
tmp.Div(tmp, u256(32))
|
||||
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},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,21 +15,17 @@ func NewMemory() *Memory {
|
|||
}
|
||||
|
||||
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
|
||||
lenSize := uint64(len(m.store) - 1)
|
||||
if totSize > lenSize {
|
||||
// Calculate the diff between the sizes
|
||||
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...)
|
||||
// It's possible the offset is greater than 0 and size equals 0. This is because
|
||||
// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
|
||||
if size > 0 {
|
||||
copy(m.store[offset:offset+size], common.RightPadBytes(value, int(size)))
|
||||
}
|
||||
}
|
||||
copy(m.store[offset:offset+size], value)
|
||||
}
|
||||
|
||||
func (m *Memory) Resize(size uint64) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import (
|
|||
"math/big"
|
||||
)
|
||||
|
||||
const maxStack = 1024
|
||||
|
||||
func newStack() *stack {
|
||||
return &stack{}
|
||||
}
|
||||
|
|
@ -15,6 +17,7 @@ type stack struct {
|
|||
}
|
||||
|
||||
func (st *stack) push(d *big.Int) {
|
||||
// NOTE push limit (1024) is checked in baseCheck
|
||||
stackItem := new(big.Int).Set(d)
|
||||
if len(st.data) > st.ptr {
|
||||
st.data[st.ptr] = stackItem
|
||||
|
|
@ -46,10 +49,11 @@ func (st *stack) peek() *big.Int {
|
|||
return st.data[st.len()-1]
|
||||
}
|
||||
|
||||
func (st *stack) require(n int) {
|
||||
func (st *stack) require(n int) error {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
if self.Recoverable {
|
||||
// Recover from any require exception
|
||||
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
self.Printf(" %v", r).Endl()
|
||||
|
||||
if err != nil {
|
||||
self.Printf(" %v", err).Endl()
|
||||
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
|
||||
context.UseGas(context.Gas)
|
||||
|
||||
ret = context.Return(nil)
|
||||
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if context.CodeAddr != 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
|
||||
statedb = self.env.State()
|
||||
|
||||
jump = func(from uint64, to *big.Int) {
|
||||
jump = func(from uint64, to *big.Int) error {
|
||||
p := to.Uint64()
|
||||
|
||||
nop := context.GetOp(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)
|
||||
pc = to.Uint64()
|
||||
|
||||
self.Endl()
|
||||
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -105,7 +103,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
|||
op = context.GetOp(pc)
|
||||
|
||||
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)
|
||||
|
||||
|
|
@ -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())
|
||||
case JUMP:
|
||||
jump(pc, stack.pop())
|
||||
if err := jump(pc, stack.pop()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue
|
||||
case JUMPI:
|
||||
pos, cond := stack.pop(), stack.pop()
|
||||
|
||||
if cond.Cmp(common.BigTrue) >= 0 {
|
||||
jump(pc, pos)
|
||||
if err := jump(pc, pos); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
|
@ -720,7 +725,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
|||
default:
|
||||
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++
|
||||
|
|
@ -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 (
|
||||
gas = 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
|
||||
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:
|
||||
n := int(op - SWAP1 + 2)
|
||||
stack.require(n)
|
||||
err := stack.require(n)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
gas.Set(GasFastestStep)
|
||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
||||
n := int(op - DUP1 + 1)
|
||||
stack.require(n)
|
||||
err := stack.require(n)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
gas.Set(GasFastestStep)
|
||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||
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]
|
||||
|
||||
|
|
@ -762,7 +777,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
|||
case EXP:
|
||||
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
|
||||
case SSTORE:
|
||||
stack.require(2)
|
||||
err := stack.require(2)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var g *big.Int
|
||||
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) {
|
||||
|
|
@ -869,7 +887,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
|
|||
|
||||
tmp := new(big.Int).Set(context.Gas)
|
||||
|
||||
panic(OOG(gas, tmp).Error())
|
||||
return nil, OOG(gas, tmp)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"encoding/hex"
|
||||
|
|
@ -139,6 +140,12 @@ func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
|
|||
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) {
|
||||
return ecdsa.GenerateKey(S256(), rand.Reader)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,16 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
|
|||
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 {
|
||||
randBytes := make([]byte, 64)
|
||||
_, err := rand.Read(randBytes)
|
||||
|
|
@ -97,11 +107,5 @@ func NewKey(rand io.Reader) *Key {
|
|||
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
|
||||
}
|
||||
|
||||
id := uuid.NewRandom()
|
||||
key := &Key{
|
||||
Id: id,
|
||||
Address: PubkeyToAddress(privateKeyECDSA.PublicKey),
|
||||
PrivateKey: privateKeyECDSA,
|
||||
}
|
||||
return key
|
||||
return NewKeyFromECDSA(privateKeyECDSA)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ type Config struct {
|
|||
Shh bool
|
||||
Dial bool
|
||||
|
||||
Etherbase string
|
||||
MinerThreads int
|
||||
AccountManager *accounts.Manager
|
||||
|
||||
|
|
@ -140,6 +141,7 @@ type Ethereum struct {
|
|||
|
||||
Mining bool
|
||||
DataDir string
|
||||
etherbase common.Address
|
||||
clientVersion string
|
||||
ethVersionId int
|
||||
netVersionId int
|
||||
|
|
@ -185,6 +187,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||
eventMux: &event.TypeMux{},
|
||||
accountManager: config.AccountManager,
|
||||
DataDir: config.DataDir,
|
||||
etherbase: common.HexToAddress(config.Etherbase),
|
||||
clientVersion: config.Name, // TODO should separate from Name
|
||||
ethVersionId: config.ProtocolVersion,
|
||||
netVersionId: config.NetworkId,
|
||||
|
|
@ -297,15 +300,31 @@ func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
|||
}
|
||||
|
||||
func (s *Ethereum) StartMining() error {
|
||||
cb, err := s.accountManager.Coinbase()
|
||||
eb, err := s.Etherbase()
|
||||
if err != nil {
|
||||
servlogger.Errorf("Cannot start mining without coinbase: %v\n", err)
|
||||
return fmt.Errorf("no coinbase: %v", err)
|
||||
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
|
||||
servlogger.Errorln(err)
|
||||
return err
|
||||
|
||||
}
|
||||
s.miner.Start(common.BytesToAddress(cb))
|
||||
|
||||
s.miner.Start(eb)
|
||||
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) IsMining() bool { return s.miner.Mining() }
|
||||
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package jsre
|
|||
|
||||
import (
|
||||
"github.com/robertkrimen/otto"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
type testNativeObjectBinding struct {
|
||||
|
|
@ -26,7 +26,7 @@ func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value
|
|||
func TestExec(t *testing.T) {
|
||||
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")
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
|
|
@ -64,7 +64,7 @@ func TestBind(t *testing.T) {
|
|||
func TestLoadScript(t *testing.T) {
|
||||
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")`)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
)
|
||||
|
||||
type CpuMiner struct {
|
||||
chMu sync.Mutex
|
||||
c chan *types.Block
|
||||
quit chan struct{}
|
||||
quitCurrentOp chan struct{}
|
||||
|
|
@ -43,16 +46,13 @@ func (self *CpuMiner) Start() {
|
|||
}
|
||||
|
||||
func (self *CpuMiner) update() {
|
||||
justStarted := true
|
||||
out:
|
||||
for {
|
||||
select {
|
||||
case block := <-self.c:
|
||||
if justStarted {
|
||||
justStarted = true
|
||||
} else {
|
||||
self.chMu.Lock()
|
||||
self.quitCurrentOp <- struct{}{}
|
||||
}
|
||||
self.chMu.Unlock()
|
||||
|
||||
go self.mine(block)
|
||||
case <-self.quit:
|
||||
|
|
@ -60,6 +60,7 @@ out:
|
|||
}
|
||||
}
|
||||
|
||||
close(self.quitCurrentOp)
|
||||
done:
|
||||
// Empty channel
|
||||
for {
|
||||
|
|
@ -75,12 +76,20 @@ done:
|
|||
|
||||
func (self *CpuMiner) mine(block *types.Block) {
|
||||
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)
|
||||
if nonce != 0 {
|
||||
block.SetNonce(nonce)
|
||||
block.Header().MixDigest = common.BytesToHash(mixDigest)
|
||||
self.returnCh <- block
|
||||
//self.returnCh <- Work{block.Number().Uint64(), nonce, mixDigest, seedHash}
|
||||
} else {
|
||||
self.returnCh <- nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ out:
|
|||
break out
|
||||
case work := <-a.workCh:
|
||||
a.work = work
|
||||
a.returnCh <- nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"math/big"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -59,12 +60,13 @@ type Agent interface {
|
|||
|
||||
type worker struct {
|
||||
mu sync.Mutex
|
||||
|
||||
agents []Agent
|
||||
recv chan *types.Block
|
||||
mux *event.TypeMux
|
||||
quit chan struct{}
|
||||
pow pow.PoW
|
||||
atWork int
|
||||
atWork int64
|
||||
|
||||
eth core.Backend
|
||||
chain *core.ChainManager
|
||||
|
|
@ -107,7 +109,7 @@ func (self *worker) start() {
|
|||
|
||||
func (self *worker) stop() {
|
||||
self.mining = false
|
||||
self.atWork = 0
|
||||
atomic.StoreInt64(&self.atWork, 0)
|
||||
|
||||
close(self.quit)
|
||||
}
|
||||
|
|
@ -135,9 +137,6 @@ out:
|
|||
self.uncleMu.Unlock()
|
||||
}
|
||||
|
||||
if self.atWork == 0 {
|
||||
self.commitNewWork()
|
||||
}
|
||||
case <-self.quit:
|
||||
// stop all agents
|
||||
for _, agent := range self.agents {
|
||||
|
|
@ -146,6 +145,11 @@ out:
|
|||
break out
|
||||
case <-timer.C:
|
||||
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() {
|
||||
for {
|
||||
for block := range self.recv {
|
||||
atomic.AddInt64(&self.atWork, -1)
|
||||
|
||||
if block == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := self.chain.InsertChain(types.Blocks{block}); err == nil {
|
||||
for _, uncle := range block.Uncles() {
|
||||
delete(self.possibleUncles, uncle.Hash())
|
||||
|
|
@ -170,7 +180,6 @@ func (self *worker) wait() {
|
|||
} else {
|
||||
self.commitNewWork()
|
||||
}
|
||||
self.atWork--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -182,8 +191,9 @@ func (self *worker) push() {
|
|||
|
||||
// push new work to agents
|
||||
for _, agent := range self.agents {
|
||||
atomic.AddInt64(&self.atWork, 1)
|
||||
|
||||
agent.Work() <- self.current.block.Copy()
|
||||
self.atWork++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
23
rpc/api.go
23
rpc/api.go
|
|
@ -3,13 +3,11 @@ package rpc
|
|||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
)
|
||||
|
||||
|
|
@ -19,15 +17,9 @@ type EthereumApi struct {
|
|||
db common.Database
|
||||
}
|
||||
|
||||
func NewEthereumApi(xeth *xeth.XEth, dataDir string) *EthereumApi {
|
||||
// What about when dataDir is empty?
|
||||
db, err := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
|
||||
api := &EthereumApi{
|
||||
eth: xeth,
|
||||
db: db,
|
||||
}
|
||||
|
||||
return api
|
||||
|
|
@ -44,10 +36,6 @@ func (api *EthereumApi) xethAtStateNum(num int64) *xeth.XEth {
|
|||
return api.xeth().AtStateNum(num)
|
||||
}
|
||||
|
||||
func (api *EthereumApi) Close() {
|
||||
api.db.Close()
|
||||
}
|
||||
|
||||
func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
|
||||
// Spec at https://github.com/ethereum/wiki/wiki/JSON-RPC
|
||||
rpclogger.Debugf("%s %s", req.Method, req.Params)
|
||||
|
|
@ -370,7 +358,8 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) 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
|
||||
case "db_getString":
|
||||
args := new(DbArgs)
|
||||
|
|
@ -382,7 +371,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
return err
|
||||
}
|
||||
|
||||
res, _ := api.db.Get([]byte(args.Database + args.Key))
|
||||
res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
|
||||
*reply = string(res)
|
||||
case "db_putHex":
|
||||
args := new(DbHexArgs)
|
||||
|
|
@ -394,7 +383,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) 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
|
||||
case "db_getHex":
|
||||
args := new(DbHexArgs)
|
||||
|
|
@ -406,7 +395,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) 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)
|
||||
case "shh_version":
|
||||
*reply = api.xeth().WhisperVersion()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"testing"
|
||||
// "time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
// "github.com/ethereum/go-ethereum/xeth"
|
||||
)
|
||||
|
||||
func TestWeb3Sha3(t *testing.T) {
|
||||
|
|
@ -26,49 +26,48 @@ func TestWeb3Sha3(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDbStr(t *testing.T) {
|
||||
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}`
|
||||
expected := "myString"
|
||||
// func TestDbStr(t *testing.T) {
|
||||
// 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}`
|
||||
// expected := "myString"
|
||||
|
||||
xeth := &xeth.XEth{}
|
||||
api := NewEthereumApi(xeth, "")
|
||||
defer api.db.Close()
|
||||
var response interface{}
|
||||
// xeth := &xeth.XEth{}
|
||||
// api := NewEthereumApi(xeth)
|
||||
// var response interface{}
|
||||
|
||||
var req RpcRequest
|
||||
json.Unmarshal([]byte(jsonput), &req)
|
||||
_ = api.GetRequestReply(&req, &response)
|
||||
// var req RpcRequest
|
||||
// json.Unmarshal([]byte(jsonput), &req)
|
||||
// _ = api.GetRequestReply(&req, &response)
|
||||
|
||||
json.Unmarshal([]byte(jsonget), &req)
|
||||
_ = api.GetRequestReply(&req, &response)
|
||||
// json.Unmarshal([]byte(jsonget), &req)
|
||||
// _ = api.GetRequestReply(&req, &response)
|
||||
|
||||
if response.(string) != expected {
|
||||
t.Errorf("Expected %s got %s", expected, response)
|
||||
}
|
||||
}
|
||||
// if response.(string) != expected {
|
||||
// t.Errorf("Expected %s got %s", expected, response)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestDbHexStr(t *testing.T) {
|
||||
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}`
|
||||
expected := "0xbeef"
|
||||
// func TestDbHexStr(t *testing.T) {
|
||||
// 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}`
|
||||
// expected := "0xbeef"
|
||||
|
||||
xeth := &xeth.XEth{}
|
||||
api := NewEthereumApi(xeth, "")
|
||||
defer api.db.Close()
|
||||
var response interface{}
|
||||
// xeth := &xeth.XEth{}
|
||||
// api := NewEthereumApi(xeth)
|
||||
// defer api.db.Close()
|
||||
// var response interface{}
|
||||
|
||||
var req RpcRequest
|
||||
json.Unmarshal([]byte(jsonput), &req)
|
||||
_ = api.GetRequestReply(&req, &response)
|
||||
// var req RpcRequest
|
||||
// json.Unmarshal([]byte(jsonput), &req)
|
||||
// _ = api.GetRequestReply(&req, &response)
|
||||
|
||||
json.Unmarshal([]byte(jsonget), &req)
|
||||
_ = api.GetRequestReply(&req, &response)
|
||||
// json.Unmarshal([]byte(jsonget), &req)
|
||||
// _ = api.GetRequestReply(&req, &response)
|
||||
|
||||
if response.(string) != expected {
|
||||
t.Errorf("Expected %s got %s", expected, response)
|
||||
}
|
||||
}
|
||||
// if response.(string) != expected {
|
||||
// t.Errorf("Expected %s got %s", expected, response)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestFilterClose(t *testing.T) {
|
||||
// t.Skip()
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ const (
|
|||
)
|
||||
|
||||
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
|
||||
func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
|
||||
api := NewEthereumApi(pipe, dataDir)
|
||||
func JSONRPC(pipe *xeth.XEth) http.Handler {
|
||||
api := NewEthereumApi(pipe)
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
// TODO this needs to be configurable
|
||||
|
|
|
|||
111
rpc/responses.go
111
rpc/responses.go
|
|
@ -6,14 +6,14 @@ import (
|
|||
"math/big"
|
||||
|
||||
"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/types"
|
||||
)
|
||||
|
||||
type BlockRes struct {
|
||||
fullTx bool
|
||||
|
||||
BlockNumber int64 `json:"number"`
|
||||
BlockNumber *big.Int `json:"number"`
|
||||
BlockHash common.Hash `json:"hash"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
Nonce [8]byte `json:"nonce"`
|
||||
|
|
@ -22,13 +22,13 @@ type BlockRes struct {
|
|||
TransactionRoot common.Hash `json:"transactionRoot"`
|
||||
StateRoot common.Hash `json:"stateRoot"`
|
||||
Miner common.Address `json:"miner"`
|
||||
Difficulty int64 `json:"difficulty"`
|
||||
TotalDifficulty int64 `json:"totalDifficulty"`
|
||||
Size int64 `json:"size"`
|
||||
Difficulty *big.Int `json:"difficulty"`
|
||||
TotalDifficulty *big.Int `json:"totalDifficulty"`
|
||||
Size *big.Int `json:"size"`
|
||||
ExtraData []byte `json:"extraData"`
|
||||
GasLimit int64 `json:"gasLimit"`
|
||||
GasLimit *big.Int `json:"gasLimit"`
|
||||
MinGasPrice int64 `json:"minGasPrice"`
|
||||
GasUsed int64 `json:"gasUsed"`
|
||||
GasUsed *big.Int `json:"gasUsed"`
|
||||
UnixTimestamp int64 `json:"timestamp"`
|
||||
Transactions []*TransactionRes `json:"transactions"`
|
||||
Uncles []common.Hash `json:"uncles"`
|
||||
|
|
@ -58,7 +58,7 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
// 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.ParentHash = b.ParentHash.Hex()
|
||||
ext.Nonce = common.ToHex(b.Nonce[:])
|
||||
|
|
@ -67,13 +67,13 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
|||
ext.TransactionRoot = b.TransactionRoot.Hex()
|
||||
ext.StateRoot = b.StateRoot.Hex()
|
||||
ext.Miner = b.Miner.Hex()
|
||||
ext.Difficulty = common.ToHex(big.NewInt(b.Difficulty).Bytes())
|
||||
ext.TotalDifficulty = common.ToHex(big.NewInt(b.TotalDifficulty).Bytes())
|
||||
ext.Size = common.ToHex(big.NewInt(b.Size).Bytes())
|
||||
ext.Difficulty = common.ToHex(b.Difficulty.Bytes())
|
||||
ext.TotalDifficulty = common.ToHex(b.TotalDifficulty.Bytes())
|
||||
ext.Size = common.ToHex(b.Size.Bytes())
|
||||
// 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.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.Transactions = make([]interface{}, len(b.Transactions))
|
||||
if b.fullTx {
|
||||
|
|
@ -99,7 +99,7 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
|||
}
|
||||
|
||||
res := new(BlockRes)
|
||||
res.BlockNumber = block.Number().Int64()
|
||||
res.BlockNumber = block.Number()
|
||||
res.BlockHash = block.Hash()
|
||||
res.ParentHash = block.ParentHash()
|
||||
res.Nonce = block.Header().Nonce
|
||||
|
|
@ -108,15 +108,13 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
|||
res.TransactionRoot = block.Header().TxHash
|
||||
res.StateRoot = block.Root()
|
||||
res.Miner = block.Header().Coinbase
|
||||
res.Difficulty = block.Difficulty().Int64()
|
||||
if block.Td != nil {
|
||||
res.TotalDifficulty = block.Td.Int64()
|
||||
}
|
||||
res.Size = int64(block.Size())
|
||||
res.Difficulty = block.Difficulty()
|
||||
res.TotalDifficulty = block.Td
|
||||
res.Size = big.NewInt(int64(block.Size()))
|
||||
// res.ExtraData =
|
||||
res.GasLimit = block.GasLimit().Int64()
|
||||
res.GasLimit = block.GasLimit()
|
||||
// res.MinGasPrice =
|
||||
res.GasUsed = block.GasUsed().Int64()
|
||||
res.GasUsed = block.GasUsed()
|
||||
res.UnixTimestamp = block.Time()
|
||||
res.Transactions = make([]*TransactionRes, len(block.Transactions()))
|
||||
for i, tx := range block.Transactions() {
|
||||
|
|
@ -135,15 +133,15 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
|||
|
||||
type TransactionRes struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
Nonce int64 `json:"nonce"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
BlockHash common.Hash `json:"blockHash,omitempty"`
|
||||
BlockNumber int64 `json:"blockNumber,omitempty"`
|
||||
TxIndex int64 `json:"transactionIndex,omitempty"`
|
||||
From common.Address `json:"from"`
|
||||
To *common.Address `json:"to"`
|
||||
Value int64 `json:"value"`
|
||||
Gas int64 `json:"gas"`
|
||||
GasPrice int64 `json:"gasPrice"`
|
||||
Value *big.Int `json:"value"`
|
||||
Gas *big.Int `json:"gas"`
|
||||
GasPrice *big.Int `json:"gasPrice"`
|
||||
Input []byte `json:"input"`
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +153,7 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
|||
BlockNumber string `json:"blockNumber,omitempty"`
|
||||
TxIndex string `json:"transactionIndex,omitempty"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
To interface{} `json:"to"`
|
||||
Value string `json:"value"`
|
||||
Gas string `json:"gas"`
|
||||
GasPrice string `json:"gasPrice"`
|
||||
|
|
@ -163,19 +161,19 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
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.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes())
|
||||
ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes())
|
||||
ext.From = t.From.Hex()
|
||||
if t.To == nil {
|
||||
ext.To = "0x00"
|
||||
ext.To = nil
|
||||
} else {
|
||||
ext.To = t.To.Hex()
|
||||
}
|
||||
ext.Value = common.ToHex(big.NewInt(t.Value).Bytes())
|
||||
ext.Gas = common.ToHex(big.NewInt(t.Gas).Bytes())
|
||||
ext.GasPrice = common.ToHex(big.NewInt(t.GasPrice).Bytes())
|
||||
ext.Value = common.ToHex(t.Value.Bytes())
|
||||
ext.Gas = common.ToHex(t.Gas.Bytes())
|
||||
ext.GasPrice = common.ToHex(t.GasPrice.Bytes())
|
||||
ext.Input = common.ToHex(t.Input)
|
||||
|
||||
return json.Marshal(ext)
|
||||
|
|
@ -184,12 +182,12 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
|||
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
|
||||
var v = new(TransactionRes)
|
||||
v.Hash = tx.Hash()
|
||||
v.Nonce = int64(tx.Nonce())
|
||||
v.Nonce = tx.Nonce()
|
||||
v.From, _ = tx.From()
|
||||
v.To = tx.To()
|
||||
v.Value = tx.Value().Int64()
|
||||
v.Gas = tx.Gas().Int64()
|
||||
v.GasPrice = tx.GasPrice().Int64()
|
||||
v.Value = tx.Value()
|
||||
v.Gas = tx.Gas()
|
||||
v.GasPrice = tx.GasPrice()
|
||||
v.Input = tx.Data()
|
||||
return v
|
||||
}
|
||||
|
|
@ -218,25 +216,48 @@ type FilterWhisperRes 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"`
|
||||
Topics []string `json:"topics"`
|
||||
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) {
|
||||
ls = make([]LogRes, len(logs))
|
||||
|
||||
for i, log := range logs {
|
||||
var l LogRes
|
||||
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
|
||||
ls[i] = NewLogRes(log)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
|||
123
rpc/responses_test.go
Normal file
123
rpc/responses_test.go
Normal 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)
|
||||
}
|
||||
14
xeth/xeth.go
14
xeth/xeth.go
|
|
@ -209,6 +209,16 @@ func (self *XEth) Accounts() []string {
|
|||
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 {
|
||||
return self.backend.PeerCount()
|
||||
}
|
||||
|
|
@ -250,8 +260,8 @@ func (self *XEth) IsListening() bool {
|
|||
}
|
||||
|
||||
func (self *XEth) Coinbase() string {
|
||||
cb, _ := self.backend.AccountManager().Coinbase()
|
||||
return common.ToHex(cb)
|
||||
eb, _ := self.backend.Etherbase()
|
||||
return eb.Hex()
|
||||
}
|
||||
|
||||
func (self *XEth) NumberToHuman(balance string) string {
|
||||
|
|
|
|||
Loading…
Reference in a new issue