mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 12:46:44 +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`
|
`go get github.com/ethereum/go-ethereum/cmd/mist`
|
||||||
|
|
||||||
Ethereum (CLI):
|
Geth (CLI):
|
||||||
|
|
||||||
`go get github.com/ethereum/go-ethereum/cmd/ethereum`
|
`go get github.com/ethereum/go-ethereum/cmd/ethereum`
|
||||||
|
|
||||||
|
|
@ -32,10 +32,10 @@ Mist (GUI):
|
||||||
godep go build -v ./cmd/mist
|
godep go build -v ./cmd/mist
|
||||||
```
|
```
|
||||||
|
|
||||||
Ethereum (CLI):
|
Geth (CLI):
|
||||||
|
|
||||||
```
|
```
|
||||||
godep go build -v ./cmd/ethereum
|
godep go build -v ./cmd/geth
|
||||||
```
|
```
|
||||||
|
|
||||||
Instead of `build`, you can use `install` which will also install the resulting binary.
|
Instead of `build`, you can use `install` which will also install the resulting binary.
|
||||||
|
|
@ -61,7 +61,7 @@ Go Ethereum comes with several wrappers/executables found in
|
||||||
[the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd):
|
[the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd):
|
||||||
|
|
||||||
* `mist` Official Ethereum Browser (ethereum GUI client)
|
* `mist` Official Ethereum Browser (ethereum GUI client)
|
||||||
* `ethereum` Ethereum CLI (ethereum command line interface client)
|
* `geth` Ethereum CLI (ethereum command line interface client)
|
||||||
* `bootnode` runs a bootstrap node for the Discovery Protocol
|
* `bootnode` runs a bootstrap node for the Discovery Protocol
|
||||||
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite:
|
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite:
|
||||||
`cat file | ethtest`.
|
`cat file | ethtest`.
|
||||||
|
|
@ -73,12 +73,12 @@ Go Ethereum comes with several wrappers/executables found in
|
||||||
Command line options
|
Command line options
|
||||||
============================
|
============================
|
||||||
|
|
||||||
Both `mist` and `ethereum` can be configured via command line options, environment variables and config files.
|
Both `mist` and `geth` can be configured via command line options, environment variables and config files.
|
||||||
|
|
||||||
To get the options available:
|
To get the options available:
|
||||||
|
|
||||||
```
|
```
|
||||||
ethereum -help
|
geth -help
|
||||||
```
|
```
|
||||||
|
|
||||||
For further details on options, see the [wiki](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)
|
For further details on options, see the [wiki](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"os"
|
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -82,13 +81,7 @@ func (am *Manager) HasAccount(addr []byte) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coinbase returns the account address that mining rewards are sent to.
|
func (am *Manager) Primary() (addr []byte, err error) {
|
||||||
func (am *Manager) Coinbase() (addr []byte, err error) {
|
|
||||||
// TODO: persist coinbase address on disk
|
|
||||||
return am.firstAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (am *Manager) firstAddr() ([]byte, error) {
|
|
||||||
addrs, err := am.keyStore.GetKeyAddresses()
|
addrs, err := am.keyStore.GetKeyAddresses()
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil, ErrNoKeys
|
return nil, ErrNoKeys
|
||||||
|
|
@ -208,3 +201,37 @@ func zeroKey(k *ecdsa.PrivateKey) {
|
||||||
b[i] = 0
|
b[i] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// USE WITH CAUTION = this will save an unencrypted private key on disk
|
||||||
|
// no cli or js interface
|
||||||
|
func (am *Manager) Export(path string, addr []byte, keyAuth string) error {
|
||||||
|
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return crypto.SaveECDSA(path, key.PrivateKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) Import(path string, keyAuth string) (Account, error) {
|
||||||
|
privateKeyECDSA, err := crypto.LoadECDSA(path)
|
||||||
|
if err != nil {
|
||||||
|
return Account{}, err
|
||||||
|
}
|
||||||
|
key := crypto.NewKeyFromECDSA(privateKeyECDSA)
|
||||||
|
if err = am.keyStore.StoreKey(key, keyAuth); err != nil {
|
||||||
|
return Account{}, err
|
||||||
|
}
|
||||||
|
return Account{Address: key.Address}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) ImportPreSaleKey(keyJSON []byte, password string) (acc Account, err error) {
|
||||||
|
var key *crypto.Key
|
||||||
|
key, err = crypto.ImportPreSaleKey(am.keyStore, keyJSON, password)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = am.keyStore.StoreKey(key, password); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return Account{Address: key.Address}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
@ -69,14 +69,13 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return otto.FalseValue()
|
return otto.FalseValue()
|
||||||
}
|
}
|
||||||
dataDir := js.ethereum.DataDir
|
|
||||||
|
|
||||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Can't listen on %s:%d: %v", addr, port, err)
|
fmt.Printf("Can't listen on %s:%d: %v", addr, port, err)
|
||||||
return otto.FalseValue()
|
return otto.FalseValue()
|
||||||
}
|
}
|
||||||
go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil), dataDir))
|
go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil)))
|
||||||
return otto.TrueValue()
|
return otto.TrueValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,14 +67,14 @@ type jsre struct {
|
||||||
prompter
|
prompter
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
|
func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool) *jsre {
|
||||||
js := &jsre{ethereum: ethereum, ps1: "> "}
|
js := &jsre{ethereum: ethereum, ps1: "> "}
|
||||||
js.xeth = xeth.New(ethereum, js)
|
js.xeth = xeth.New(ethereum, js)
|
||||||
js.re = re.New(libPath)
|
js.re = re.New(libPath)
|
||||||
js.apiBindings()
|
js.apiBindings()
|
||||||
js.adminBindings()
|
js.adminBindings()
|
||||||
|
|
||||||
if !liner.TerminalSupported() {
|
if !liner.TerminalSupported() || !interactive {
|
||||||
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
||||||
} else {
|
} else {
|
||||||
lr := liner.NewLiner()
|
lr := liner.NewLiner()
|
||||||
|
|
@ -91,8 +91,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
|
||||||
|
|
||||||
func (js *jsre) apiBindings() {
|
func (js *jsre) apiBindings() {
|
||||||
|
|
||||||
ethApi := rpc.NewEthereumApi(js.xeth, js.ethereum.DataDir)
|
ethApi := rpc.NewEthereumApi(js.xeth)
|
||||||
ethApi.Close()
|
|
||||||
//js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal))
|
//js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal))
|
||||||
|
|
||||||
jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re)
|
jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re)
|
||||||
|
|
@ -102,7 +101,7 @@ func (js *jsre) apiBindings() {
|
||||||
jethObj := t.Object()
|
jethObj := t.Object()
|
||||||
jethObj.Set("send", jeth.Send)
|
jethObj.Set("send", jeth.Send)
|
||||||
|
|
||||||
err := js.re.Compile("bignum.js", re.BigNumber_JS)
|
err := js.re.Compile("bignumber.js", re.BigNumber_JS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Error loading bignumber.js: %v", err)
|
utils.Fatalf("Error loading bignumber.js: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -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(ð.Config{
|
ethereum, err = eth.New(ð.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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,14 +23,15 @@ package main
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
|
@ -41,8 +42,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "Ethereum(G)"
|
ClientIdentifier = "Geth"
|
||||||
Version = "0.9.3"
|
Version = "0.9.4"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -74,10 +75,44 @@ Regular users do not need to execute it.
|
||||||
The output of this command is supposed to be machine-readable.
|
The output of this command is supposed to be machine-readable.
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "wallet",
|
||||||
|
Usage: "ethereum presale wallet",
|
||||||
|
Subcommands: []cli.Command{
|
||||||
|
{
|
||||||
|
Action: importWallet,
|
||||||
|
Name: "import",
|
||||||
|
Usage: "import ethereum presale wallet",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Action: accountList,
|
Action: accountList,
|
||||||
Name: "account",
|
Name: "account",
|
||||||
Usage: "manage accounts",
|
Usage: "manage accounts",
|
||||||
|
Description: `
|
||||||
|
|
||||||
|
Manage accounts lets you create new accounts, list all existing accounts,
|
||||||
|
import a private key into a new account.
|
||||||
|
|
||||||
|
It supports interactive mode, when you are prompted for password as well as
|
||||||
|
non-interactive mode where passwords are supplied via a given password file.
|
||||||
|
Non-interactive mode is only meant for scripted use on test networks or known
|
||||||
|
safe environments.
|
||||||
|
|
||||||
|
Make sure you remember the password you gave when creating a new account (with
|
||||||
|
either new or import). Without it you are not able to unlock your account.
|
||||||
|
|
||||||
|
Note that exporting your key in unencrypted format is NOT supported.
|
||||||
|
|
||||||
|
Keys are stored under <DATADIR>/keys.
|
||||||
|
It is safe to transfer the entire directory or the individual keys therein
|
||||||
|
between ethereum nodes.
|
||||||
|
Make sure you backup your keys regularly.
|
||||||
|
|
||||||
|
And finally. DO NOT FORGET YOUR PASSWORD.
|
||||||
|
`,
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
{
|
{
|
||||||
Action: accountList,
|
Action: accountList,
|
||||||
|
|
@ -88,6 +123,51 @@ The output of this command is supposed to be machine-readable.
|
||||||
Action: accountCreate,
|
Action: accountCreate,
|
||||||
Name: "new",
|
Name: "new",
|
||||||
Usage: "create a new account",
|
Usage: "create a new account",
|
||||||
|
Description: `
|
||||||
|
|
||||||
|
ethereum account new
|
||||||
|
|
||||||
|
Creates a new account. Prints the address.
|
||||||
|
|
||||||
|
The account is saved in encrypted format, you are prompted for a passphrase.
|
||||||
|
|
||||||
|
You must remember this passphrase to unlock your account in the future.
|
||||||
|
|
||||||
|
For non-interactive use the passphrase can be specified with the --password flag:
|
||||||
|
|
||||||
|
ethereum --password <passwordfile> account new
|
||||||
|
|
||||||
|
Note, this is meant to be used for testing only, it is a bad idea to save your
|
||||||
|
password to file or expose in any other way.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: accountImport,
|
||||||
|
Name: "import",
|
||||||
|
Usage: "import a private key into a new account",
|
||||||
|
Description: `
|
||||||
|
|
||||||
|
ethereum account import <keyfile>
|
||||||
|
|
||||||
|
Imports an unencrypted private key from <keyfile> and creates a new account.
|
||||||
|
Prints the address.
|
||||||
|
|
||||||
|
The keyfile is assumed to contain an unencrypted private key in canonical EC
|
||||||
|
raw bytes format.
|
||||||
|
|
||||||
|
The account is saved in encrypted format, you are prompted for a passphrase.
|
||||||
|
|
||||||
|
You must remember this passphrase to unlock your account in the future.
|
||||||
|
|
||||||
|
For non-interactive use the passphrase can be specified with the -password flag:
|
||||||
|
|
||||||
|
ethereum --password <passwordfile> account import <keyfile>
|
||||||
|
|
||||||
|
Note:
|
||||||
|
As you can directly copy your encrypted accounts to another ethereum instance,
|
||||||
|
this import mechanism is not needed when you transfer an account between
|
||||||
|
nodes.
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -103,18 +183,20 @@ Use "ethereum dump 0" to dump the genesis block.
|
||||||
{
|
{
|
||||||
Action: console,
|
Action: console,
|
||||||
Name: "console",
|
Name: "console",
|
||||||
Usage: `Ethereum Console: interactive JavaScript environment`,
|
Usage: `Geth Console: interactive JavaScript environment`,
|
||||||
Description: `
|
Description: `
|
||||||
Console is an interactive shell for the Ethereum JavaScript runtime environment which exposes a node admin interface as well as the DAPP JavaScript API.
|
The Geth console is an interactive shell for the JavaScript runtime environment
|
||||||
|
which exposes a node admin interface as well as the DAPP JavaScript API.
|
||||||
See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
|
See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Action: execJSFiles,
|
Action: execJSFiles,
|
||||||
Name: "js",
|
Name: "js",
|
||||||
Usage: `executes the given JavaScript files in the Ethereum Frontier JavaScript VM`,
|
Usage: `executes the given JavaScript files in the Geth JavaScript VM`,
|
||||||
Description: `
|
Description: `
|
||||||
The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console
|
The JavaScript VM exposes a node admin interface as well as the DAPP
|
||||||
|
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -130,6 +212,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
|
||||||
}
|
}
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
utils.UnlockedAccountFlag,
|
utils.UnlockedAccountFlag,
|
||||||
|
utils.PasswordFileFlag,
|
||||||
utils.BootnodesFlag,
|
utils.BootnodesFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.JSpathFlag,
|
utils.JSpathFlag,
|
||||||
|
|
@ -138,6 +221,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
|
||||||
utils.LogJSONFlag,
|
utils.LogJSONFlag,
|
||||||
utils.LogLevelFlag,
|
utils.LogLevelFlag,
|
||||||
utils.MaxPeersFlag,
|
utils.MaxPeersFlag,
|
||||||
|
utils.EtherbaseFlag,
|
||||||
utils.MinerThreadsFlag,
|
utils.MinerThreadsFlag,
|
||||||
utils.MiningEnabledFlag,
|
utils.MiningEnabledFlag,
|
||||||
utils.NATFlag,
|
utils.NATFlag,
|
||||||
|
|
@ -146,7 +230,6 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
|
||||||
utils.RPCEnabledFlag,
|
utils.RPCEnabledFlag,
|
||||||
utils.RPCListenAddrFlag,
|
utils.RPCListenAddrFlag,
|
||||||
utils.RPCPortFlag,
|
utils.RPCPortFlag,
|
||||||
utils.UnencryptedKeysFlag,
|
|
||||||
utils.VMDebugFlag,
|
utils.VMDebugFlag,
|
||||||
utils.ProtocolVersionFlag,
|
utils.ProtocolVersionFlag,
|
||||||
utils.NetworkIdFlag,
|
utils.NetworkIdFlag,
|
||||||
|
|
@ -194,7 +277,7 @@ func console(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
startEth(ctx, ethereum)
|
startEth(ctx, ethereum)
|
||||||
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name))
|
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true)
|
||||||
repl.interactive()
|
repl.interactive()
|
||||||
|
|
||||||
ethereum.Stop()
|
ethereum.Stop()
|
||||||
|
|
@ -209,7 +292,7 @@ func execJSFiles(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
startEth(ctx, ethereum)
|
startEth(ctx, ethereum)
|
||||||
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name))
|
repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false)
|
||||||
for _, file := range ctx.Args() {
|
for _, file := range ctx.Args() {
|
||||||
repl.exec(file)
|
repl.exec(file)
|
||||||
}
|
}
|
||||||
|
|
@ -218,22 +301,36 @@ func execJSFiles(ctx *cli.Context) {
|
||||||
ethereum.WaitForShutdown()
|
ethereum.WaitForShutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
|
||||||
utils.StartEthereum(eth)
|
var err error
|
||||||
|
|
||||||
// Load startup keys. XXX we are going to need a different format
|
// Load startup keys. XXX we are going to need a different format
|
||||||
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
|
||||||
if len(account) > 0 {
|
|
||||||
split := strings.Split(account, ":")
|
|
||||||
if len(split) != 2 {
|
|
||||||
utils.Fatalf("Illegal 'unlock' format (address:password)")
|
|
||||||
}
|
|
||||||
am := eth.AccountManager()
|
|
||||||
// Attempt to unlock the account
|
// Attempt to unlock the account
|
||||||
err := am.Unlock(common.FromHex(split[0]), split[1])
|
passphrase = getPassPhrase(ctx, "", false)
|
||||||
|
accbytes := common.FromHex(account)
|
||||||
|
if len(accbytes) == 0 {
|
||||||
|
utils.Fatalf("Invalid account address '%s'", account)
|
||||||
|
}
|
||||||
|
err = am.Unlock(accbytes, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Unlock account failed '%v'", err)
|
utils.Fatalf("Unlock account failed '%v'", err)
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
||||||
|
utils.StartEthereum(eth)
|
||||||
|
am := eth.AccountManager()
|
||||||
|
|
||||||
|
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
||||||
|
if len(account) > 0 {
|
||||||
|
if account == "primary" {
|
||||||
|
accbytes, err := am.Primary()
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("no primary account: %v", err)
|
||||||
|
}
|
||||||
|
account = common.ToHex(accbytes)
|
||||||
|
}
|
||||||
|
unlockAccount(ctx, am, account)
|
||||||
}
|
}
|
||||||
// Start auxiliary services if enabled.
|
// Start auxiliary services if enabled.
|
||||||
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
||||||
|
|
@ -255,16 +352,15 @@ func accountList(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func accountCreate(ctx *cli.Context) {
|
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) {
|
||||||
am := utils.GetAccountManager(ctx)
|
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
|
||||||
passphrase := ""
|
if len(passfile) == 0 {
|
||||||
if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) {
|
fmt.Println(desc)
|
||||||
fmt.Println("The new account will be encrypted with a passphrase.")
|
|
||||||
fmt.Println("Please enter a passphrase now.")
|
|
||||||
auth, err := readPassword("Passphrase: ", true)
|
auth, err := readPassword("Passphrase: ", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("%v", err)
|
utils.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
if confirmation {
|
||||||
confirm, err := readPassword("Repeat Passphrase: ", false)
|
confirm, err := readPassword("Repeat Passphrase: ", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("%v", err)
|
utils.Fatalf("%v", err)
|
||||||
|
|
@ -272,13 +368,61 @@ func accountCreate(ctx *cli.Context) {
|
||||||
if auth != confirm {
|
if auth != confirm {
|
||||||
utils.Fatalf("Passphrases did not match.")
|
utils.Fatalf("Passphrases did not match.")
|
||||||
}
|
}
|
||||||
passphrase = auth
|
|
||||||
}
|
}
|
||||||
|
passphrase = auth
|
||||||
|
|
||||||
|
} else {
|
||||||
|
passbytes, err := ioutil.ReadFile(passfile)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
|
||||||
|
}
|
||||||
|
passphrase = string(passbytes)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func accountCreate(ctx *cli.Context) {
|
||||||
|
am := utils.GetAccountManager(ctx)
|
||||||
|
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
|
||||||
acct, err := am.NewAccount(passphrase)
|
acct, err := am.NewAccount(passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not create the account: %v", err)
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Address: %x\n", acct.Address)
|
fmt.Printf("Address: %x\n", acct)
|
||||||
|
}
|
||||||
|
|
||||||
|
func importWallet(ctx *cli.Context) {
|
||||||
|
keyfile := ctx.Args().First()
|
||||||
|
if len(keyfile) == 0 {
|
||||||
|
utils.Fatalf("keyfile must be given as argument")
|
||||||
|
}
|
||||||
|
keyJson, err := ioutil.ReadFile(keyfile)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not read wallet file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
am := utils.GetAccountManager(ctx)
|
||||||
|
passphrase := getPassPhrase(ctx, "", false)
|
||||||
|
|
||||||
|
acct, err := am.ImportPreSaleKey(keyJson, passphrase)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Address: %x\n", acct)
|
||||||
|
}
|
||||||
|
|
||||||
|
func accountImport(ctx *cli.Context) {
|
||||||
|
keyfile := ctx.Args().First()
|
||||||
|
if len(keyfile) == 0 {
|
||||||
|
utils.Fatalf("keyfile must be given as argument")
|
||||||
|
}
|
||||||
|
am := utils.GetAccountManager(ctx)
|
||||||
|
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
|
||||||
|
acct, err := am.Import(keyfile, passphrase)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Address: %x\n", acct)
|
||||||
}
|
}
|
||||||
|
|
||||||
func importchain(ctx *cli.Context) {
|
func importchain(ctx *cli.Context) {
|
||||||
|
|
@ -325,7 +469,6 @@ func dump(ctx *cli.Context) {
|
||||||
} else {
|
} else {
|
||||||
statedb := state.New(block.Root(), stateDb)
|
statedb := state.New(block.Root(), stateDb)
|
||||||
fmt.Printf("%s\n", statedb.Dump())
|
fmt.Printf("%s\n", statedb.Dump())
|
||||||
// fmt.Println(block)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,15 +96,21 @@ var (
|
||||||
Name: "mine",
|
Name: "mine",
|
||||||
Usage: "Enable mining",
|
Usage: "Enable mining",
|
||||||
}
|
}
|
||||||
|
EtherbaseFlag = cli.StringFlag{
|
||||||
// key settings
|
Name: "etherbase",
|
||||||
UnencryptedKeysFlag = cli.BoolFlag{
|
Usage: "public address for block mining rewards. By default the address of your primary account is used",
|
||||||
Name: "unencrypted-keys",
|
Value: "primary",
|
||||||
Usage: "disable private key disk encryption (for testing)",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnlockedAccountFlag = cli.StringFlag{
|
UnlockedAccountFlag = cli.StringFlag{
|
||||||
Name: "unlock",
|
Name: "unlock",
|
||||||
Usage: "Unlock a given account untill this programs exits (address:password)",
|
Usage: "unlock the account given until this program exits (prompts for password). '--unlock primary' unlocks the primary account",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
|
PasswordFileFlag = cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "Path to password file for (un)locking an existing account.",
|
||||||
|
Value: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
// logging and debug settings
|
// logging and debug settings
|
||||||
|
|
@ -214,6 +220,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
||||||
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
||||||
LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
|
LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
|
||||||
LogJSON: ctx.GlobalString(LogJSONFlag.Name),
|
LogJSON: ctx.GlobalString(LogJSONFlag.Name),
|
||||||
|
Etherbase: ctx.GlobalString(EtherbaseFlag.Name),
|
||||||
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
||||||
AccountManager: GetAccountManager(ctx),
|
AccountManager: GetAccountManager(ctx),
|
||||||
VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
|
VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
|
||||||
|
|
@ -243,23 +250,17 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Dat
|
||||||
|
|
||||||
func GetAccountManager(ctx *cli.Context) *accounts.Manager {
|
func GetAccountManager(ctx *cli.Context) *accounts.Manager {
|
||||||
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
||||||
var ks crypto.KeyStore2
|
ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
|
||||||
if ctx.GlobalBool(UnencryptedKeysFlag.Name) {
|
|
||||||
ks = crypto.NewKeyStorePlain(path.Join(dataDir, "plainkeys"))
|
|
||||||
} else {
|
|
||||||
ks = crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
|
|
||||||
}
|
|
||||||
return accounts.NewManager(ks)
|
return accounts.NewManager(ks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
|
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
|
||||||
addr := ctx.GlobalString(RPCListenAddrFlag.Name)
|
addr := ctx.GlobalString(RPCListenAddrFlag.Name)
|
||||||
port := ctx.GlobalInt(RPCPortFlag.Name)
|
port := ctx.GlobalInt(RPCPortFlag.Name)
|
||||||
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
|
||||||
fmt.Println("Starting RPC on port: ", port)
|
fmt.Println("Starting RPC on port: ", port)
|
||||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't listen on %s:%d: %v", addr, port, err)
|
Fatalf("Can't listen on %s:%d: %v", addr, port, err)
|
||||||
}
|
}
|
||||||
go http.Serve(l, rpc.JSONRPC(xeth.New(eth, nil), dataDir))
|
go http.Serve(l, rpc.JSONRPC(xeth.New(eth, nil)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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{})
|
||||||
|
|
|
||||||
164
core/vm/gas.go
164
core/vm/gas.go
|
|
@ -1,11 +1,9 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import "math/big"
|
import (
|
||||||
|
"fmt"
|
||||||
type req struct {
|
"math/big"
|
||||||
stack int
|
)
|
||||||
gas *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GasQuickStep = big.NewInt(2)
|
GasQuickStep = big.NewInt(2)
|
||||||
|
|
@ -56,75 +54,30 @@ var (
|
||||||
GasCopyWord = big.NewInt(3)
|
GasCopyWord = big.NewInt(3)
|
||||||
)
|
)
|
||||||
|
|
||||||
var _baseCheck = map[OpCode]req{
|
func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
|
||||||
// Req stack Gas price
|
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
||||||
ADD: {2, GasFastestStep},
|
// PUSH is also allowed to calculate the same price for all PUSHes
|
||||||
LT: {2, GasFastestStep},
|
// DUP requirements are handled elsewhere (except for the stack limit check)
|
||||||
GT: {2, GasFastestStep},
|
if op >= PUSH1 && op <= PUSH32 {
|
||||||
SLT: {2, GasFastestStep},
|
op = PUSH1
|
||||||
SGT: {2, GasFastestStep},
|
}
|
||||||
EQ: {2, GasFastestStep},
|
if op >= DUP1 && op <= DUP16 {
|
||||||
ISZERO: {1, GasFastestStep},
|
op = DUP1
|
||||||
SUB: {2, GasFastestStep},
|
}
|
||||||
AND: {2, GasFastestStep},
|
|
||||||
OR: {2, GasFastestStep},
|
|
||||||
XOR: {2, GasFastestStep},
|
|
||||||
NOT: {1, GasFastestStep},
|
|
||||||
BYTE: {2, GasFastestStep},
|
|
||||||
CALLDATALOAD: {1, GasFastestStep},
|
|
||||||
CALLDATACOPY: {3, GasFastestStep},
|
|
||||||
MLOAD: {1, GasFastestStep},
|
|
||||||
MSTORE: {2, GasFastestStep},
|
|
||||||
MSTORE8: {2, GasFastestStep},
|
|
||||||
CODECOPY: {3, GasFastestStep},
|
|
||||||
MUL: {2, GasFastStep},
|
|
||||||
DIV: {2, GasFastStep},
|
|
||||||
SDIV: {2, GasFastStep},
|
|
||||||
MOD: {2, GasFastStep},
|
|
||||||
SMOD: {2, GasFastStep},
|
|
||||||
SIGNEXTEND: {2, GasFastStep},
|
|
||||||
ADDMOD: {3, GasMidStep},
|
|
||||||
MULMOD: {3, GasMidStep},
|
|
||||||
JUMP: {1, GasMidStep},
|
|
||||||
JUMPI: {2, GasSlowStep},
|
|
||||||
EXP: {2, GasSlowStep},
|
|
||||||
ADDRESS: {0, GasQuickStep},
|
|
||||||
ORIGIN: {0, GasQuickStep},
|
|
||||||
CALLER: {0, GasQuickStep},
|
|
||||||
CALLVALUE: {0, GasQuickStep},
|
|
||||||
CODESIZE: {0, GasQuickStep},
|
|
||||||
GASPRICE: {0, GasQuickStep},
|
|
||||||
COINBASE: {0, GasQuickStep},
|
|
||||||
TIMESTAMP: {0, GasQuickStep},
|
|
||||||
NUMBER: {0, GasQuickStep},
|
|
||||||
CALLDATASIZE: {0, GasQuickStep},
|
|
||||||
DIFFICULTY: {0, GasQuickStep},
|
|
||||||
GASLIMIT: {0, GasQuickStep},
|
|
||||||
POP: {0, GasQuickStep},
|
|
||||||
PC: {0, GasQuickStep},
|
|
||||||
MSIZE: {0, GasQuickStep},
|
|
||||||
GAS: {0, GasQuickStep},
|
|
||||||
BLOCKHASH: {1, GasExtStep},
|
|
||||||
BALANCE: {0, GasExtStep},
|
|
||||||
EXTCODESIZE: {1, GasExtStep},
|
|
||||||
EXTCODECOPY: {4, GasExtStep},
|
|
||||||
SLOAD: {1, GasStorageGet},
|
|
||||||
SSTORE: {2, Zero},
|
|
||||||
SHA3: {1, GasSha3Base},
|
|
||||||
CREATE: {3, GasCreate},
|
|
||||||
CALL: {7, GasCall},
|
|
||||||
CALLCODE: {7, GasCall},
|
|
||||||
JUMPDEST: {0, GasJumpDest},
|
|
||||||
SUICIDE: {1, Zero},
|
|
||||||
RETURN: {2, Zero},
|
|
||||||
}
|
|
||||||
|
|
||||||
func baseCheck(op OpCode, stack *stack, gas *big.Int) {
|
|
||||||
if r, ok := _baseCheck[op]; ok {
|
if r, ok := _baseCheck[op]; ok {
|
||||||
stack.require(r.stack)
|
err := stack.require(r.stackPop)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.stackPush && len(stack.data)-r.stackPop+1 > 1024 {
|
||||||
|
return fmt.Errorf("stack limit reached (%d)", maxStack)
|
||||||
|
}
|
||||||
|
|
||||||
gas.Add(gas, r.gas)
|
gas.Add(gas, r.gas)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toWordSize(size *big.Int) *big.Int {
|
func toWordSize(size *big.Int) *big.Int {
|
||||||
|
|
@ -133,3 +86,74 @@ func toWordSize(size *big.Int) *big.Int {
|
||||||
tmp.Div(tmp, u256(32))
|
tmp.Div(tmp, u256(32))
|
||||||
return tmp
|
return tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type req struct {
|
||||||
|
stackPop int
|
||||||
|
gas *big.Int
|
||||||
|
stackPush bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var _baseCheck = map[OpCode]req{
|
||||||
|
// opcode | stack pop | gas price | stack push
|
||||||
|
ADD: {2, GasFastestStep, true},
|
||||||
|
LT: {2, GasFastestStep, true},
|
||||||
|
GT: {2, GasFastestStep, true},
|
||||||
|
SLT: {2, GasFastestStep, true},
|
||||||
|
SGT: {2, GasFastestStep, true},
|
||||||
|
EQ: {2, GasFastestStep, true},
|
||||||
|
ISZERO: {1, GasFastestStep, true},
|
||||||
|
SUB: {2, GasFastestStep, true},
|
||||||
|
AND: {2, GasFastestStep, true},
|
||||||
|
OR: {2, GasFastestStep, true},
|
||||||
|
XOR: {2, GasFastestStep, true},
|
||||||
|
NOT: {1, GasFastestStep, true},
|
||||||
|
BYTE: {2, GasFastestStep, true},
|
||||||
|
CALLDATALOAD: {1, GasFastestStep, true},
|
||||||
|
CALLDATACOPY: {3, GasFastestStep, true},
|
||||||
|
MLOAD: {1, GasFastestStep, true},
|
||||||
|
MSTORE: {2, GasFastestStep, false},
|
||||||
|
MSTORE8: {2, GasFastestStep, false},
|
||||||
|
CODECOPY: {3, GasFastestStep, false},
|
||||||
|
MUL: {2, GasFastStep, true},
|
||||||
|
DIV: {2, GasFastStep, true},
|
||||||
|
SDIV: {2, GasFastStep, true},
|
||||||
|
MOD: {2, GasFastStep, true},
|
||||||
|
SMOD: {2, GasFastStep, true},
|
||||||
|
SIGNEXTEND: {2, GasFastStep, true},
|
||||||
|
ADDMOD: {3, GasMidStep, true},
|
||||||
|
MULMOD: {3, GasMidStep, true},
|
||||||
|
JUMP: {1, GasMidStep, false},
|
||||||
|
JUMPI: {2, GasSlowStep, false},
|
||||||
|
EXP: {2, GasSlowStep, true},
|
||||||
|
ADDRESS: {0, GasQuickStep, true},
|
||||||
|
ORIGIN: {0, GasQuickStep, true},
|
||||||
|
CALLER: {0, GasQuickStep, true},
|
||||||
|
CALLVALUE: {0, GasQuickStep, true},
|
||||||
|
CODESIZE: {0, GasQuickStep, true},
|
||||||
|
GASPRICE: {0, GasQuickStep, true},
|
||||||
|
COINBASE: {0, GasQuickStep, true},
|
||||||
|
TIMESTAMP: {0, GasQuickStep, true},
|
||||||
|
NUMBER: {0, GasQuickStep, true},
|
||||||
|
CALLDATASIZE: {0, GasQuickStep, true},
|
||||||
|
DIFFICULTY: {0, GasQuickStep, true},
|
||||||
|
GASLIMIT: {0, GasQuickStep, true},
|
||||||
|
POP: {1, GasQuickStep, false},
|
||||||
|
PC: {0, GasQuickStep, true},
|
||||||
|
MSIZE: {0, GasQuickStep, true},
|
||||||
|
GAS: {0, GasQuickStep, true},
|
||||||
|
BLOCKHASH: {1, GasExtStep, true},
|
||||||
|
BALANCE: {0, GasExtStep, true},
|
||||||
|
EXTCODESIZE: {1, GasExtStep, true},
|
||||||
|
EXTCODECOPY: {4, GasExtStep, false},
|
||||||
|
SLOAD: {1, GasStorageGet, true},
|
||||||
|
SSTORE: {2, Zero, false},
|
||||||
|
SHA3: {1, GasSha3Base, true},
|
||||||
|
CREATE: {3, GasCreate, true},
|
||||||
|
CALL: {7, GasCall, true},
|
||||||
|
CALLCODE: {7, GasCall, true},
|
||||||
|
JUMPDEST: {0, GasJumpDest, false},
|
||||||
|
SUICIDE: {1, Zero, false},
|
||||||
|
RETURN: {2, Zero, false},
|
||||||
|
PUSH1: {0, GasFastestStep, true},
|
||||||
|
DUP1: {0, Zero, true},
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,21 +15,17 @@ func NewMemory() *Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Memory) Set(offset, size uint64, value []byte) {
|
func (m *Memory) Set(offset, size uint64, value []byte) {
|
||||||
value = common.RightPadBytes(value, int(size))
|
// length of store may never be less than offset + size.
|
||||||
|
// The store should be resized PRIOR to setting the memory
|
||||||
|
if size > uint64(len(m.store)) {
|
||||||
|
panic("INVALID memory: store empty")
|
||||||
|
}
|
||||||
|
|
||||||
totSize := offset + size
|
// It's possible the offset is greater than 0 and size equals 0. This is because
|
||||||
lenSize := uint64(len(m.store) - 1)
|
// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
|
||||||
if totSize > lenSize {
|
if size > 0 {
|
||||||
// Calculate the diff between the sizes
|
copy(m.store[offset:offset+size], common.RightPadBytes(value, int(size)))
|
||||||
diff := totSize - lenSize
|
|
||||||
if diff > 0 {
|
|
||||||
// Create a new empty slice and append it
|
|
||||||
newSlice := make([]byte, diff-1)
|
|
||||||
// Resize slice
|
|
||||||
m.store = append(m.store, newSlice...)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
copy(m.store[offset:offset+size], value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Memory) Resize(size uint64) {
|
func (m *Memory) Resize(size uint64) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxStack = 1024
|
||||||
|
|
||||||
func newStack() *stack {
|
func newStack() *stack {
|
||||||
return &stack{}
|
return &stack{}
|
||||||
}
|
}
|
||||||
|
|
@ -15,6 +17,7 @@ type stack struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) push(d *big.Int) {
|
func (st *stack) push(d *big.Int) {
|
||||||
|
// NOTE push limit (1024) is checked in baseCheck
|
||||||
stackItem := new(big.Int).Set(d)
|
stackItem := new(big.Int).Set(d)
|
||||||
if len(st.data) > st.ptr {
|
if len(st.data) > st.ptr {
|
||||||
st.data[st.ptr] = stackItem
|
st.data[st.ptr] = stackItem
|
||||||
|
|
@ -46,10 +49,11 @@ func (st *stack) peek() *big.Int {
|
||||||
return st.data[st.len()-1]
|
return st.data[st.len()-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) require(n int) {
|
func (st *stack) require(n int) error {
|
||||||
if st.len() < n {
|
if st.len() < n {
|
||||||
panic(fmt.Sprintf("stack underflow (%d <=> %d)", len(st.data), n))
|
return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) Print() {
|
func (st *stack) Print() {
|
||||||
|
|
|
||||||
|
|
@ -45,20 +45,16 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl()
|
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl()
|
||||||
|
|
||||||
if self.Recoverable {
|
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
||||||
// Recover from any require exception
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if err != nil {
|
||||||
self.Printf(" %v", r).Endl()
|
self.Printf(" %v", err).Endl()
|
||||||
|
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
|
||||||
context.UseGas(context.Gas)
|
context.UseGas(context.Gas)
|
||||||
|
|
||||||
ret = context.Return(nil)
|
ret = context.Return(nil)
|
||||||
|
|
||||||
err = fmt.Errorf("%v", r)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
if context.CodeAddr != nil {
|
if context.CodeAddr != nil {
|
||||||
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
|
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
|
||||||
|
|
@ -76,18 +72,20 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
step = 0
|
step = 0
|
||||||
statedb = self.env.State()
|
statedb = self.env.State()
|
||||||
|
|
||||||
jump = func(from uint64, to *big.Int) {
|
jump = func(from uint64, to *big.Int) error {
|
||||||
p := to.Uint64()
|
p := to.Uint64()
|
||||||
|
|
||||||
nop := context.GetOp(p)
|
nop := context.GetOp(p)
|
||||||
if !destinations.Has(p) {
|
if !destinations.Has(p) {
|
||||||
panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p))
|
return fmt.Errorf("invalid jump destination (%v) %v", nop, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" ~> %v", to)
|
self.Printf(" ~> %v", to)
|
||||||
pc = to.Uint64()
|
pc = to.Uint64()
|
||||||
|
|
||||||
self.Endl()
|
self.Endl()
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -105,7 +103,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
op = context.GetOp(pc)
|
op = context.GetOp(pc)
|
||||||
|
|
||||||
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
|
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
|
||||||
newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
|
newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
self.Printf("(g) %-3v (%v)", gas, context.Gas)
|
self.Printf("(g) %-3v (%v)", gas, context.Gas)
|
||||||
|
|
||||||
|
|
@ -600,14 +601,18 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
|
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
|
||||||
case JUMP:
|
case JUMP:
|
||||||
jump(pc, stack.pop())
|
if err := jump(pc, stack.pop()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
case JUMPI:
|
case JUMPI:
|
||||||
pos, cond := stack.pop(), stack.pop()
|
pos, cond := stack.pop(), stack.pop()
|
||||||
|
|
||||||
if cond.Cmp(common.BigTrue) >= 0 {
|
if cond.Cmp(common.BigTrue) >= 0 {
|
||||||
jump(pc, pos)
|
if err := jump(pc, pos); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -720,7 +725,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
default:
|
default:
|
||||||
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
|
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
|
||||||
|
|
||||||
panic(fmt.Errorf("Invalid opcode %x", op))
|
return nil, fmt.Errorf("Invalid opcode %x", op)
|
||||||
}
|
}
|
||||||
|
|
||||||
pc++
|
pc++
|
||||||
|
|
@ -729,28 +734,38 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int) {
|
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
|
||||||
var (
|
var (
|
||||||
gas = new(big.Int)
|
gas = new(big.Int)
|
||||||
newMemSize *big.Int = new(big.Int)
|
newMemSize *big.Int = new(big.Int)
|
||||||
)
|
)
|
||||||
baseCheck(op, stack, gas)
|
err := baseCheck(op, stack, gas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// stack Check, memory resize & gas phase
|
// stack Check, memory resize & gas phase
|
||||||
switch op {
|
switch op {
|
||||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
|
||||||
gas.Set(GasFastestStep)
|
|
||||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
||||||
n := int(op - SWAP1 + 2)
|
n := int(op - SWAP1 + 2)
|
||||||
stack.require(n)
|
err := stack.require(n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
gas.Set(GasFastestStep)
|
gas.Set(GasFastestStep)
|
||||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
||||||
n := int(op - DUP1 + 1)
|
n := int(op - DUP1 + 1)
|
||||||
stack.require(n)
|
err := stack.require(n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
gas.Set(GasFastestStep)
|
gas.Set(GasFastestStep)
|
||||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||||
n := int(op - LOG0)
|
n := int(op - LOG0)
|
||||||
stack.require(n + 2)
|
err := stack.require(n + 2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
||||||
|
|
||||||
|
|
@ -762,7 +777,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
||||||
case EXP:
|
case EXP:
|
||||||
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
|
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
|
||||||
case SSTORE:
|
case SSTORE:
|
||||||
stack.require(2)
|
err := stack.require(2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var g *big.Int
|
var g *big.Int
|
||||||
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
||||||
|
|
@ -853,7 +871,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMemSize, gas
|
return newMemSize, gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
|
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
|
||||||
|
|
@ -869,7 +887,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
|
||||||
|
|
||||||
tmp := new(big.Int).Set(context.Gas)
|
tmp := new(big.Int).Set(context.Gas)
|
||||||
|
|
||||||
panic(OOG(gas, tmp).Error())
|
return nil, OOG(gas, tmp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ type Config struct {
|
||||||
Shh bool
|
Shh bool
|
||||||
Dial bool
|
Dial bool
|
||||||
|
|
||||||
|
Etherbase string
|
||||||
MinerThreads int
|
MinerThreads int
|
||||||
AccountManager *accounts.Manager
|
AccountManager *accounts.Manager
|
||||||
|
|
||||||
|
|
@ -140,6 +141,7 @@ type Ethereum struct {
|
||||||
|
|
||||||
Mining bool
|
Mining bool
|
||||||
DataDir string
|
DataDir string
|
||||||
|
etherbase common.Address
|
||||||
clientVersion string
|
clientVersion string
|
||||||
ethVersionId int
|
ethVersionId int
|
||||||
netVersionId int
|
netVersionId int
|
||||||
|
|
@ -185,6 +187,7 @@ func New(config *Config) (*Ethereum, error) {
|
||||||
eventMux: &event.TypeMux{},
|
eventMux: &event.TypeMux{},
|
||||||
accountManager: config.AccountManager,
|
accountManager: config.AccountManager,
|
||||||
DataDir: config.DataDir,
|
DataDir: config.DataDir,
|
||||||
|
etherbase: common.HexToAddress(config.Etherbase),
|
||||||
clientVersion: config.Name, // TODO should separate from Name
|
clientVersion: config.Name, // TODO should separate from Name
|
||||||
ethVersionId: config.ProtocolVersion,
|
ethVersionId: config.ProtocolVersion,
|
||||||
netVersionId: config.NetworkId,
|
netVersionId: config.NetworkId,
|
||||||
|
|
@ -297,15 +300,31 @@ func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) StartMining() error {
|
func (s *Ethereum) StartMining() error {
|
||||||
cb, err := s.accountManager.Coinbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
servlogger.Errorf("Cannot start mining without coinbase: %v\n", err)
|
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
|
||||||
return fmt.Errorf("no coinbase: %v", err)
|
servlogger.Errorln(err)
|
||||||
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
s.miner.Start(common.BytesToAddress(cb))
|
|
||||||
|
s.miner.Start(eb)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
||||||
|
eb = s.etherbase
|
||||||
|
if (eb == common.Address{}) {
|
||||||
|
var ebbytes []byte
|
||||||
|
ebbytes, err = s.accountManager.Primary()
|
||||||
|
eb = common.BytesToAddress(ebbytes)
|
||||||
|
if (eb == common.Address{}) {
|
||||||
|
err = fmt.Errorf("no accounts found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Ethereum) StopMining() { s.miner.Stop() }
|
func (s *Ethereum) StopMining() { s.miner.Stop() }
|
||||||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
||||||
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
package miner
|
package miner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CpuMiner struct {
|
type CpuMiner struct {
|
||||||
|
chMu sync.Mutex
|
||||||
c chan *types.Block
|
c chan *types.Block
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
quitCurrentOp chan struct{}
|
quitCurrentOp chan struct{}
|
||||||
|
|
@ -43,16 +46,13 @@ func (self *CpuMiner) Start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuMiner) update() {
|
func (self *CpuMiner) update() {
|
||||||
justStarted := true
|
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case block := <-self.c:
|
case block := <-self.c:
|
||||||
if justStarted {
|
self.chMu.Lock()
|
||||||
justStarted = true
|
|
||||||
} else {
|
|
||||||
self.quitCurrentOp <- struct{}{}
|
self.quitCurrentOp <- struct{}{}
|
||||||
}
|
self.chMu.Unlock()
|
||||||
|
|
||||||
go self.mine(block)
|
go self.mine(block)
|
||||||
case <-self.quit:
|
case <-self.quit:
|
||||||
|
|
@ -60,6 +60,7 @@ out:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(self.quitCurrentOp)
|
||||||
done:
|
done:
|
||||||
// Empty channel
|
// Empty channel
|
||||||
for {
|
for {
|
||||||
|
|
@ -75,12 +76,20 @@ done:
|
||||||
|
|
||||||
func (self *CpuMiner) mine(block *types.Block) {
|
func (self *CpuMiner) mine(block *types.Block) {
|
||||||
minerlogger.Debugf("(re)started agent[%d]. mining...\n", self.index)
|
minerlogger.Debugf("(re)started agent[%d]. mining...\n", self.index)
|
||||||
|
|
||||||
|
// Reset the channel
|
||||||
|
self.chMu.Lock()
|
||||||
|
self.quitCurrentOp = make(chan struct{}, 1)
|
||||||
|
self.chMu.Unlock()
|
||||||
|
|
||||||
|
// Mine
|
||||||
nonce, mixDigest, _ := self.pow.Search(block, self.quitCurrentOp)
|
nonce, mixDigest, _ := self.pow.Search(block, self.quitCurrentOp)
|
||||||
if nonce != 0 {
|
if nonce != 0 {
|
||||||
block.SetNonce(nonce)
|
block.SetNonce(nonce)
|
||||||
block.Header().MixDigest = common.BytesToHash(mixDigest)
|
block.Header().MixDigest = common.BytesToHash(mixDigest)
|
||||||
self.returnCh <- block
|
self.returnCh <- block
|
||||||
//self.returnCh <- Work{block.Number().Uint64(), nonce, mixDigest, seedHash}
|
} else {
|
||||||
|
self.returnCh <- nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -59,12 +60,13 @@ type Agent interface {
|
||||||
|
|
||||||
type worker struct {
|
type worker struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
agents []Agent
|
agents []Agent
|
||||||
recv chan *types.Block
|
recv chan *types.Block
|
||||||
mux *event.TypeMux
|
mux *event.TypeMux
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
pow pow.PoW
|
pow pow.PoW
|
||||||
atWork int
|
atWork int64
|
||||||
|
|
||||||
eth core.Backend
|
eth core.Backend
|
||||||
chain *core.ChainManager
|
chain *core.ChainManager
|
||||||
|
|
@ -107,7 +109,7 @@ func (self *worker) start() {
|
||||||
|
|
||||||
func (self *worker) stop() {
|
func (self *worker) stop() {
|
||||||
self.mining = false
|
self.mining = false
|
||||||
self.atWork = 0
|
atomic.StoreInt64(&self.atWork, 0)
|
||||||
|
|
||||||
close(self.quit)
|
close(self.quit)
|
||||||
}
|
}
|
||||||
|
|
@ -135,9 +137,6 @@ out:
|
||||||
self.uncleMu.Unlock()
|
self.uncleMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.atWork == 0 {
|
|
||||||
self.commitNewWork()
|
|
||||||
}
|
|
||||||
case <-self.quit:
|
case <-self.quit:
|
||||||
// stop all agents
|
// stop all agents
|
||||||
for _, agent := range self.agents {
|
for _, agent := range self.agents {
|
||||||
|
|
@ -146,6 +145,11 @@ out:
|
||||||
break out
|
break out
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")
|
minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")
|
||||||
|
|
||||||
|
// XXX In case all mined a possible uncle
|
||||||
|
if atomic.LoadInt64(&self.atWork) == 0 {
|
||||||
|
self.commitNewWork()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +159,12 @@ out:
|
||||||
func (self *worker) wait() {
|
func (self *worker) wait() {
|
||||||
for {
|
for {
|
||||||
for block := range self.recv {
|
for block := range self.recv {
|
||||||
|
atomic.AddInt64(&self.atWork, -1)
|
||||||
|
|
||||||
|
if block == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if err := self.chain.InsertChain(types.Blocks{block}); err == nil {
|
if err := self.chain.InsertChain(types.Blocks{block}); err == nil {
|
||||||
for _, uncle := range block.Uncles() {
|
for _, uncle := range block.Uncles() {
|
||||||
delete(self.possibleUncles, uncle.Hash())
|
delete(self.possibleUncles, uncle.Hash())
|
||||||
|
|
@ -170,7 +180,6 @@ func (self *worker) wait() {
|
||||||
} else {
|
} else {
|
||||||
self.commitNewWork()
|
self.commitNewWork()
|
||||||
}
|
}
|
||||||
self.atWork--
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -182,8 +191,9 @@ func (self *worker) push() {
|
||||||
|
|
||||||
// push new work to agents
|
// push new work to agents
|
||||||
for _, agent := range self.agents {
|
for _, agent := range self.agents {
|
||||||
|
atomic.AddInt64(&self.atWork, 1)
|
||||||
|
|
||||||
agent.Work() <- self.current.block.Copy()
|
agent.Work() <- self.current.block.Copy()
|
||||||
self.atWork++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
rpc/api.go
23
rpc/api.go
|
|
@ -3,13 +3,11 @@ package rpc
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
"path"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -19,15 +17,9 @@ type EthereumApi struct {
|
||||||
db common.Database
|
db common.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEthereumApi(xeth *xeth.XEth, dataDir string) *EthereumApi {
|
func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
|
||||||
// What about when dataDir is empty?
|
|
||||||
db, err := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
api := &EthereumApi{
|
api := &EthereumApi{
|
||||||
eth: xeth,
|
eth: xeth,
|
||||||
db: db,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return api
|
return api
|
||||||
|
|
@ -44,10 +36,6 @@ func (api *EthereumApi) xethAtStateNum(num int64) *xeth.XEth {
|
||||||
return api.xeth().AtStateNum(num)
|
return api.xeth().AtStateNum(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *EthereumApi) Close() {
|
|
||||||
api.db.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
|
func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
|
||||||
// Spec at https://github.com/ethereum/wiki/wiki/JSON-RPC
|
// Spec at https://github.com/ethereum/wiki/wiki/JSON-RPC
|
||||||
rpclogger.Debugf("%s %s", req.Method, req.Params)
|
rpclogger.Debugf("%s %s", req.Method, req.Params)
|
||||||
|
|
@ -370,7 +358,8 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
api.db.Put([]byte(args.Database+args.Key), args.Value)
|
api.xeth().DbPut([]byte(args.Database+args.Key), args.Value)
|
||||||
|
|
||||||
*reply = true
|
*reply = true
|
||||||
case "db_getString":
|
case "db_getString":
|
||||||
args := new(DbArgs)
|
args := new(DbArgs)
|
||||||
|
|
@ -382,7 +371,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, _ := api.db.Get([]byte(args.Database + args.Key))
|
res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
|
||||||
*reply = string(res)
|
*reply = string(res)
|
||||||
case "db_putHex":
|
case "db_putHex":
|
||||||
args := new(DbHexArgs)
|
args := new(DbHexArgs)
|
||||||
|
|
@ -394,7 +383,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
api.db.Put([]byte(args.Database+args.Key), args.Value)
|
api.xeth().DbPut([]byte(args.Database+args.Key), args.Value)
|
||||||
*reply = true
|
*reply = true
|
||||||
case "db_getHex":
|
case "db_getHex":
|
||||||
args := new(DbHexArgs)
|
args := new(DbHexArgs)
|
||||||
|
|
@ -406,7 +395,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, _ := api.db.Get([]byte(args.Database + args.Key))
|
res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
|
||||||
*reply = common.ToHex(res)
|
*reply = common.ToHex(res)
|
||||||
case "shh_version":
|
case "shh_version":
|
||||||
*reply = api.xeth().WhisperVersion()
|
*reply = api.xeth().WhisperVersion()
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
// "time"
|
// "time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
// "github.com/ethereum/go-ethereum/xeth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWeb3Sha3(t *testing.T) {
|
func TestWeb3Sha3(t *testing.T) {
|
||||||
|
|
@ -26,49 +26,48 @@ func TestWeb3Sha3(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDbStr(t *testing.T) {
|
// func TestDbStr(t *testing.T) {
|
||||||
jsonput := `{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":64}`
|
// jsonput := `{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":64}`
|
||||||
jsonget := `{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":64}`
|
// jsonget := `{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":64}`
|
||||||
expected := "myString"
|
// expected := "myString"
|
||||||
|
|
||||||
xeth := &xeth.XEth{}
|
// xeth := &xeth.XEth{}
|
||||||
api := NewEthereumApi(xeth, "")
|
// api := NewEthereumApi(xeth)
|
||||||
defer api.db.Close()
|
// var response interface{}
|
||||||
var response interface{}
|
|
||||||
|
|
||||||
var req RpcRequest
|
// var req RpcRequest
|
||||||
json.Unmarshal([]byte(jsonput), &req)
|
// json.Unmarshal([]byte(jsonput), &req)
|
||||||
_ = api.GetRequestReply(&req, &response)
|
// _ = api.GetRequestReply(&req, &response)
|
||||||
|
|
||||||
json.Unmarshal([]byte(jsonget), &req)
|
// json.Unmarshal([]byte(jsonget), &req)
|
||||||
_ = api.GetRequestReply(&req, &response)
|
// _ = api.GetRequestReply(&req, &response)
|
||||||
|
|
||||||
if response.(string) != expected {
|
// if response.(string) != expected {
|
||||||
t.Errorf("Expected %s got %s", expected, response)
|
// t.Errorf("Expected %s got %s", expected, response)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestDbHexStr(t *testing.T) {
|
// func TestDbHexStr(t *testing.T) {
|
||||||
jsonput := `{"jsonrpc":"2.0","method":"db_putHex","params":["testDB","beefKey","0xbeef"],"id":64}`
|
// jsonput := `{"jsonrpc":"2.0","method":"db_putHex","params":["testDB","beefKey","0xbeef"],"id":64}`
|
||||||
jsonget := `{"jsonrpc":"2.0","method":"db_getHex","params":["testDB","beefKey"],"id":64}`
|
// jsonget := `{"jsonrpc":"2.0","method":"db_getHex","params":["testDB","beefKey"],"id":64}`
|
||||||
expected := "0xbeef"
|
// expected := "0xbeef"
|
||||||
|
|
||||||
xeth := &xeth.XEth{}
|
// xeth := &xeth.XEth{}
|
||||||
api := NewEthereumApi(xeth, "")
|
// api := NewEthereumApi(xeth)
|
||||||
defer api.db.Close()
|
// defer api.db.Close()
|
||||||
var response interface{}
|
// var response interface{}
|
||||||
|
|
||||||
var req RpcRequest
|
// var req RpcRequest
|
||||||
json.Unmarshal([]byte(jsonput), &req)
|
// json.Unmarshal([]byte(jsonput), &req)
|
||||||
_ = api.GetRequestReply(&req, &response)
|
// _ = api.GetRequestReply(&req, &response)
|
||||||
|
|
||||||
json.Unmarshal([]byte(jsonget), &req)
|
// json.Unmarshal([]byte(jsonget), &req)
|
||||||
_ = api.GetRequestReply(&req, &response)
|
// _ = api.GetRequestReply(&req, &response)
|
||||||
|
|
||||||
if response.(string) != expected {
|
// if response.(string) != expected {
|
||||||
t.Errorf("Expected %s got %s", expected, response)
|
// t.Errorf("Expected %s got %s", expected, response)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// func TestFilterClose(t *testing.T) {
|
// func TestFilterClose(t *testing.T) {
|
||||||
// t.Skip()
|
// t.Skip()
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
|
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
|
||||||
func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
|
func JSONRPC(pipe *xeth.XEth) http.Handler {
|
||||||
api := NewEthereumApi(pipe, dataDir)
|
api := NewEthereumApi(pipe)
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
// TODO this needs to be configurable
|
// TODO this needs to be configurable
|
||||||
|
|
|
||||||
111
rpc/responses.go
111
rpc/responses.go
|
|
@ -6,14 +6,14 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockRes struct {
|
type BlockRes struct {
|
||||||
fullTx bool
|
fullTx bool
|
||||||
|
|
||||||
BlockNumber int64 `json:"number"`
|
BlockNumber *big.Int `json:"number"`
|
||||||
BlockHash common.Hash `json:"hash"`
|
BlockHash common.Hash `json:"hash"`
|
||||||
ParentHash common.Hash `json:"parentHash"`
|
ParentHash common.Hash `json:"parentHash"`
|
||||||
Nonce [8]byte `json:"nonce"`
|
Nonce [8]byte `json:"nonce"`
|
||||||
|
|
@ -22,13 +22,13 @@ type BlockRes struct {
|
||||||
TransactionRoot common.Hash `json:"transactionRoot"`
|
TransactionRoot common.Hash `json:"transactionRoot"`
|
||||||
StateRoot common.Hash `json:"stateRoot"`
|
StateRoot common.Hash `json:"stateRoot"`
|
||||||
Miner common.Address `json:"miner"`
|
Miner common.Address `json:"miner"`
|
||||||
Difficulty int64 `json:"difficulty"`
|
Difficulty *big.Int `json:"difficulty"`
|
||||||
TotalDifficulty int64 `json:"totalDifficulty"`
|
TotalDifficulty *big.Int `json:"totalDifficulty"`
|
||||||
Size int64 `json:"size"`
|
Size *big.Int `json:"size"`
|
||||||
ExtraData []byte `json:"extraData"`
|
ExtraData []byte `json:"extraData"`
|
||||||
GasLimit int64 `json:"gasLimit"`
|
GasLimit *big.Int `json:"gasLimit"`
|
||||||
MinGasPrice int64 `json:"minGasPrice"`
|
MinGasPrice int64 `json:"minGasPrice"`
|
||||||
GasUsed int64 `json:"gasUsed"`
|
GasUsed *big.Int `json:"gasUsed"`
|
||||||
UnixTimestamp int64 `json:"timestamp"`
|
UnixTimestamp int64 `json:"timestamp"`
|
||||||
Transactions []*TransactionRes `json:"transactions"`
|
Transactions []*TransactionRes `json:"transactions"`
|
||||||
Uncles []common.Hash `json:"uncles"`
|
Uncles []common.Hash `json:"uncles"`
|
||||||
|
|
@ -58,7 +58,7 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert strict types to hexified strings
|
// convert strict types to hexified strings
|
||||||
ext.BlockNumber = common.ToHex(big.NewInt(b.BlockNumber).Bytes())
|
ext.BlockNumber = common.ToHex(b.BlockNumber.Bytes())
|
||||||
ext.BlockHash = b.BlockHash.Hex()
|
ext.BlockHash = b.BlockHash.Hex()
|
||||||
ext.ParentHash = b.ParentHash.Hex()
|
ext.ParentHash = b.ParentHash.Hex()
|
||||||
ext.Nonce = common.ToHex(b.Nonce[:])
|
ext.Nonce = common.ToHex(b.Nonce[:])
|
||||||
|
|
@ -67,13 +67,13 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
||||||
ext.TransactionRoot = b.TransactionRoot.Hex()
|
ext.TransactionRoot = b.TransactionRoot.Hex()
|
||||||
ext.StateRoot = b.StateRoot.Hex()
|
ext.StateRoot = b.StateRoot.Hex()
|
||||||
ext.Miner = b.Miner.Hex()
|
ext.Miner = b.Miner.Hex()
|
||||||
ext.Difficulty = common.ToHex(big.NewInt(b.Difficulty).Bytes())
|
ext.Difficulty = common.ToHex(b.Difficulty.Bytes())
|
||||||
ext.TotalDifficulty = common.ToHex(big.NewInt(b.TotalDifficulty).Bytes())
|
ext.TotalDifficulty = common.ToHex(b.TotalDifficulty.Bytes())
|
||||||
ext.Size = common.ToHex(big.NewInt(b.Size).Bytes())
|
ext.Size = common.ToHex(b.Size.Bytes())
|
||||||
// ext.ExtraData = common.ToHex(b.ExtraData)
|
// ext.ExtraData = common.ToHex(b.ExtraData)
|
||||||
ext.GasLimit = common.ToHex(big.NewInt(b.GasLimit).Bytes())
|
ext.GasLimit = common.ToHex(b.GasLimit.Bytes())
|
||||||
// ext.MinGasPrice = common.ToHex(big.NewInt(b.MinGasPrice).Bytes())
|
// ext.MinGasPrice = common.ToHex(big.NewInt(b.MinGasPrice).Bytes())
|
||||||
ext.GasUsed = common.ToHex(big.NewInt(b.GasUsed).Bytes())
|
ext.GasUsed = common.ToHex(b.GasUsed.Bytes())
|
||||||
ext.UnixTimestamp = common.ToHex(big.NewInt(b.UnixTimestamp).Bytes())
|
ext.UnixTimestamp = common.ToHex(big.NewInt(b.UnixTimestamp).Bytes())
|
||||||
ext.Transactions = make([]interface{}, len(b.Transactions))
|
ext.Transactions = make([]interface{}, len(b.Transactions))
|
||||||
if b.fullTx {
|
if b.fullTx {
|
||||||
|
|
@ -99,7 +99,7 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
||||||
}
|
}
|
||||||
|
|
||||||
res := new(BlockRes)
|
res := new(BlockRes)
|
||||||
res.BlockNumber = block.Number().Int64()
|
res.BlockNumber = block.Number()
|
||||||
res.BlockHash = block.Hash()
|
res.BlockHash = block.Hash()
|
||||||
res.ParentHash = block.ParentHash()
|
res.ParentHash = block.ParentHash()
|
||||||
res.Nonce = block.Header().Nonce
|
res.Nonce = block.Header().Nonce
|
||||||
|
|
@ -108,15 +108,13 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
||||||
res.TransactionRoot = block.Header().TxHash
|
res.TransactionRoot = block.Header().TxHash
|
||||||
res.StateRoot = block.Root()
|
res.StateRoot = block.Root()
|
||||||
res.Miner = block.Header().Coinbase
|
res.Miner = block.Header().Coinbase
|
||||||
res.Difficulty = block.Difficulty().Int64()
|
res.Difficulty = block.Difficulty()
|
||||||
if block.Td != nil {
|
res.TotalDifficulty = block.Td
|
||||||
res.TotalDifficulty = block.Td.Int64()
|
res.Size = big.NewInt(int64(block.Size()))
|
||||||
}
|
|
||||||
res.Size = int64(block.Size())
|
|
||||||
// res.ExtraData =
|
// res.ExtraData =
|
||||||
res.GasLimit = block.GasLimit().Int64()
|
res.GasLimit = block.GasLimit()
|
||||||
// res.MinGasPrice =
|
// res.MinGasPrice =
|
||||||
res.GasUsed = block.GasUsed().Int64()
|
res.GasUsed = block.GasUsed()
|
||||||
res.UnixTimestamp = block.Time()
|
res.UnixTimestamp = block.Time()
|
||||||
res.Transactions = make([]*TransactionRes, len(block.Transactions()))
|
res.Transactions = make([]*TransactionRes, len(block.Transactions()))
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
|
@ -135,15 +133,15 @@ func NewBlockRes(block *types.Block) *BlockRes {
|
||||||
|
|
||||||
type TransactionRes struct {
|
type TransactionRes struct {
|
||||||
Hash common.Hash `json:"hash"`
|
Hash common.Hash `json:"hash"`
|
||||||
Nonce int64 `json:"nonce"`
|
Nonce uint64 `json:"nonce"`
|
||||||
BlockHash common.Hash `json:"blockHash,omitempty"`
|
BlockHash common.Hash `json:"blockHash,omitempty"`
|
||||||
BlockNumber int64 `json:"blockNumber,omitempty"`
|
BlockNumber int64 `json:"blockNumber,omitempty"`
|
||||||
TxIndex int64 `json:"transactionIndex,omitempty"`
|
TxIndex int64 `json:"transactionIndex,omitempty"`
|
||||||
From common.Address `json:"from"`
|
From common.Address `json:"from"`
|
||||||
To *common.Address `json:"to"`
|
To *common.Address `json:"to"`
|
||||||
Value int64 `json:"value"`
|
Value *big.Int `json:"value"`
|
||||||
Gas int64 `json:"gas"`
|
Gas *big.Int `json:"gas"`
|
||||||
GasPrice int64 `json:"gasPrice"`
|
GasPrice *big.Int `json:"gasPrice"`
|
||||||
Input []byte `json:"input"`
|
Input []byte `json:"input"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +153,7 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
||||||
BlockNumber string `json:"blockNumber,omitempty"`
|
BlockNumber string `json:"blockNumber,omitempty"`
|
||||||
TxIndex string `json:"transactionIndex,omitempty"`
|
TxIndex string `json:"transactionIndex,omitempty"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To interface{} `json:"to"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Gas string `json:"gas"`
|
Gas string `json:"gas"`
|
||||||
GasPrice string `json:"gasPrice"`
|
GasPrice string `json:"gasPrice"`
|
||||||
|
|
@ -163,19 +161,19 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.Hash = t.Hash.Hex()
|
ext.Hash = t.Hash.Hex()
|
||||||
ext.Nonce = common.ToHex(big.NewInt(t.Nonce).Bytes())
|
ext.Nonce = common.ToHex(big.NewInt(int64(t.Nonce)).Bytes())
|
||||||
ext.BlockHash = t.BlockHash.Hex()
|
ext.BlockHash = t.BlockHash.Hex()
|
||||||
ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes())
|
ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes())
|
||||||
ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes())
|
ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes())
|
||||||
ext.From = t.From.Hex()
|
ext.From = t.From.Hex()
|
||||||
if t.To == nil {
|
if t.To == nil {
|
||||||
ext.To = "0x00"
|
ext.To = nil
|
||||||
} else {
|
} else {
|
||||||
ext.To = t.To.Hex()
|
ext.To = t.To.Hex()
|
||||||
}
|
}
|
||||||
ext.Value = common.ToHex(big.NewInt(t.Value).Bytes())
|
ext.Value = common.ToHex(t.Value.Bytes())
|
||||||
ext.Gas = common.ToHex(big.NewInt(t.Gas).Bytes())
|
ext.Gas = common.ToHex(t.Gas.Bytes())
|
||||||
ext.GasPrice = common.ToHex(big.NewInt(t.GasPrice).Bytes())
|
ext.GasPrice = common.ToHex(t.GasPrice.Bytes())
|
||||||
ext.Input = common.ToHex(t.Input)
|
ext.Input = common.ToHex(t.Input)
|
||||||
|
|
||||||
return json.Marshal(ext)
|
return json.Marshal(ext)
|
||||||
|
|
@ -184,12 +182,12 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) {
|
||||||
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
|
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
|
||||||
var v = new(TransactionRes)
|
var v = new(TransactionRes)
|
||||||
v.Hash = tx.Hash()
|
v.Hash = tx.Hash()
|
||||||
v.Nonce = int64(tx.Nonce())
|
v.Nonce = tx.Nonce()
|
||||||
v.From, _ = tx.From()
|
v.From, _ = tx.From()
|
||||||
v.To = tx.To()
|
v.To = tx.To()
|
||||||
v.Value = tx.Value().Int64()
|
v.Value = tx.Value()
|
||||||
v.Gas = tx.Gas().Int64()
|
v.Gas = tx.Gas()
|
||||||
v.GasPrice = tx.GasPrice().Int64()
|
v.GasPrice = tx.GasPrice()
|
||||||
v.Input = tx.Data()
|
v.Input = tx.Data()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
@ -218,25 +216,48 @@ type FilterWhisperRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogRes struct {
|
type LogRes struct {
|
||||||
|
Address common.Address `json:"address"`
|
||||||
|
Topics []common.Hash `json:"topics"`
|
||||||
|
Data []byte `json:"data"`
|
||||||
|
Number uint64 `json:"number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogRes(log state.Log) LogRes {
|
||||||
|
var l LogRes
|
||||||
|
l.Topics = make([]common.Hash, len(log.Topics()))
|
||||||
|
l.Address = log.Address()
|
||||||
|
l.Data = log.Data()
|
||||||
|
l.Number = log.Number()
|
||||||
|
for j, topic := range log.Topics() {
|
||||||
|
l.Topics[j] = topic
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogRes) MarshalJSON() ([]byte, error) {
|
||||||
|
var ext struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Topics []string `json:"topics"`
|
Topics []string `json:"topics"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Number uint64 `json:"number"`
|
Number string `json:"number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
ext.Address = l.Address.Hex()
|
||||||
|
ext.Data = common.Bytes2Hex(l.Data)
|
||||||
|
ext.Number = common.Bytes2Hex(big.NewInt(int64(l.Number)).Bytes())
|
||||||
|
ext.Topics = make([]string, len(l.Topics))
|
||||||
|
for i, v := range l.Topics {
|
||||||
|
ext.Topics[i] = v.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogsRes(logs state.Logs) (ls []LogRes) {
|
func NewLogsRes(logs state.Logs) (ls []LogRes) {
|
||||||
ls = make([]LogRes, len(logs))
|
ls = make([]LogRes, len(logs))
|
||||||
|
|
||||||
for i, log := range logs {
|
for i, log := range logs {
|
||||||
var l LogRes
|
ls[i] = NewLogRes(log)
|
||||||
l.Topics = make([]string, len(log.Topics()))
|
|
||||||
l.Address = log.Address().Hex()
|
|
||||||
l.Data = common.ToHex(log.Data())
|
|
||||||
l.Number = log.Number()
|
|
||||||
for j, topic := range log.Topics() {
|
|
||||||
l.Topics[j] = topic.Hex()
|
|
||||||
}
|
|
||||||
ls[i] = l
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
||||||
123
rpc/responses_test.go
Normal file
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
|
return accountAddresses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *XEth) DbPut(key, val []byte) bool {
|
||||||
|
self.backend.ExtraDb().Put(key, val)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *XEth) DbGet(key []byte) ([]byte, error) {
|
||||||
|
val, err := self.backend.ExtraDb().Get(key)
|
||||||
|
return val, err
|
||||||
|
}
|
||||||
|
|
||||||
func (self *XEth) PeerCount() int {
|
func (self *XEth) PeerCount() int {
|
||||||
return self.backend.PeerCount()
|
return self.backend.PeerCount()
|
||||||
}
|
}
|
||||||
|
|
@ -250,8 +260,8 @@ func (self *XEth) IsListening() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) Coinbase() string {
|
func (self *XEth) Coinbase() string {
|
||||||
cb, _ := self.backend.AccountManager().Coinbase()
|
eb, _ := self.backend.Etherbase()
|
||||||
return common.ToHex(cb)
|
return eb.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) NumberToHuman(balance string) string {
|
func (self *XEth) NumberToHuman(balance string) string {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue