Merge remote-tracking branch 'origin' into rpcargs

Conflicts:
	rpc/args.go
This commit is contained in:
Taylor Gerring 2015-03-26 22:42:46 +01:00
commit 6bd1f6cc49
25 changed files with 397 additions and 204 deletions

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"
@ -208,3 +207,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

@ -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()
@ -102,7 +102,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,
@ -146,7 +229,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 +276,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 +291,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 +300,36 @@ func execJSFiles(ctx *cli.Context) {
ethereum.WaitForShutdown() ethereum.WaitForShutdown()
} }
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
// Attempt to unlock the account
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) { func startEth(ctx *cli.Context, eth *eth.Ethereum) {
utils.StartEthereum(eth) utils.StartEthereum(eth)
am := eth.AccountManager()
// Load startup keys. XXX we are going to need a different format
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
if len(account) > 0 { if len(account) > 0 {
split := strings.Split(account, ":") if account == "coinbase" {
if len(split) != 2 { accbytes, err := am.Coinbase()
utils.Fatalf("Illegal 'unlock' format (address:password)") if err != nil {
} utils.Fatalf("no coinbase account: %v", err)
am := eth.AccountManager() }
// Attempt to unlock the account account = common.ToHex(accbytes)
err := am.Unlock(common.FromHex(split[0]), split[1])
if err != nil {
utils.Fatalf("Unlock account failed '%v'", err)
} }
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,30 +351,77 @@ 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)
} }
confirm, err := readPassword("Repeat Passphrase: ", false) if confirmation {
if err != nil { confirm, err := readPassword("Repeat Passphrase: ", false)
utils.Fatalf("%v", err) if err != nil {
} utils.Fatalf("%v", err)
if auth != confirm { }
utils.Fatalf("Passphrases did not match.") 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) 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) {

@ -1 +1 @@
Subproject commit 9f073d9091cd2d2b46dd46afea9dcf5d825ecd7c Subproject commit 17164bea8b330d6a118b40d6fbe222ffb12a0e9f

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

@ -97,14 +97,15 @@ var (
Usage: "Enable mining", Usage: "Enable mining",
} }
// key settings
UnencryptedKeysFlag = cli.BoolFlag{
Name: "unencrypted-keys",
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 coinbase' unlocks the primary (coinbase) 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
@ -243,12 +244,7 @@ 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)
} }

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

@ -4,8 +4,8 @@ import (
"math" "math"
"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 AccountChange struct { type AccountChange struct {

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,10 @@ type stack struct {
} }
func (st *stack) push(d *big.Int) { func (st *stack) push(d *big.Int) {
if len(st.data) == maxStack {
panic(fmt.Sprintf("stack limit reached (%d)", maxStack))
}
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

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
} }

File diff suppressed because one or more lines are too long

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 self.quitCurrentOp <- struct{}{}
} else { self.chMu.Unlock()
self.quitCurrentOp <- struct{}{}
}
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"
@ -58,13 +59,14 @@ 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,6 +3,8 @@ package rpc
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
// "errors"
// "fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -60,6 +62,26 @@ func numString(raw interface{}, number *int64) error {
return nil return nil
} }
// func toNumber(v interface{}) (int64, error) {
// var str string
// if v != nil {
// var ok bool
// str, ok = v.(string)
// if !ok {
// return 0, errors.New("is not a string or undefined")
// }
// } else {
// str = "latest"
// }
// switch str {
// case "latest":
// return -1, nil
// default:
// return int64(common.Big(v.(string)).Int64()), nil
// }
// }
type GetBlockByHashArgs struct { type GetBlockByHashArgs struct {
BlockHash string BlockHash string
IncludeTxs bool IncludeTxs bool
@ -442,6 +464,14 @@ func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
return NewInsufficientParamsError(len(obj), 1) return NewInsufficientParamsError(len(obj), 1)
} }
// args.Earliest, err = toNumber(obj[0].ToBlock)
// if err != nil {
// return NewDecodeParamError(fmt.Sprintf("FromBlock %v", err))
// }
// args.Latest, err = toNumber(obj[0].FromBlock)
// if err != nil {
// return NewDecodeParamError(fmt.Sprintf("ToBlock %v", err))
var num int64 var num int64
if err := blockHeight(obj[0].FromBlock, &num); err != nil { if err := blockHeight(obj[0].FromBlock, &num); err != nil {
return err return err
@ -464,6 +494,7 @@ func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
if err := numString(obj[0].Offset, &num); err != nil { if err := numString(obj[0].Offset, &num); err != nil {
return err return err
} }
args.Skip = int(num) args.Skip = int(num)

View File

@ -9,5 +9,16 @@
"full_size": 1073739904, "full_size": 1073739904,
"header_hash": "2a8de2adf89af77358250bf908bf04ba94a6e8c3ba87775564a41d269a05e4ce", "header_hash": "2a8de2adf89af77358250bf908bf04ba94a6e8c3ba87775564a41d269a05e4ce",
"cache_hash": "35ded12eecf2ce2e8da2e15c06d463aae9b84cb2530a00b932e4bbc484cde353" "cache_hash": "35ded12eecf2ce2e8da2e15c06d463aae9b84cb2530a00b932e4bbc484cde353"
},
"second": {
"nonce": "307692cf71b12f6d",
"mixhash": "e55d02c555a7969361cf74a9ec6211d8c14e4517930a00442f171bdb1698d175",
"header": "f901f7a01bef91439a3e070a6586851c11e6fd79bbbea074b2b836727b8e75c7d4a6b698a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea3cb5f94fa2ddd52ec6dd6eb75cf824f4058ca1a00c6e51346be0670ce63ac5f05324e27d20b180146269c5aab844d09a2b108c64a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd880845511ed2a80a0e55d02c555a7969361cf74a9ec6211d8c14e4517930a00442f171bdb1698d17588307692cf71b12f6d",
"seed": "0000000000000000000000000000000000000000000000000000000000000000",
"result": "ab9b13423cface72cbec8424221651bc2e384ef0f7a560e038fc68c8d8684829",
"cache_size": 16776896,
"full_size": 1073739904,
"header_hash": "100cbec5e5ef82991290d0d93d758f19082e71f234cf479192a8b94df6da6bfe",
"cache_hash": "35ded12eecf2ce2e8da2e15c06d463aae9b84cb2530a00b932e4bbc484cde353"
} }
} }