Compare commits
37 Commits
v1.0.2
...
release/1.
Author | SHA1 | Date | |
---|---|---|---|
0397c66c4d | |||
0cdc7647aa | |||
c5d7faefe9 | |||
d7211dec79 | |||
cea2c0eedf | |||
b738172dcc | |||
abdc3d3c77 | |||
80901e8288 | |||
465796c3a8 | |||
9c05284bd1 | |||
56edaa1653 | |||
8865fda872 | |||
b0df9b164c | |||
72188234aa | |||
8c0619d29c | |||
16a3a4303f | |||
eaed7584f1 | |||
0262ba58cb | |||
e088998867 | |||
db5ec711e8 | |||
9d49c80783 | |||
b1fdb9f38e | |||
a606dc274b | |||
c9d6fba07d | |||
228fc5a83a | |||
c28dc03f6d | |||
dcb276a0dd | |||
53864a73db | |||
cf65a127e1 | |||
fd64dce6a5 | |||
d60b07249c | |||
7b99278eb0 | |||
aaf8ae1d0b | |||
a83fdd0046 | |||
b1a219b0ec | |||
487b3b0f7b | |||
4ca3d49307 |
@ -1,6 +1,9 @@
|
|||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.4.2
|
- 1.4.2
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get install -yqq libgmp3-dev
|
||||||
install:
|
install:
|
||||||
# - go get code.google.com/p/go.tools/cmd/goimports
|
# - go get code.google.com/p/go.tools/cmd/goimports
|
||||||
# - go get github.com/golang/lint/golint
|
# - go get github.com/golang/lint/golint
|
||||||
@ -19,11 +22,7 @@ after_success:
|
|||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
||||||
sudo: false
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- libgmp3-dev
|
|
||||||
notifications:
|
notifications:
|
||||||
webhooks:
|
webhooks:
|
||||||
urls:
|
urls:
|
||||||
|
4
Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go
generated
vendored
4
Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go
generated
vendored
@ -9,8 +9,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical
|
// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical
|
||||||
@ -27,7 +25,6 @@ func NewHTTPUClient() (*HTTPUClient, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fdtrack.Open("upnp")
|
|
||||||
return &HTTPUClient{conn: conn}, nil
|
return &HTTPUClient{conn: conn}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +33,6 @@ func NewHTTPUClient() (*HTTPUClient, error) {
|
|||||||
func (httpu *HTTPUClient) Close() error {
|
func (httpu *HTTPUClient) Close() error {
|
||||||
httpu.connLock.Lock()
|
httpu.connLock.Lock()
|
||||||
defer httpu.connLock.Unlock()
|
defer httpu.connLock.Unlock()
|
||||||
fdtrack.Close("upnp")
|
|
||||||
return httpu.conn.Close()
|
return httpu.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go
generated
vendored
14
Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go
generated
vendored
@ -7,12 +7,9 @@ import (
|
|||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -29,17 +26,6 @@ type SOAPClient struct {
|
|||||||
func NewSOAPClient(endpointURL url.URL) *SOAPClient {
|
func NewSOAPClient(endpointURL url.URL) *SOAPClient {
|
||||||
return &SOAPClient{
|
return &SOAPClient{
|
||||||
EndpointURL: endpointURL,
|
EndpointURL: endpointURL,
|
||||||
HTTPClient: http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Dial: func(network, addr string) (net.Conn, error) {
|
|
||||||
c, err := net.Dial(network, addr)
|
|
||||||
if c != nil {
|
|
||||||
c = fdtrack.WrapConn("upnp", c)
|
|
||||||
}
|
|
||||||
return c, err
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
generated
vendored
4
Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
generated
vendored
@ -5,8 +5,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Implement the NAT-PMP protocol, typically supported by Apple routers and open source
|
// Implement the NAT-PMP protocol, typically supported by Apple routers and open source
|
||||||
@ -104,8 +102,6 @@ func (n *Client) rpc(msg []byte, resultSize int) (result []byte, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fdtrack.Open("natpmp")
|
|
||||||
defer fdtrack.Close("natpmp")
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
result = make([]byte, resultSize)
|
result = make([]byte, resultSize)
|
||||||
|
5
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
generated
vendored
5
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
generated
vendored
@ -18,7 +18,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -370,8 +369,6 @@ func (fw fileWrap) Close() error {
|
|||||||
err := fw.File.Close()
|
err := fw.File.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.fs.log(fmt.Sprintf("close %s.%d: %v", f.Type(), f.Num(), err))
|
f.fs.log(fmt.Sprintf("close %s.%d: %v", f.Type(), f.Num(), err))
|
||||||
} else {
|
|
||||||
fdtrack.Close("leveldb")
|
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -403,7 +400,6 @@ func (f *file) Open() (Reader, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
fdtrack.Open("leveldb")
|
|
||||||
f.open = true
|
f.open = true
|
||||||
f.fs.open++
|
f.fs.open++
|
||||||
return fileWrap{of, f}, nil
|
return fileWrap{of, f}, nil
|
||||||
@ -422,7 +418,6 @@ func (f *file) Create() (Writer, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fdtrack.Open("leveldb")
|
|
||||||
f.open = true
|
f.open = true
|
||||||
f.fs.open++
|
f.fs.open++
|
||||||
return fileWrap{of, f}, nil
|
return fileWrap{of, f}, nil
|
||||||
|
@ -78,8 +78,8 @@ func (am *Manager) DeleteAccount(address common.Address, auth string) error {
|
|||||||
|
|
||||||
func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) {
|
func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) {
|
||||||
am.mutex.RLock()
|
am.mutex.RLock()
|
||||||
defer am.mutex.RUnlock()
|
|
||||||
unlockedKey, found := am.unlocked[a.Address]
|
unlockedKey, found := am.unlocked[a.Address]
|
||||||
|
am.mutex.RUnlock()
|
||||||
if !found {
|
if !found {
|
||||||
return nil, ErrLocked
|
return nil, ErrLocked
|
||||||
}
|
}
|
||||||
@ -87,17 +87,14 @@ func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error)
|
|||||||
return signature, err
|
return signature, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock unlocks the given account indefinitely.
|
// unlock indefinitely
|
||||||
func (am *Manager) Unlock(addr common.Address, keyAuth string) error {
|
func (am *Manager) Unlock(addr common.Address, keyAuth string) error {
|
||||||
return am.TimedUnlock(addr, keyAuth, 0)
|
return am.TimedUnlock(addr, keyAuth, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimedUnlock unlocks the account with the given address. The account
|
// Unlock unlocks the account with the given address. The account
|
||||||
// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
|
// stays unlocked for the duration of timeout
|
||||||
// until the program exits.
|
// it timeout is 0 the account is unlocked for the entire session
|
||||||
//
|
|
||||||
// If the accout is already unlocked, TimedUnlock extends or shortens
|
|
||||||
// the active unlock timeout.
|
|
||||||
func (am *Manager) TimedUnlock(addr common.Address, keyAuth string, timeout time.Duration) error {
|
func (am *Manager) TimedUnlock(addr common.Address, keyAuth string, timeout time.Duration) error {
|
||||||
key, err := am.keyStore.GetKey(addr, keyAuth)
|
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,10 +23,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testSigData = make([]byte, 32)
|
|
||||||
|
|
||||||
func TestSign(t *testing.T) {
|
func TestSign(t *testing.T) {
|
||||||
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain)
|
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
@ -34,24 +33,26 @@ func TestSign(t *testing.T) {
|
|||||||
am := NewManager(ks)
|
am := NewManager(ks)
|
||||||
pass := "" // not used but required by API
|
pass := "" // not used but required by API
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
|
toSign := randentropy.GetEntropyCSPRNG(32)
|
||||||
am.Unlock(a1.Address, "")
|
am.Unlock(a1.Address, "")
|
||||||
|
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTimedUnlock(t *testing.T) {
|
func TestTimedUnlock(t *testing.T) {
|
||||||
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain)
|
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePassphrase)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
am := NewManager(ks)
|
am := NewManager(ks)
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
|
toSign := randentropy.GetEntropyCSPRNG(32)
|
||||||
|
|
||||||
// Signing without passphrase fails because account is locked
|
// Signing without passphrase fails because account is locked
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != ErrLocked {
|
if err != ErrLocked {
|
||||||
t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
|
t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
|
||||||
}
|
}
|
||||||
@ -62,26 +63,28 @@ func TestTimedUnlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Signing without passphrase works because account is temp unlocked
|
// Signing without passphrase works because account is temp unlocked
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signing fails again after automatic locking
|
// Signing fails again after automatic locking
|
||||||
time.Sleep(150 * time.Millisecond)
|
time.Sleep(150 * time.Millisecond)
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != ErrLocked {
|
if err != ErrLocked {
|
||||||
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
|
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOverrideUnlock(t *testing.T) {
|
func TestOverrideUnlock(t *testing.T) {
|
||||||
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain)
|
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePassphrase)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
am := NewManager(ks)
|
am := NewManager(ks)
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
|
toSign := randentropy.GetEntropyCSPRNG(32)
|
||||||
|
|
||||||
// Unlock indefinitely
|
// Unlock indefinitely
|
||||||
if err = am.Unlock(a1.Address, pass); err != nil {
|
if err = am.Unlock(a1.Address, pass); err != nil {
|
||||||
@ -89,7 +92,7 @@ func TestOverrideUnlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Signing without passphrase works because account is temp unlocked
|
// Signing without passphrase works because account is temp unlocked
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
||||||
}
|
}
|
||||||
@ -100,46 +103,20 @@ func TestOverrideUnlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Signing without passphrase still works because account is temp unlocked
|
// Signing without passphrase still works because account is temp unlocked
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signing fails again after automatic locking
|
// Signing fails again after automatic locking
|
||||||
time.Sleep(150 * time.Millisecond)
|
time.Sleep(150 * time.Millisecond)
|
||||||
_, err = am.Sign(a1, testSigData)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != ErrLocked {
|
if err != ErrLocked {
|
||||||
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
|
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test should fail under -race if signing races the expiration goroutine.
|
//
|
||||||
func TestSignRace(t *testing.T) {
|
|
||||||
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain)
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
|
|
||||||
// Create a test account.
|
|
||||||
am := NewManager(ks)
|
|
||||||
a1, err := am.NewAccount("")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("could not create the test account", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := am.TimedUnlock(a1.Address, "", 15*time.Millisecond); err != nil {
|
|
||||||
t.Fatalf("could not unlock the test account", err)
|
|
||||||
}
|
|
||||||
end := time.Now().Add(500 * time.Millisecond)
|
|
||||||
for time.Now().Before(end) {
|
|
||||||
if _, err := am.Sign(a1, testSigData); err == ErrLocked {
|
|
||||||
return
|
|
||||||
} else if err != nil {
|
|
||||||
t.Errorf("Sign error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
t.Errorf("Account did not lock within the timeout")
|
|
||||||
}
|
|
||||||
|
|
||||||
func tmpKeyStore(t *testing.T, new func(string) crypto.KeyStore) (string, crypto.KeyStore) {
|
func tmpKeyStore(t *testing.T, new func(string) crypto.KeyStore) (string, crypto.KeyStore) {
|
||||||
d, err := ioutil.TempDir("", "eth-keystore-test")
|
d, err := ioutil.TempDir("", "eth-keystore-test")
|
||||||
|
@ -36,7 +36,6 @@ var (
|
|||||||
defaultTest = "all"
|
defaultTest = "all"
|
||||||
defaultDir = "."
|
defaultDir = "."
|
||||||
allTests = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests", "RLPTests"}
|
allTests = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests", "RLPTests"}
|
||||||
testDirMapping = map[string]string{"BlockTests": "BlockchainTests"}
|
|
||||||
skipTests = []string{}
|
skipTests = []string{}
|
||||||
|
|
||||||
TestFlag = cli.StringFlag{
|
TestFlag = cli.StringFlag{
|
||||||
@ -136,13 +135,8 @@ func runSuite(test, file string) {
|
|||||||
var err error
|
var err error
|
||||||
var files []string
|
var files []string
|
||||||
if test == defaultTest {
|
if test == defaultTest {
|
||||||
// check if we have an explicit directory mapping for the test
|
files, err = getFiles(filepath.Join(file, curTest))
|
||||||
if _, ok := testDirMapping[curTest]; ok {
|
|
||||||
files, err = getFiles(filepath.Join(file, testDirMapping[curTest]))
|
|
||||||
} else {
|
|
||||||
// otherwise assume test name
|
|
||||||
files, err = getFiles(filepath.Join(file, curTest))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
files, err = getFiles(file)
|
files, err = getFiles(file)
|
||||||
}
|
}
|
||||||
|
112
cmd/evm/main.go
112
cmd/evm/main.go
@ -18,129 +18,79 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
|
||||||
"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"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"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/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
app *cli.App
|
code = flag.String("code", "", "evm code")
|
||||||
DebugFlag = cli.BoolFlag{
|
loglevel = flag.Int("log", 4, "log level")
|
||||||
Name: "debug",
|
gas = flag.String("gas", "1000000000", "gas amount")
|
||||||
Usage: "output full trace logs",
|
price = flag.String("price", "0", "gas price")
|
||||||
}
|
value = flag.String("value", "0", "tx value")
|
||||||
CodeFlag = cli.StringFlag{
|
dump = flag.Bool("dump", false, "dump state after run")
|
||||||
Name: "code",
|
data = flag.String("data", "", "data")
|
||||||
Usage: "EVM code",
|
|
||||||
}
|
|
||||||
GasFlag = cli.StringFlag{
|
|
||||||
Name: "gas",
|
|
||||||
Usage: "gas limit for the evm",
|
|
||||||
Value: "10000000000",
|
|
||||||
}
|
|
||||||
PriceFlag = cli.StringFlag{
|
|
||||||
Name: "price",
|
|
||||||
Usage: "price set for the evm",
|
|
||||||
Value: "0",
|
|
||||||
}
|
|
||||||
ValueFlag = cli.StringFlag{
|
|
||||||
Name: "value",
|
|
||||||
Usage: "value set for the evm",
|
|
||||||
Value: "0",
|
|
||||||
}
|
|
||||||
DumpFlag = cli.BoolFlag{
|
|
||||||
Name: "dump",
|
|
||||||
Usage: "dumps the state after the run",
|
|
||||||
}
|
|
||||||
InputFlag = cli.StringFlag{
|
|
||||||
Name: "input",
|
|
||||||
Usage: "input for the EVM",
|
|
||||||
}
|
|
||||||
SysStatFlag = cli.BoolFlag{
|
|
||||||
Name: "sysstat",
|
|
||||||
Usage: "display system stats",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func perr(v ...interface{}) {
|
||||||
app = utils.NewApp("0.2", "the evm command line interface")
|
fmt.Println(v...)
|
||||||
app.Flags = []cli.Flag{
|
//os.Exit(1)
|
||||||
DebugFlag,
|
|
||||||
SysStatFlag,
|
|
||||||
CodeFlag,
|
|
||||||
GasFlag,
|
|
||||||
PriceFlag,
|
|
||||||
ValueFlag,
|
|
||||||
DumpFlag,
|
|
||||||
InputFlag,
|
|
||||||
}
|
|
||||||
app.Action = run
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(ctx *cli.Context) {
|
func main() {
|
||||||
vm.Debug = ctx.GlobalBool(DebugFlag.Name)
|
flag.Parse()
|
||||||
|
|
||||||
|
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel)))
|
||||||
|
|
||||||
|
vm.Debug = true
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb := state.New(common.Hash{}, db)
|
statedb := state.New(common.Hash{}, db)
|
||||||
sender := statedb.CreateAccount(common.StringToAddress("sender"))
|
sender := statedb.CreateAccount(common.StringToAddress("sender"))
|
||||||
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
||||||
receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)))
|
receiver.SetCode(common.Hex2Bytes(*code))
|
||||||
|
|
||||||
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)))
|
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value))
|
||||||
|
|
||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
ret, e := vmenv.Call(
|
|
||||||
sender,
|
|
||||||
receiver.Address(),
|
|
||||||
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)),
|
|
||||||
common.Big(ctx.GlobalString(GasFlag.Name)),
|
|
||||||
common.Big(ctx.GlobalString(PriceFlag.Name)),
|
|
||||||
common.Big(ctx.GlobalString(ValueFlag.Name)),
|
|
||||||
)
|
|
||||||
vmdone := time.Since(tstart)
|
|
||||||
|
|
||||||
|
ret, e := vmenv.Call(sender, receiver.Address(), common.Hex2Bytes(*data), common.Big(*gas), common.Big(*price), common.Big(*value))
|
||||||
|
|
||||||
|
logger.Flush()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
fmt.Println(e)
|
perr(e)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.GlobalBool(DumpFlag.Name) {
|
if *dump {
|
||||||
fmt.Println(string(statedb.Dump()))
|
fmt.Println(string(statedb.Dump()))
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.StdErrFormat(vmenv.StructLogs())
|
vm.StdErrFormat(vmenv.StructLogs())
|
||||||
|
|
||||||
if ctx.GlobalBool(SysStatFlag.Name) {
|
var mem runtime.MemStats
|
||||||
var mem runtime.MemStats
|
runtime.ReadMemStats(&mem)
|
||||||
runtime.ReadMemStats(&mem)
|
fmt.Printf("vm took %v\n", time.Since(tstart))
|
||||||
fmt.Printf("vm took %v\n", vmdone)
|
fmt.Printf(`alloc: %d
|
||||||
fmt.Printf(`alloc: %d
|
|
||||||
tot alloc: %d
|
tot alloc: %d
|
||||||
no. malloc: %d
|
no. malloc: %d
|
||||||
heap alloc: %d
|
heap alloc: %d
|
||||||
heap objs: %d
|
heap objs: %d
|
||||||
num gc: %d
|
num gc: %d
|
||||||
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
|
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("OUT: 0x%x\n", ret)
|
fmt.Printf("%x\n", ret)
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type VMEnv struct {
|
type VMEnv struct {
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"sort"
|
"sort"
|
||||||
@ -45,10 +44,6 @@ import (
|
|||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var passwordRegexp = regexp.MustCompile("personal.[nu]")
|
|
||||||
|
|
||||||
const passwordRepl = ""
|
|
||||||
|
|
||||||
type prompter interface {
|
type prompter interface {
|
||||||
AppendHistory(string)
|
AppendHistory(string)
|
||||||
Prompt(p string) (string, error)
|
Prompt(p string) (string, error)
|
||||||
@ -418,10 +413,8 @@ func (self *jsre) interactive() {
|
|||||||
str += input + "\n"
|
str += input + "\n"
|
||||||
self.setIndent()
|
self.setIndent()
|
||||||
if indentCount <= 0 {
|
if indentCount <= 0 {
|
||||||
hist := hidepassword(str[:len(str)-1])
|
hist := str[:len(str)-1]
|
||||||
if len(hist) > 0 {
|
self.AppendHistory(hist)
|
||||||
self.AppendHistory(hist)
|
|
||||||
}
|
|
||||||
self.parseInput(str)
|
self.parseInput(str)
|
||||||
str = ""
|
str = ""
|
||||||
}
|
}
|
||||||
@ -429,14 +422,6 @@ func (self *jsre) interactive() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hidepassword(input string) string {
|
|
||||||
if passwordRegexp.MatchString(input) {
|
|
||||||
return passwordRepl
|
|
||||||
} else {
|
|
||||||
return input
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *jsre) withHistory(op func(*os.File)) {
|
func (self *jsre) withHistory(op func(*os.File)) {
|
||||||
datadir := common.DefaultDataDir()
|
datadir := common.DefaultDataDir()
|
||||||
if self.ethereum != nil {
|
if self.ethereum != nil {
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
@ -50,11 +49,11 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "Geth"
|
ClientIdentifier = "Geth"
|
||||||
Version = "1.0.2"
|
Version = "1.0.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gitCommit string // set via linker flagg
|
gitCommit string // set via linker flag
|
||||||
nodeNameVersion string
|
nodeNameVersion string
|
||||||
app *cli.App
|
app *cli.App
|
||||||
)
|
)
|
||||||
@ -281,8 +280,6 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
|||||||
utils.BootnodesFlag,
|
utils.BootnodesFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.BlockchainVersionFlag,
|
utils.BlockchainVersionFlag,
|
||||||
utils.OlympicFlag,
|
|
||||||
utils.CacheFlag,
|
|
||||||
utils.JSpathFlag,
|
utils.JSpathFlag,
|
||||||
utils.ListenPortFlag,
|
utils.ListenPortFlag,
|
||||||
utils.MaxPeersFlag,
|
utils.MaxPeersFlag,
|
||||||
@ -348,9 +345,6 @@ func main() {
|
|||||||
|
|
||||||
func run(ctx *cli.Context) {
|
func run(ctx *cli.Context) {
|
||||||
utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name))
|
utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name))
|
||||||
if ctx.GlobalBool(utils.OlympicFlag.Name) {
|
|
||||||
utils.InitOlympic()
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
||||||
ethereum, err := eth.New(cfg)
|
ethereum, err := eth.New(cfg)
|
||||||
@ -506,7 +500,7 @@ func blockRecovery(ctx *cli.Context) {
|
|||||||
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
||||||
utils.CheckLegalese(cfg.DataDir)
|
utils.CheckLegalese(cfg.DataDir)
|
||||||
|
|
||||||
blockDb, err := ethdb.NewLDBDatabase(filepath.Join(cfg.DataDir, "blockchain"), cfg.DatabaseCache)
|
blockDb, err := ethdb.NewLDBDatabase(filepath.Join(cfg.DataDir, "blockchain"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalln("could not open db:", err)
|
glog.Fatalln("could not open db:", err)
|
||||||
}
|
}
|
||||||
@ -533,9 +527,6 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
|||||||
// Start Ethereum itself
|
// Start Ethereum itself
|
||||||
utils.StartEthereum(eth)
|
utils.StartEthereum(eth)
|
||||||
|
|
||||||
// Start logging file descriptor stats.
|
|
||||||
fdtrack.Start()
|
|
||||||
|
|
||||||
am := eth.AccountManager()
|
am := eth.AccountManager()
|
||||||
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
||||||
accounts := strings.Split(account, " ")
|
accounts := strings.Split(account, " ")
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -33,7 +32,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/peterh/liner"
|
"github.com/peterh/liner"
|
||||||
)
|
)
|
||||||
@ -145,15 +143,6 @@ func StartEthereum(ethereum *eth.Ethereum) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitOlympic() {
|
|
||||||
params.DurationLimit = big.NewInt(8)
|
|
||||||
params.GenesisGasLimit = big.NewInt(3141592)
|
|
||||||
params.MinGasLimit = big.NewInt(125000)
|
|
||||||
params.MaximumExtraDataSize = big.NewInt(1024)
|
|
||||||
NetworkIdFlag.Value = 0
|
|
||||||
core.BlockReward = big.NewInt(1.5e+18)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatTransactionData(data string) []byte {
|
func FormatTransactionData(data string) []byte {
|
||||||
d := common.StringToByteFunc(data, func(s string) (ret []byte) {
|
d := common.StringToByteFunc(data, func(s string) (ret []byte) {
|
||||||
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
|
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
|
||||||
@ -214,11 +203,6 @@ func ImportChain(chain *core.ChainManager, fn string) error {
|
|||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return fmt.Errorf("at block %d: %v", n, err)
|
return fmt.Errorf("at block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
// don't import first block
|
|
||||||
if b.NumberU64() == 0 {
|
|
||||||
i--
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
blocks[i] = &b
|
blocks[i] = &b
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
@ -234,7 +218,6 @@ func ImportChain(chain *core.ChainManager, fn string) error {
|
|||||||
batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4])
|
batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[:i]); err != nil {
|
if _, err := chain.InsertChain(blocks[:i]); err != nil {
|
||||||
return fmt.Errorf("invalid block %d: %v", n, err)
|
return fmt.Errorf("invalid block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
@ -126,15 +126,6 @@ var (
|
|||||||
Name: "natspec",
|
Name: "natspec",
|
||||||
Usage: "Enable NatSpec confirmation notice",
|
Usage: "Enable NatSpec confirmation notice",
|
||||||
}
|
}
|
||||||
CacheFlag = cli.IntFlag{
|
|
||||||
Name: "cache",
|
|
||||||
Usage: "Megabytes of memory allocated to internal caching",
|
|
||||||
Value: 0,
|
|
||||||
}
|
|
||||||
OlympicFlag = cli.BoolFlag{
|
|
||||||
Name: "olympic",
|
|
||||||
Usage: "Use olympic style protocol",
|
|
||||||
}
|
|
||||||
|
|
||||||
// miner settings
|
// miner settings
|
||||||
MinerThreadsFlag = cli.IntFlag{
|
MinerThreadsFlag = cli.IntFlag{
|
||||||
@ -158,7 +149,7 @@ var (
|
|||||||
GasPriceFlag = cli.StringFlag{
|
GasPriceFlag = cli.StringFlag{
|
||||||
Name: "gasprice",
|
Name: "gasprice",
|
||||||
Usage: "Sets the minimal gasprice when mining transactions",
|
Usage: "Sets the minimal gasprice when mining transactions",
|
||||||
Value: new(big.Int).Mul(big.NewInt(50), common.Shannon).String(),
|
Value: new(big.Int).Mul(big.NewInt(500), common.Shannon).String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
UnlockedAccountFlag = cli.StringFlag{
|
UnlockedAccountFlag = cli.StringFlag{
|
||||||
@ -318,12 +309,12 @@ var (
|
|||||||
GpoMinGasPriceFlag = cli.StringFlag{
|
GpoMinGasPriceFlag = cli.StringFlag{
|
||||||
Name: "gpomin",
|
Name: "gpomin",
|
||||||
Usage: "Minimum suggested gas price",
|
Usage: "Minimum suggested gas price",
|
||||||
Value: new(big.Int).Mul(big.NewInt(50), common.Shannon).String(),
|
Value: new(big.Int).Mul(big.NewInt(1), common.Szabo).String(),
|
||||||
}
|
}
|
||||||
GpoMaxGasPriceFlag = cli.StringFlag{
|
GpoMaxGasPriceFlag = cli.StringFlag{
|
||||||
Name: "gpomax",
|
Name: "gpomax",
|
||||||
Usage: "Maximum suggested gas price",
|
Usage: "Maximum suggested gas price",
|
||||||
Value: new(big.Int).Mul(big.NewInt(500), common.Shannon).String(),
|
Value: new(big.Int).Mul(big.NewInt(100), common.Szabo).String(),
|
||||||
}
|
}
|
||||||
GpoFullBlockRatioFlag = cli.IntFlag{
|
GpoFullBlockRatioFlag = cli.IntFlag{
|
||||||
Name: "gpofull",
|
Name: "gpofull",
|
||||||
@ -393,7 +384,6 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
|||||||
GenesisNonce: ctx.GlobalInt(GenesisNonceFlag.Name),
|
GenesisNonce: ctx.GlobalInt(GenesisNonceFlag.Name),
|
||||||
GenesisFile: ctx.GlobalString(GenesisFileFlag.Name),
|
GenesisFile: ctx.GlobalString(GenesisFileFlag.Name),
|
||||||
BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name),
|
BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name),
|
||||||
DatabaseCache: ctx.GlobalInt(CacheFlag.Name),
|
|
||||||
SkipBcVersionCheck: false,
|
SkipBcVersionCheck: false,
|
||||||
NetworkId: ctx.GlobalInt(NetworkIdFlag.Name),
|
NetworkId: ctx.GlobalInt(NetworkIdFlag.Name),
|
||||||
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
||||||
@ -406,7 +396,6 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
|||||||
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
||||||
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
||||||
Port: ctx.GlobalString(ListenPortFlag.Name),
|
Port: ctx.GlobalString(ListenPortFlag.Name),
|
||||||
Olympic: ctx.GlobalBool(OlympicFlag.Name),
|
|
||||||
NAT: MakeNAT(ctx),
|
NAT: MakeNAT(ctx),
|
||||||
NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name),
|
NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name),
|
||||||
Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name),
|
Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name),
|
||||||
@ -436,26 +425,17 @@ func SetupLogger(ctx *cli.Context) {
|
|||||||
|
|
||||||
// MakeChain creates a chain manager from set command line flags.
|
// MakeChain creates a chain manager from set command line flags.
|
||||||
func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, extraDB common.Database) {
|
func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, extraDB common.Database) {
|
||||||
datadir := ctx.GlobalString(DataDirFlag.Name)
|
dd := ctx.GlobalString(DataDirFlag.Name)
|
||||||
cache := ctx.GlobalInt(CacheFlag.Name)
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if blockDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "blockchain"), cache); err != nil {
|
if blockDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "blockchain")); err != nil {
|
||||||
Fatalf("Could not open database: %v", err)
|
Fatalf("Could not open database: %v", err)
|
||||||
}
|
}
|
||||||
if stateDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "state"), cache); err != nil {
|
if stateDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "state")); err != nil {
|
||||||
Fatalf("Could not open database: %v", err)
|
Fatalf("Could not open database: %v", err)
|
||||||
}
|
}
|
||||||
if extraDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "extra"), cache); err != nil {
|
if extraDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "extra")); err != nil {
|
||||||
Fatalf("Could not open database: %v", err)
|
Fatalf("Could not open database: %v", err)
|
||||||
}
|
}
|
||||||
if ctx.GlobalBool(OlympicFlag.Name) {
|
|
||||||
InitOlympic()
|
|
||||||
_, err := core.WriteTestNetGenesisBlock(stateDB, blockDB, 42)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eventMux := new(event.TypeMux)
|
eventMux := new(event.TypeMux)
|
||||||
pow := ethash.New()
|
pow := ethash.New()
|
||||||
|
@ -153,7 +153,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
|||||||
b.Fatalf("cannot create temporary directory: %v", err)
|
b.Fatalf("cannot create temporary directory: %v", err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
db, err = ethdb.NewLDBDatabase(dir, 0)
|
db, err = ethdb.NewLDBDatabase(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("cannot create temporary database: %v", err)
|
b.Fatalf("cannot create temporary database: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -386,7 +386,7 @@ func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, check
|
|||||||
return BlockEqualTSErr
|
return BlockEqualTSErr
|
||||||
}
|
}
|
||||||
|
|
||||||
expd := CalcDifficulty(block.Time, parent.Time(), parent.Number(), parent.Difficulty())
|
expd := CalcDifficulty(block.Time, parent.Time(), parent.Difficulty())
|
||||||
if expd.Cmp(block.Difficulty) != 0 {
|
if expd.Cmp(block.Difficulty) != 0 {
|
||||||
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
|
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,8 @@ import "github.com/ethereum/go-ethereum/common"
|
|||||||
|
|
||||||
// Set of manually tracked bad hashes (usually hard forks)
|
// Set of manually tracked bad hashes (usually hard forks)
|
||||||
var BadHashes = map[common.Hash]bool{
|
var BadHashes = map[common.Hash]bool{
|
||||||
common.HexToHash("05bef30ef572270f654746da22639a7a0c97dd97a7050b9e252391996aaeb689"): true,
|
common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"): true,
|
||||||
|
common.HexToHash("38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc"): true,
|
||||||
|
common.HexToHash("7064455b364775a16afbdecd75370e912c6e2879f202eda85b9beae547fff3ac"): true,
|
||||||
|
common.HexToHash("5b7c80070a6eff35f3eb3181edb023465c776d40af2885571e1bc4689f3a44d8"): true,
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
jeff = common.HexToAddress("959c33de5961820567930eccce51ea715c496f85")
|
jeff = common.HexToAddress("a8edb1ac2c86d3d9d78f96cd18001f60df29e52c")
|
||||||
vitalik = common.HexToAddress("c8158da0b567a8cc898991c2c2a073af67dc03a9")
|
vitalik = common.HexToAddress("1baf27b88c48dd02b744999cf3522766929d2b2a")
|
||||||
christoph = common.HexToAddress("7a19a893f91d5b6e2cdf941b6acbba2cbcf431ee")
|
christoph = common.HexToAddress("60d11b58744784dc97f878f7e3749c0f1381a004")
|
||||||
gav = common.HexToAddress("539dd9aaf45c3feb03f9c004f4098bd3268fef6b")
|
gav = common.HexToAddress("4bb7e8ae99b645c2b7860b8f3a2328aae28bd80a")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Canary will check the 0'd address of the 4 contracts above.
|
// Canary will check the 0'd address of the 4 contracts above.
|
||||||
|
@ -171,7 +171,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
|
|||||||
Root: state.Root(),
|
Root: state.Root(),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
Difficulty: CalcDifficulty(time, parent.Time(), parent.Number(), parent.Difficulty()),
|
Difficulty: CalcDifficulty(time, parent.Time(), parent.Difficulty()),
|
||||||
GasLimit: CalcGasLimit(parent),
|
GasLimit: CalcGasLimit(parent),
|
||||||
GasUsed: new(big.Int),
|
GasUsed: new(big.Int),
|
||||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||||
|
@ -73,11 +73,13 @@ type ChainManager struct {
|
|||||||
lastBlockHash common.Hash
|
lastBlockHash common.Hash
|
||||||
currentGasLimit *big.Int
|
currentGasLimit *big.Int
|
||||||
|
|
||||||
|
transState *state.StateDB
|
||||||
|
txState *state.ManagedState
|
||||||
|
|
||||||
cache *lru.Cache // cache is the LRU caching
|
cache *lru.Cache // cache is the LRU caching
|
||||||
futureBlocks *lru.Cache // future blocks are blocks added for later processing
|
futureBlocks *lru.Cache // future blocks are blocks added for later processing
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
running int32 // running must be called automically
|
|
||||||
// procInterrupt must be atomically called
|
// procInterrupt must be atomically called
|
||||||
procInterrupt int32 // interrupt signaler for block processing
|
procInterrupt int32 // interrupt signaler for block processing
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
@ -99,15 +101,7 @@ func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux
|
|||||||
|
|
||||||
bc.genesisBlock = bc.GetBlockByNumber(0)
|
bc.genesisBlock = bc.GetBlockByNumber(0)
|
||||||
if bc.genesisBlock == nil {
|
if bc.genesisBlock == nil {
|
||||||
reader, err := NewDefaultGenesisReader()
|
return nil, ErrNoGenesis
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
bc.genesisBlock, err = WriteGenesisBlock(stateDb, blockDb, reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infoln("WARNING: Wrote default ethereum genesis block")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bc.setLastState(); err != nil {
|
if err := bc.setLastState(); err != nil {
|
||||||
@ -128,7 +122,9 @@ func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bc.transState = bc.State().Copy()
|
||||||
// Take ownership of this particular state
|
// Take ownership of this particular state
|
||||||
|
bc.txState = state.ManageState(bc.State().Copy())
|
||||||
|
|
||||||
bc.futureBlocks, _ = lru.New(maxFutureBlocks)
|
bc.futureBlocks, _ = lru.New(maxFutureBlocks)
|
||||||
bc.makeCache()
|
bc.makeCache()
|
||||||
@ -150,6 +146,9 @@ func (bc *ChainManager) SetHead(head *types.Block) {
|
|||||||
bc.currentBlock = head
|
bc.currentBlock = head
|
||||||
bc.makeCache()
|
bc.makeCache()
|
||||||
|
|
||||||
|
statedb := state.New(head.Root(), bc.stateDb)
|
||||||
|
bc.txState = state.ManageState(statedb)
|
||||||
|
bc.transState = statedb.Copy()
|
||||||
bc.setTotalDifficulty(head.Td)
|
bc.setTotalDifficulty(head.Td)
|
||||||
bc.insert(head)
|
bc.insert(head)
|
||||||
bc.setLastState()
|
bc.setLastState()
|
||||||
@ -198,6 +197,17 @@ func (self *ChainManager) State() *state.StateDB {
|
|||||||
return state.New(self.CurrentBlock().Root(), self.stateDb)
|
return state.New(self.CurrentBlock().Root(), self.stateDb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ChainManager) TransState() *state.StateDB {
|
||||||
|
self.tsmu.RLock()
|
||||||
|
defer self.tsmu.RUnlock()
|
||||||
|
|
||||||
|
return self.transState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ChainManager) setTransState(statedb *state.StateDB) {
|
||||||
|
self.transState = statedb
|
||||||
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) recover() bool {
|
func (bc *ChainManager) recover() bool {
|
||||||
data, _ := bc.blockDb.Get([]byte("checkpoint"))
|
data, _ := bc.blockDb.Get([]byte("checkpoint"))
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
@ -452,9 +462,6 @@ func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) Stop() {
|
func (bc *ChainManager) Stop() {
|
||||||
if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
close(bc.quit)
|
close(bc.quit)
|
||||||
atomic.StoreInt32(&bc.procInterrupt, 1)
|
atomic.StoreInt32(&bc.procInterrupt, 1)
|
||||||
|
|
||||||
@ -516,6 +523,9 @@ func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status wr
|
|||||||
self.insert(block)
|
self.insert(block)
|
||||||
self.mu.Unlock()
|
self.mu.Unlock()
|
||||||
|
|
||||||
|
self.setTransState(state.New(block.Root(), self.stateDb))
|
||||||
|
self.txState.SetState(state.New(block.Root(), self.stateDb))
|
||||||
|
|
||||||
status = CanonStatTy
|
status = CanonStatTy
|
||||||
} else {
|
} else {
|
||||||
status = SideStatTy
|
status = SideStatTy
|
||||||
|
@ -392,6 +392,7 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
|
|||||||
bc.futureBlocks, _ = lru.New(100)
|
bc.futureBlocks, _ = lru.New(100)
|
||||||
bc.processor = bproc{}
|
bc.processor = bproc{}
|
||||||
bc.ResetWithGenesisBlock(genesis)
|
bc.ResetWithGenesisBlock(genesis)
|
||||||
|
bc.txState = state.ManageState(bc.State())
|
||||||
|
|
||||||
return bc
|
return bc
|
||||||
}
|
}
|
||||||
|
@ -30,15 +30,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
blockHashPre = []byte("block-hash-")
|
blockHashPre = []byte("block-hash-")
|
||||||
blockNumPre = []byte("block-num-")
|
blockNumPre = []byte("block-num-")
|
||||||
expDiffPeriod = big.NewInt(100000)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
||||||
// the difficulty that a new block b should have when created at time
|
// the difficulty that a new block b should have when created at time
|
||||||
// given the parent block's time and difficulty.
|
// given the parent block's time and difficulty.
|
||||||
func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
|
func CalcDifficulty(time, parentTime uint64, parentDiff *big.Int) *big.Int {
|
||||||
diff := new(big.Int)
|
diff := new(big.Int)
|
||||||
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
|
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
|
||||||
bigTime := new(big.Int)
|
bigTime := new(big.Int)
|
||||||
@ -53,19 +52,8 @@ func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int)
|
|||||||
diff.Sub(parentDiff, adjust)
|
diff.Sub(parentDiff, adjust)
|
||||||
}
|
}
|
||||||
if diff.Cmp(params.MinimumDifficulty) < 0 {
|
if diff.Cmp(params.MinimumDifficulty) < 0 {
|
||||||
diff = params.MinimumDifficulty
|
return params.MinimumDifficulty
|
||||||
}
|
}
|
||||||
|
|
||||||
periodCount := new(big.Int).Add(parentNumber, common.Big1)
|
|
||||||
periodCount.Div(periodCount, expDiffPeriod)
|
|
||||||
if periodCount.Cmp(common.Big1) > 0 {
|
|
||||||
// diff = diff + 2^(periodCount - 2)
|
|
||||||
expDiff := periodCount.Sub(periodCount, common.Big2)
|
|
||||||
expDiff.Exp(common.Big2, expDiff, nil)
|
|
||||||
diff.Add(diff, expDiff)
|
|
||||||
diff = common.BigMax(diff, params.MinimumDifficulty)
|
|
||||||
}
|
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,30 +69,17 @@ func CalcTD(block, parent *types.Block) *big.Int {
|
|||||||
|
|
||||||
// CalcGasLimit computes the gas limit of the next block after parent.
|
// CalcGasLimit computes the gas limit of the next block after parent.
|
||||||
// The result may be modified by the caller.
|
// The result may be modified by the caller.
|
||||||
// This is miner strategy, not consensus protocol.
|
|
||||||
func CalcGasLimit(parent *types.Block) *big.Int {
|
func CalcGasLimit(parent *types.Block) *big.Int {
|
||||||
// contrib = (parentGasUsed * 3 / 2) / 1024
|
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
|
||||||
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
|
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
|
||||||
contrib = contrib.Div(contrib, big.NewInt(2))
|
contrib = contrib.Div(contrib, big.NewInt(2))
|
||||||
contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
|
contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
|
||||||
|
|
||||||
// decay = parentGasLimit / 1024 -1
|
|
||||||
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
|
|
||||||
decay.Sub(decay, big.NewInt(1))
|
|
||||||
|
|
||||||
/*
|
|
||||||
strategy: gasLimit of block-to-mine is set based on parent's
|
|
||||||
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
|
|
||||||
increase it, otherwise lower it (or leave it unchanged if it's right
|
|
||||||
at that usage) the amount increased/decreased depends on how far away
|
|
||||||
from parentGasLimit * (2/3) parentGasUsed is.
|
|
||||||
*/
|
|
||||||
gl := new(big.Int).Sub(parent.GasLimit(), decay)
|
gl := new(big.Int).Sub(parent.GasLimit(), decay)
|
||||||
gl = gl.Add(gl, contrib)
|
gl = gl.Add(gl, contrib)
|
||||||
|
gl = gl.Add(gl, big.NewInt(1))
|
||||||
gl.Set(common.BigMax(gl, params.MinGasLimit))
|
gl.Set(common.BigMax(gl, params.MinGasLimit))
|
||||||
|
|
||||||
// however, if we're now below the target (GenesisGasLimit) we increase the
|
|
||||||
// limit as much as we can (parentGasLimit / 1024 -1)
|
|
||||||
if gl.Cmp(params.GenesisGasLimit) < 0 {
|
if gl.Cmp(params.GenesisGasLimit) < 0 {
|
||||||
gl.Add(parent.GasLimit(), decay)
|
gl.Add(parent.GasLimit(), decay)
|
||||||
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
|
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"math/big"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type diffTest struct {
|
|
||||||
ParentTimestamp uint64
|
|
||||||
ParentDifficulty *big.Int
|
|
||||||
CurrentTimestamp uint64
|
|
||||||
CurrentBlocknumber *big.Int
|
|
||||||
CurrentDifficulty *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
|
|
||||||
var ext struct {
|
|
||||||
ParentTimestamp string
|
|
||||||
ParentDifficulty string
|
|
||||||
CurrentTimestamp string
|
|
||||||
CurrentBlocknumber string
|
|
||||||
CurrentDifficulty string
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(b, &ext); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.ParentTimestamp = common.String2Big(ext.ParentTimestamp).Uint64()
|
|
||||||
d.ParentDifficulty = common.String2Big(ext.ParentDifficulty)
|
|
||||||
d.CurrentTimestamp = common.String2Big(ext.CurrentTimestamp).Uint64()
|
|
||||||
d.CurrentBlocknumber = common.String2Big(ext.CurrentBlocknumber)
|
|
||||||
d.CurrentDifficulty = common.String2Big(ext.CurrentDifficulty)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDifficulty(t *testing.T) {
|
|
||||||
file, err := os.Open("../tests/files/BasicTests/difficulty.json")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
tests := make(map[string]diffTest)
|
|
||||||
err = json.NewDecoder(file).Decode(&tests)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, test := range tests {
|
|
||||||
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
|
||||||
diff := CalcDifficulty(test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
|
|
||||||
if diff.Cmp(test.CurrentDifficulty) != 0 {
|
|
||||||
t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
@ -82,9 +82,8 @@ type StateObject struct {
|
|||||||
// Mark for deletion
|
// Mark for deletion
|
||||||
// When an object is marked for deletion it will be delete from the trie
|
// When an object is marked for deletion it will be delete from the trie
|
||||||
// during the "update" phase of the state transition
|
// during the "update" phase of the state transition
|
||||||
remove bool
|
remove bool
|
||||||
deleted bool
|
dirty bool
|
||||||
dirty bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) Reset() {
|
func (self *StateObject) Reset() {
|
||||||
|
@ -44,7 +44,6 @@ type StateDB struct {
|
|||||||
thash, bhash common.Hash
|
thash, bhash common.Hash
|
||||||
txIndex int
|
txIndex int
|
||||||
logs map[common.Hash]Logs
|
logs map[common.Hash]Logs
|
||||||
logSize uint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new state from a given trie
|
// Create a new state from a given trie
|
||||||
@ -67,9 +66,7 @@ func (self *StateDB) AddLog(log *Log) {
|
|||||||
log.TxHash = self.thash
|
log.TxHash = self.thash
|
||||||
log.BlockHash = self.bhash
|
log.BlockHash = self.bhash
|
||||||
log.TxIndex = uint(self.txIndex)
|
log.TxIndex = uint(self.txIndex)
|
||||||
log.Index = self.logSize
|
|
||||||
self.logs[self.thash] = append(self.logs[self.thash], log)
|
self.logs[self.thash] = append(self.logs[self.thash], log)
|
||||||
self.logSize++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetLogs(hash common.Hash) Logs {
|
func (self *StateDB) GetLogs(hash common.Hash) Logs {
|
||||||
@ -203,20 +200,18 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
|
|||||||
|
|
||||||
// Delete the given state object and delete it from the state trie
|
// Delete the given state object and delete it from the state trie
|
||||||
func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
|
func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
|
||||||
stateObject.deleted = true
|
|
||||||
|
|
||||||
addr := stateObject.Address()
|
addr := stateObject.Address()
|
||||||
self.trie.Delete(addr[:])
|
self.trie.Delete(addr[:])
|
||||||
|
|
||||||
|
//delete(self.stateObjects, addr.Str())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object given my the address. Nil if not found
|
// Retrieve a state object given my the address. Nil if not found
|
||||||
func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) {
|
func (self *StateDB) GetStateObject(addr common.Address) *StateObject {
|
||||||
stateObject = self.stateObjects[addr.Str()]
|
//addr = common.Address(addr)
|
||||||
if stateObject != nil {
|
|
||||||
if stateObject.deleted {
|
|
||||||
stateObject = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
stateObject := self.stateObjects[addr.Str()]
|
||||||
|
if stateObject != nil {
|
||||||
return stateObject
|
return stateObject
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +233,7 @@ func (self *StateDB) SetStateObject(object *StateObject) {
|
|||||||
// Retrieve a state object or create a new state object if nil
|
// Retrieve a state object or create a new state object if nil
|
||||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.GetStateObject(addr)
|
||||||
if stateObject == nil || stateObject.deleted {
|
if stateObject == nil {
|
||||||
stateObject = self.CreateAccount(addr)
|
stateObject = self.CreateAccount(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +288,6 @@ func (self *StateDB) Copy() *StateDB {
|
|||||||
state.logs[hash] = make(Logs, len(logs))
|
state.logs[hash] = make(Logs, len(logs))
|
||||||
copy(state.logs[hash], logs)
|
copy(state.logs[hash], logs)
|
||||||
}
|
}
|
||||||
state.logSize = self.logSize
|
|
||||||
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@ -304,7 +298,6 @@ func (self *StateDB) Set(state *StateDB) {
|
|||||||
|
|
||||||
self.refund = state.refund
|
self.refund = state.refund
|
||||||
self.logs = state.logs
|
self.logs = state.logs
|
||||||
self.logSize = state.logSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) Root() common.Hash {
|
func (s *StateDB) Root() common.Hash {
|
||||||
|
@ -135,7 +135,7 @@ func (pool *TxPool) resetState() {
|
|||||||
func (pool *TxPool) Stop() {
|
func (pool *TxPool) Stop() {
|
||||||
close(pool.quit)
|
close(pool.quit)
|
||||||
pool.events.Unsubscribe()
|
pool.events.Unsubscribe()
|
||||||
glog.V(logger.Info).Infoln("Transaction pool stopped")
|
glog.V(logger.Info).Infoln("TX Pool stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) State() *state.ManagedState {
|
func (pool *TxPool) State() *state.ManagedState {
|
||||||
@ -356,12 +356,11 @@ func (self *TxPool) RemoveTransactions(txs types.Transactions) {
|
|||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer self.mu.Unlock()
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
self.RemoveTx(tx.Hash())
|
self.removeTx(tx.Hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTx removes the transaction with the given hash from the pool.
|
func (pool *TxPool) removeTx(hash common.Hash) {
|
||||||
func (pool *TxPool) RemoveTx(hash common.Hash) {
|
|
||||||
// delete from pending pool
|
// delete from pending pool
|
||||||
delete(pool.pending, hash)
|
delete(pool.pending, hash)
|
||||||
// delete from queue
|
// delete from queue
|
||||||
|
@ -130,7 +130,7 @@ func TestRemoveTx(t *testing.T) {
|
|||||||
t.Error("expected txs to be 1, got", len(pool.pending))
|
t.Error("expected txs to be 1, got", len(pool.pending))
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.RemoveTx(tx.Hash())
|
pool.removeTx(tx.Hash())
|
||||||
|
|
||||||
if len(pool.queue) > 0 {
|
if len(pool.queue) > 0 {
|
||||||
t.Error("expected queue to be 0, got", len(pool.queue))
|
t.Error("expected queue to be 0, got", len(pool.queue))
|
||||||
|
@ -19,11 +19,9 @@ package core
|
|||||||
import (
|
import (
|
||||||
"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/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -33,21 +31,13 @@ var (
|
|||||||
|
|
||||||
// PutTransactions stores the transactions in the given database
|
// PutTransactions stores the transactions in the given database
|
||||||
func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) {
|
func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) {
|
||||||
batch := new(leveldb.Batch)
|
|
||||||
_, batchWrite := db.(*ethdb.LDBDatabase)
|
|
||||||
|
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
rlpEnc, err := rlp.EncodeToBytes(tx)
|
rlpEnc, err := rlp.EncodeToBytes(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Debug).Infoln("Failed encoding tx", err)
|
glog.V(logger.Debug).Infoln("Failed encoding tx", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
db.Put(tx.Hash().Bytes(), rlpEnc)
|
||||||
if batchWrite {
|
|
||||||
batch.Put(tx.Hash().Bytes(), rlpEnc)
|
|
||||||
} else {
|
|
||||||
db.Put(tx.Hash().Bytes(), rlpEnc)
|
|
||||||
}
|
|
||||||
|
|
||||||
var txExtra struct {
|
var txExtra struct {
|
||||||
BlockHash common.Hash
|
BlockHash common.Hash
|
||||||
@ -62,44 +52,20 @@ func PutTransactions(db common.Database, block *types.Block, txs types.Transacti
|
|||||||
glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err)
|
glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
|
||||||
if batchWrite {
|
|
||||||
batch.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
|
|
||||||
} else {
|
|
||||||
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if db, ok := db.(*ethdb.LDBDatabase); ok {
|
|
||||||
if err := db.LDB().Write(batch, nil); err != nil {
|
|
||||||
glog.V(logger.Error).Infoln("db write err:", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutReceipts stores the receipts in the current database
|
// PutReceipts stores the receipts in the current database
|
||||||
func PutReceipts(db common.Database, receipts types.Receipts) error {
|
func PutReceipts(db common.Database, receipts types.Receipts) error {
|
||||||
batch := new(leveldb.Batch)
|
|
||||||
_, batchWrite := db.(*ethdb.LDBDatabase)
|
|
||||||
|
|
||||||
for _, receipt := range receipts {
|
for _, receipt := range receipts {
|
||||||
storageReceipt := (*types.ReceiptForStorage)(receipt)
|
storageReceipt := (*types.ReceiptForStorage)(receipt)
|
||||||
bytes, err := rlp.EncodeToBytes(storageReceipt)
|
bytes, err := rlp.EncodeToBytes(storageReceipt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
|
||||||
if batchWrite {
|
if err != nil {
|
||||||
batch.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
|
|
||||||
} else {
|
|
||||||
err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if db, ok := db.(*ethdb.LDBDatabase); ok {
|
|
||||||
if err := db.LDB().Write(batch, nil); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) EncodeRLP(w io.Writer) error {
|
func (b Block) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, extblock{
|
return rlp.Encode(w, extblock{
|
||||||
Header: b.header,
|
Header: b.header,
|
||||||
Txs: b.transactions,
|
Txs: b.transactions,
|
||||||
@ -274,7 +274,7 @@ func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *StorageBlock) EncodeRLP(w io.Writer) error {
|
func (b StorageBlock) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, storageblock{
|
return rlp.Encode(w, storageblock{
|
||||||
Header: b.header,
|
Header: b.header,
|
||||||
Txs: b.transactions,
|
Txs: b.transactions,
|
||||||
|
@ -97,6 +97,15 @@ func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice
|
|||||||
return &Transaction{data: d}
|
return &Transaction{data: d}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTransactionFromBytes(data []byte) *Transaction {
|
||||||
|
// TODO: remove this function if possible. callers would
|
||||||
|
// much better off decoding into transaction directly.
|
||||||
|
// it's not that hard.
|
||||||
|
tx := new(Transaction)
|
||||||
|
rlp.DecodeBytes(data, tx)
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, &tx.data)
|
return rlp.Encode(w, &tx.data)
|
||||||
}
|
}
|
||||||
@ -289,22 +298,3 @@ type TxByNonce struct{ Transactions }
|
|||||||
func (s TxByNonce) Less(i, j int) bool {
|
func (s TxByNonce) Less(i, j int) bool {
|
||||||
return s.Transactions[i].data.AccountNonce < s.Transactions[j].data.AccountNonce
|
return s.Transactions[i].data.AccountNonce < s.Transactions[j].data.AccountNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
type TxByPrice struct{ Transactions }
|
|
||||||
|
|
||||||
func (s TxByPrice) Less(i, j int) bool {
|
|
||||||
return s.Transactions[i].data.Price.Cmp(s.Transactions[j].data.Price) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type TxByPriceAndNonce struct{ Transactions }
|
|
||||||
|
|
||||||
func (s TxByPriceAndNonce) Less(i, j int) bool {
|
|
||||||
// we can ignore the error here. Sorting shouldn't care about validness
|
|
||||||
ifrom, _ := s.Transactions[i].From()
|
|
||||||
jfrom, _ := s.Transactions[j].From()
|
|
||||||
// favour nonce if they are from the same recipient
|
|
||||||
if ifrom == jfrom {
|
|
||||||
return s.Transactions[i].data.AccountNonce < s.Transactions[j].data.AccountNonce
|
|
||||||
}
|
|
||||||
return s.Transactions[i].data.Price.Cmp(s.Transactions[j].data.Price) > 0
|
|
||||||
}
|
|
||||||
|
@ -81,9 +81,11 @@ func doScheme(base, v []int) asn1.ObjectIdentifier {
|
|||||||
type secgNamedCurve asn1.ObjectIdentifier
|
type secgNamedCurve asn1.ObjectIdentifier
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
secgNamedCurveP224 = secgNamedCurve{1, 3, 132, 0, 33}
|
||||||
secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
|
secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
|
||||||
secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
|
secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
|
||||||
secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
|
secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
|
||||||
|
rawCurveP224 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 3}
|
||||||
rawCurveP256 = []byte{6, 8, 4, 2, 1, 3, 4, 7, 2, 2, 0, 6, 6, 1, 3, 1, 7}
|
rawCurveP256 = []byte{6, 8, 4, 2, 1, 3, 4, 7, 2, 2, 0, 6, 6, 1, 3, 1, 7}
|
||||||
rawCurveP384 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 4}
|
rawCurveP384 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 4}
|
||||||
rawCurveP521 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 5}
|
rawCurveP521 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 5}
|
||||||
@ -91,6 +93,8 @@ var (
|
|||||||
|
|
||||||
func rawCurve(curve elliptic.Curve) []byte {
|
func rawCurve(curve elliptic.Curve) []byte {
|
||||||
switch curve {
|
switch curve {
|
||||||
|
case elliptic.P224():
|
||||||
|
return rawCurveP224
|
||||||
case elliptic.P256():
|
case elliptic.P256():
|
||||||
return rawCurveP256
|
return rawCurveP256
|
||||||
case elliptic.P384():
|
case elliptic.P384():
|
||||||
@ -116,6 +120,8 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
|
|||||||
|
|
||||||
func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
|
func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
|
||||||
switch {
|
switch {
|
||||||
|
case curve.Equal(secgNamedCurveP224):
|
||||||
|
return elliptic.P224()
|
||||||
case curve.Equal(secgNamedCurveP256):
|
case curve.Equal(secgNamedCurveP256):
|
||||||
return elliptic.P256()
|
return elliptic.P256()
|
||||||
case curve.Equal(secgNamedCurveP384):
|
case curve.Equal(secgNamedCurveP384):
|
||||||
@ -128,6 +134,8 @@ func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
|
|||||||
|
|
||||||
func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
|
func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
|
||||||
switch curve {
|
switch curve {
|
||||||
|
case elliptic.P224():
|
||||||
|
return secgNamedCurveP224, true
|
||||||
case elliptic.P256():
|
case elliptic.P256():
|
||||||
return secgNamedCurveP256, true
|
return secgNamedCurveP256, true
|
||||||
case elliptic.P384():
|
case elliptic.P384():
|
||||||
@ -240,7 +248,7 @@ var idEcPublicKeySupplemented = doScheme(idPublicKeyType, []int{0})
|
|||||||
|
|
||||||
func curveToRaw(curve elliptic.Curve) (rv asn1.RawValue, ok bool) {
|
func curveToRaw(curve elliptic.Curve) (rv asn1.RawValue, ok bool) {
|
||||||
switch curve {
|
switch curve {
|
||||||
case elliptic.P256(), elliptic.P384(), elliptic.P521():
|
case elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521():
|
||||||
raw := rawCurve(curve)
|
raw := rawCurve(curve)
|
||||||
return asn1.RawValue{
|
return asn1.RawValue{
|
||||||
Tag: 30,
|
Tag: 30,
|
||||||
|
@ -407,6 +407,11 @@ type testCase struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var testCases = []testCase{
|
var testCases = []testCase{
|
||||||
|
testCase{
|
||||||
|
Curve: elliptic.P224(),
|
||||||
|
Name: "P224",
|
||||||
|
Expected: false,
|
||||||
|
},
|
||||||
testCase{
|
testCase{
|
||||||
Curve: elliptic.P256(),
|
Curve: elliptic.P256(),
|
||||||
Name: "P256",
|
Name: "P256",
|
||||||
|
@ -147,6 +147,7 @@ func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {
|
func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {
|
||||||
|
fmt.Printf("%v\n", keyAddr.Hex())
|
||||||
m := make(map[string]interface{})
|
m := make(map[string]interface{})
|
||||||
err = getKey(keysDirPath, keyAddr, &m)
|
err = getKey(keysDirPath, keyAddr, &m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -21,11 +21,9 @@ package secp256k1
|
|||||||
/*
|
/*
|
||||||
#cgo CFLAGS: -I./secp256k1
|
#cgo CFLAGS: -I./secp256k1
|
||||||
#cgo darwin CFLAGS: -I/usr/local/include
|
#cgo darwin CFLAGS: -I/usr/local/include
|
||||||
#cgo freebsd CFLAGS: -I/usr/local/include
|
|
||||||
#cgo linux,arm CFLAGS: -I/usr/local/arm/include
|
#cgo linux,arm CFLAGS: -I/usr/local/arm/include
|
||||||
#cgo LDFLAGS: -lgmp
|
#cgo LDFLAGS: -lgmp
|
||||||
#cgo darwin LDFLAGS: -L/usr/local/lib
|
#cgo darwin LDFLAGS: -L/usr/local/lib
|
||||||
#cgo freebsd LDFLAGS: -L/usr/local/lib
|
|
||||||
#cgo linux,arm LDFLAGS: -L/usr/local/arm/lib
|
#cgo linux,arm LDFLAGS: -L/usr/local/arm/lib
|
||||||
#define USE_NUM_GMP
|
#define USE_NUM_GMP
|
||||||
#define USE_FIELD_10X26
|
#define USE_FIELD_10X26
|
||||||
|
@ -78,11 +78,9 @@ type Config struct {
|
|||||||
GenesisNonce int
|
GenesisNonce int
|
||||||
GenesisFile string
|
GenesisFile string
|
||||||
GenesisBlock *types.Block // used by block tests
|
GenesisBlock *types.Block // used by block tests
|
||||||
Olympic bool
|
|
||||||
|
|
||||||
BlockChainVersion int
|
BlockChainVersion int
|
||||||
SkipBcVersionCheck bool // e.g. blockchain export
|
SkipBcVersionCheck bool // e.g. blockchain export
|
||||||
DatabaseCache int
|
|
||||||
|
|
||||||
DataDir string
|
DataDir string
|
||||||
LogFile string
|
LogFile string
|
||||||
@ -264,7 +262,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
|
|
||||||
newdb := config.NewDB
|
newdb := config.NewDB
|
||||||
if newdb == nil {
|
if newdb == nil {
|
||||||
newdb = func(path string) (common.Database, error) { return ethdb.NewLDBDatabase(path, config.DatabaseCache) }
|
newdb = func(path string) (common.Database, error) { return ethdb.NewLDBDatabase(path) }
|
||||||
}
|
}
|
||||||
blockDb, err := newdb(filepath.Join(config.DataDir, "blockchain"))
|
blockDb, err := newdb(filepath.Join(config.DataDir, "blockchain"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -303,14 +301,6 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
glog.V(logger.Info).Infof("Successfully wrote genesis block. New genesis hash = %x\n", block.Hash())
|
glog.V(logger.Info).Infof("Successfully wrote genesis block. New genesis hash = %x\n", block.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Olympic {
|
|
||||||
_, err := core.WriteTestNetGenesisBlock(stateDb, blockDb, 42)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
glog.V(logger.Error).Infoln("Starting Olympic network")
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is for testing only.
|
// This is for testing only.
|
||||||
if config.GenesisBlock != nil {
|
if config.GenesisBlock != nil {
|
||||||
core.WriteBlock(blockDb, config.GenesisBlock)
|
core.WriteBlock(blockDb, config.GenesisBlock)
|
||||||
|
@ -28,13 +28,12 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testdb, _ = ethdb.NewMemDatabase()
|
testdb, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.GenesisBlockForTesting(testdb, common.Address{}, big.NewInt(0))
|
genesis = core.GenesisBlockForTesting(testdb, common.Address{}, big.NewInt(0))
|
||||||
unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit}, nil, nil, nil)
|
unknownBlock = types.NewBlock(&types.Header{}, nil, nil, nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// makeChain creates a chain of n blocks starting at and including parent.
|
// makeChain creates a chain of n blocks starting at and including parent.
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package ethdb
|
package ethdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -36,14 +35,6 @@ import (
|
|||||||
|
|
||||||
var OpenFileLimit = 64
|
var OpenFileLimit = 64
|
||||||
|
|
||||||
// cacheRatio specifies how the total alloted cache is distributed between the
|
|
||||||
// various system databases.
|
|
||||||
var cacheRatio = map[string]float64{
|
|
||||||
"blockchain": 1.0 / 13.0,
|
|
||||||
"extra": 2.0 / 13.0,
|
|
||||||
"state": 10.0 / 13.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
type LDBDatabase struct {
|
type LDBDatabase struct {
|
||||||
fn string // filename for reporting
|
fn string // filename for reporting
|
||||||
db *leveldb.DB // LevelDB instance
|
db *leveldb.DB // LevelDB instance
|
||||||
@ -65,24 +56,14 @@ type LDBDatabase struct {
|
|||||||
// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
|
// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
|
||||||
// it self but requires a background poller which syncs every X. `Flush` should be called
|
// it self but requires a background poller which syncs every X. `Flush` should be called
|
||||||
// when data needs to be stored and written to disk.
|
// when data needs to be stored and written to disk.
|
||||||
func NewLDBDatabase(file string, cache int) (*LDBDatabase, error) {
|
func NewLDBDatabase(file string) (*LDBDatabase, error) {
|
||||||
// Calculate the cache allowance for this particular database
|
// Open the db
|
||||||
cache = int(float64(cache) * cacheRatio[filepath.Base(file)])
|
db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit})
|
||||||
if cache < 16 {
|
// check for corruption and attempt to recover
|
||||||
cache = 16
|
if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted {
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infof("Alloted %dMB cache to %s", cache, file)
|
|
||||||
|
|
||||||
// Open the db and recover any potential corruptions
|
|
||||||
db, err := leveldb.OpenFile(file, &opt.Options{
|
|
||||||
OpenFilesCacheCapacity: OpenFileLimit,
|
|
||||||
BlockCacheCapacity: cache / 2 * opt.MiB,
|
|
||||||
WriteBuffer: cache / 4 * opt.MiB, // Two of these are used internally
|
|
||||||
})
|
|
||||||
if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
|
|
||||||
db, err = leveldb.RecoverFile(file, nil)
|
db, err = leveldb.RecoverFile(file, nil)
|
||||||
}
|
}
|
||||||
// (Re)check for errors and abort if opening of the db failed
|
// (re) check for errors and abort if opening of the db failed
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ func newDb() *LDBDatabase {
|
|||||||
if common.FileExist(file) {
|
if common.FileExist(file) {
|
||||||
os.RemoveAll(file)
|
os.RemoveAll(file)
|
||||||
}
|
}
|
||||||
db, _ := NewLDBDatabase(file, 0)
|
|
||||||
|
db, _ := NewLDBDatabase(file)
|
||||||
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Package fdtrack logs statistics about open file descriptors.
|
|
||||||
package fdtrack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mutex sync.Mutex
|
|
||||||
all = make(map[string]int)
|
|
||||||
)
|
|
||||||
|
|
||||||
func Open(desc string) {
|
|
||||||
mutex.Lock()
|
|
||||||
all[desc] += 1
|
|
||||||
mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Close(desc string) {
|
|
||||||
mutex.Lock()
|
|
||||||
defer mutex.Unlock()
|
|
||||||
if c, ok := all[desc]; ok {
|
|
||||||
if c == 1 {
|
|
||||||
delete(all, desc)
|
|
||||||
} else {
|
|
||||||
all[desc]--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapListener(desc string, l net.Listener) net.Listener {
|
|
||||||
Open(desc)
|
|
||||||
return &wrappedListener{l, desc}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrappedListener struct {
|
|
||||||
net.Listener
|
|
||||||
desc string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrappedListener) Accept() (net.Conn, error) {
|
|
||||||
c, err := w.Listener.Accept()
|
|
||||||
if err == nil {
|
|
||||||
c = WrapConn(w.desc, c)
|
|
||||||
}
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrappedListener) Close() error {
|
|
||||||
err := w.Listener.Close()
|
|
||||||
if err == nil {
|
|
||||||
Close(w.desc)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapConn(desc string, conn net.Conn) net.Conn {
|
|
||||||
Open(desc)
|
|
||||||
return &wrappedConn{conn, desc}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrappedConn struct {
|
|
||||||
net.Conn
|
|
||||||
desc string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrappedConn) Close() error {
|
|
||||||
err := w.Conn.Close()
|
|
||||||
if err == nil {
|
|
||||||
Close(w.desc)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func Start() {
|
|
||||||
go func() {
|
|
||||||
for range time.Tick(15 * time.Second) {
|
|
||||||
mutex.Lock()
|
|
||||||
var sum, tracked = 0, []string{}
|
|
||||||
for what, n := range all {
|
|
||||||
sum += n
|
|
||||||
tracked = append(tracked, fmt.Sprintf("%s:%d", what, n))
|
|
||||||
}
|
|
||||||
mutex.Unlock()
|
|
||||||
used, _ := fdusage()
|
|
||||||
sort.Strings(tracked)
|
|
||||||
glog.Infof("fd usage %d/%d, tracked %d %v", used, fdlimit(), sum, tracked)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// +build !linux,!darwin
|
|
||||||
|
|
||||||
package fdtrack
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func fdlimit() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func fdusage() (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// +build darwin
|
|
||||||
|
|
||||||
package fdtrack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// #cgo CFLAGS: -lproc
|
|
||||||
// #include <libproc.h>
|
|
||||||
// #include <stdlib.h>
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func fdlimit() int {
|
|
||||||
var nofile syscall.Rlimit
|
|
||||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &nofile); err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return int(nofile.Cur)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fdusage() (int, error) {
|
|
||||||
pid := C.int(os.Getpid())
|
|
||||||
// Query for a rough estimate on the amout of data that
|
|
||||||
// proc_pidinfo will return.
|
|
||||||
rlen, err := C.proc_pidinfo(pid, C.PROC_PIDLISTFDS, 0, nil, 0)
|
|
||||||
if rlen <= 0 {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
// Load the list of file descriptors. We don't actually care about
|
|
||||||
// the content, only about the size. Since the number of fds can
|
|
||||||
// change while we're reading them, the loop enlarges the buffer
|
|
||||||
// until proc_pidinfo says the result fitted.
|
|
||||||
var buf unsafe.Pointer
|
|
||||||
defer func() {
|
|
||||||
if buf != nil {
|
|
||||||
C.free(buf)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
for buflen := rlen; ; buflen *= 2 {
|
|
||||||
buf, err = C.reallocf(buf, C.size_t(buflen))
|
|
||||||
if buf == nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
rlen, err = C.proc_pidinfo(pid, C.PROC_PIDLISTFDS, 0, buf, buflen)
|
|
||||||
if rlen <= 0 {
|
|
||||||
return 0, err
|
|
||||||
} else if rlen == buflen {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return int(rlen / C.PROC_PIDLISTFD_SIZE), nil
|
|
||||||
}
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package fdtrack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func fdlimit() int {
|
|
||||||
var nofile syscall.Rlimit
|
|
||||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &nofile); err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return int(nofile.Cur)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fdusage() (int, error) {
|
|
||||||
f, err := os.Open("/proc/self/fd")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
const batchSize = 100
|
|
||||||
n := 0
|
|
||||||
for {
|
|
||||||
list, err := f.Readdirnames(batchSize)
|
|
||||||
n += len(list)
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
} else if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
@ -1137,10 +1137,10 @@ var toHex = function (val) {
|
|||||||
if (isString(val)) {
|
if (isString(val)) {
|
||||||
if (val.indexOf('-0x') === 0)
|
if (val.indexOf('-0x') === 0)
|
||||||
return fromDecimal(val);
|
return fromDecimal(val);
|
||||||
else if (!isFinite(val))
|
|
||||||
return fromAscii(val);
|
|
||||||
else if(val.indexOf('0x') === 0)
|
else if(val.indexOf('0x') === 0)
|
||||||
return val;
|
return val;
|
||||||
|
else if (!isFinite(val))
|
||||||
|
return fromAscii(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fromDecimal(val);
|
return fromDecimal(val);
|
||||||
|
@ -34,7 +34,6 @@ func ReadDiskStats(stats *DiskStats) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer inf.Close()
|
|
||||||
in := bufio.NewReader(inf)
|
in := bufio.NewReader(inf)
|
||||||
|
|
||||||
// Iterate over the IO counter, and extract what we need
|
// Iterate over the IO counter, and extract what we need
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"sync"
|
"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/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
@ -28,10 +29,10 @@ import (
|
|||||||
type CpuAgent struct {
|
type CpuAgent struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
workCh chan *Work
|
workCh chan *types.Block
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
quitCurrentOp chan struct{}
|
quitCurrentOp chan struct{}
|
||||||
returnCh chan<- *Result
|
returnCh chan<- *types.Block
|
||||||
|
|
||||||
index int
|
index int
|
||||||
pow pow.PoW
|
pow pow.PoW
|
||||||
@ -46,9 +47,9 @@ func NewCpuAgent(index int, pow pow.PoW) *CpuAgent {
|
|||||||
return miner
|
return miner
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) Work() chan<- *Work { return self.workCh }
|
func (self *CpuAgent) Work() chan<- *types.Block { return self.workCh }
|
||||||
func (self *CpuAgent) Pow() pow.PoW { return self.pow }
|
func (self *CpuAgent) Pow() pow.PoW { return self.pow }
|
||||||
func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch }
|
func (self *CpuAgent) SetReturnCh(ch chan<- *types.Block) { self.returnCh = ch }
|
||||||
|
|
||||||
func (self *CpuAgent) Stop() {
|
func (self *CpuAgent) Stop() {
|
||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
@ -64,7 +65,7 @@ func (self *CpuAgent) Start() {
|
|||||||
self.quit = make(chan struct{})
|
self.quit = make(chan struct{})
|
||||||
// creating current op ch makes sure we're not closing a nil ch
|
// creating current op ch makes sure we're not closing a nil ch
|
||||||
// later on
|
// later on
|
||||||
self.workCh = make(chan *Work, 1)
|
self.workCh = make(chan *types.Block, 1)
|
||||||
|
|
||||||
go self.update()
|
go self.update()
|
||||||
}
|
}
|
||||||
@ -73,13 +74,13 @@ func (self *CpuAgent) update() {
|
|||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case work := <-self.workCh:
|
case block := <-self.workCh:
|
||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
if self.quitCurrentOp != nil {
|
if self.quitCurrentOp != nil {
|
||||||
close(self.quitCurrentOp)
|
close(self.quitCurrentOp)
|
||||||
}
|
}
|
||||||
self.quitCurrentOp = make(chan struct{})
|
self.quitCurrentOp = make(chan struct{})
|
||||||
go self.mine(work, self.quitCurrentOp)
|
go self.mine(block, self.quitCurrentOp)
|
||||||
self.mu.Unlock()
|
self.mu.Unlock()
|
||||||
case <-self.quit:
|
case <-self.quit:
|
||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
@ -105,14 +106,13 @@ done:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
|
func (self *CpuAgent) mine(block *types.Block, stop <-chan struct{}) {
|
||||||
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
|
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
|
||||||
|
|
||||||
// Mine
|
// Mine
|
||||||
nonce, mixDigest := self.pow.Search(work.Block, stop)
|
nonce, mixDigest := self.pow.Search(block, stop)
|
||||||
if nonce != 0 {
|
if nonce != 0 {
|
||||||
block := work.Block.WithMiningResult(nonce, common.BytesToHash(mixDigest))
|
self.returnCh <- block.WithMiningResult(nonce, common.BytesToHash(mixDigest))
|
||||||
self.returnCh <- &Result{work, block}
|
|
||||||
} else {
|
} else {
|
||||||
self.returnCh <- nil
|
self.returnCh <- nil
|
||||||
}
|
}
|
||||||
|
@ -18,44 +18,39 @@ package miner
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RemoteAgent struct {
|
type RemoteAgent struct {
|
||||||
mu sync.Mutex
|
work *types.Block
|
||||||
|
currentWork *types.Block
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
workCh chan *Work
|
workCh chan *types.Block
|
||||||
returnCh chan<- *Result
|
returnCh chan<- *types.Block
|
||||||
|
|
||||||
currentWork *Work
|
|
||||||
work map[common.Hash]*Work
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoteAgent() *RemoteAgent {
|
func NewRemoteAgent() *RemoteAgent {
|
||||||
agent := &RemoteAgent{work: make(map[common.Hash]*Work)}
|
agent := &RemoteAgent{}
|
||||||
|
|
||||||
return agent
|
return agent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *RemoteAgent) Work() chan<- *Work {
|
func (a *RemoteAgent) Work() chan<- *types.Block {
|
||||||
return a.workCh
|
return a.workCh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *RemoteAgent) SetReturnCh(returnCh chan<- *Result) {
|
func (a *RemoteAgent) SetReturnCh(returnCh chan<- *types.Block) {
|
||||||
a.returnCh = returnCh
|
a.returnCh = returnCh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *RemoteAgent) Start() {
|
func (a *RemoteAgent) Start() {
|
||||||
a.quit = make(chan struct{})
|
a.quit = make(chan struct{})
|
||||||
a.workCh = make(chan *Work, 1)
|
a.workCh = make(chan *types.Block, 1)
|
||||||
go a.maintainLoop()
|
go a.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *RemoteAgent) Stop() {
|
func (a *RemoteAgent) Stop() {
|
||||||
@ -65,72 +60,47 @@ func (a *RemoteAgent) Stop() {
|
|||||||
|
|
||||||
func (a *RemoteAgent) GetHashRate() int64 { return 0 }
|
func (a *RemoteAgent) GetHashRate() int64 { return 0 }
|
||||||
|
|
||||||
func (a *RemoteAgent) GetWork() [3]string {
|
func (a *RemoteAgent) run() {
|
||||||
a.mu.Lock()
|
|
||||||
defer a.mu.Unlock()
|
|
||||||
|
|
||||||
var res [3]string
|
|
||||||
|
|
||||||
if a.currentWork != nil {
|
|
||||||
block := a.currentWork.Block
|
|
||||||
|
|
||||||
res[0] = block.HashNoNonce().Hex()
|
|
||||||
seedHash, _ := ethash.GetSeedHash(block.NumberU64())
|
|
||||||
res[1] = common.BytesToHash(seedHash).Hex()
|
|
||||||
// Calculate the "target" to be returned to the external miner
|
|
||||||
n := big.NewInt(1)
|
|
||||||
n.Lsh(n, 255)
|
|
||||||
n.Div(n, block.Difficulty())
|
|
||||||
n.Lsh(n, 1)
|
|
||||||
res[2] = common.BytesToHash(n.Bytes()).Hex()
|
|
||||||
|
|
||||||
a.work[block.HashNoNonce()] = a.currentWork
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true or false, but does not indicate if the PoW was correct
|
|
||||||
func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, hash common.Hash) bool {
|
|
||||||
a.mu.Lock()
|
|
||||||
defer a.mu.Unlock()
|
|
||||||
|
|
||||||
// Make sure the work submitted is present
|
|
||||||
if a.work[hash] != nil {
|
|
||||||
block := a.work[hash].Block.WithMiningResult(nonce, mixDigest)
|
|
||||||
a.returnCh <- &Result{a.work[hash], block}
|
|
||||||
|
|
||||||
delete(a.work, hash)
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
glog.V(logger.Info).Infof("Work was submitted for %x but no pending work found\n", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *RemoteAgent) maintainLoop() {
|
|
||||||
ticker := time.Tick(5 * time.Second)
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-a.quit:
|
case <-a.quit:
|
||||||
break out
|
break out
|
||||||
case work := <-a.workCh:
|
case work := <-a.workCh:
|
||||||
a.mu.Lock()
|
a.work = work
|
||||||
a.currentWork = work
|
|
||||||
a.mu.Unlock()
|
|
||||||
case <-ticker:
|
|
||||||
// cleanup
|
|
||||||
a.mu.Lock()
|
|
||||||
for hash, work := range a.work {
|
|
||||||
if time.Since(work.createdAt) > 7*(12*time.Second) {
|
|
||||||
delete(a.work, hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *RemoteAgent) GetWork() [3]string {
|
||||||
|
var res [3]string
|
||||||
|
|
||||||
|
if a.work != nil {
|
||||||
|
a.currentWork = a.work
|
||||||
|
|
||||||
|
res[0] = a.work.HashNoNonce().Hex()
|
||||||
|
seedHash, _ := ethash.GetSeedHash(a.currentWork.NumberU64())
|
||||||
|
res[1] = common.BytesToHash(seedHash).Hex()
|
||||||
|
// Calculate the "target" to be returned to the external miner
|
||||||
|
n := big.NewInt(1)
|
||||||
|
n.Lsh(n, 255)
|
||||||
|
n.Div(n, a.work.Difficulty())
|
||||||
|
n.Lsh(n, 1)
|
||||||
|
res[2] = common.BytesToHash(n.Bytes()).Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, seedHash common.Hash) bool {
|
||||||
|
// Return true or false, but does not indicate if the PoW was correct
|
||||||
|
|
||||||
|
// Make sure the external miner was working on the right hash
|
||||||
|
if a.currentWork != nil && a.work != nil {
|
||||||
|
a.returnCh <- a.currentWork.WithMiningResult(nonce, mixDigest)
|
||||||
|
//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
240
miner/worker.go
240
miner/worker.go
@ -38,20 +38,25 @@ import (
|
|||||||
|
|
||||||
var jsonlogger = logger.NewJsonLogger()
|
var jsonlogger = logger.NewJsonLogger()
|
||||||
|
|
||||||
const (
|
// Work holds the current work
|
||||||
resultQueueSize = 10
|
type Work struct {
|
||||||
miningLogAtDepth = 5
|
Number uint64
|
||||||
)
|
Nonce uint64
|
||||||
|
MixDigest []byte
|
||||||
|
SeedHash []byte
|
||||||
|
}
|
||||||
|
|
||||||
// Agent can register themself with the worker
|
// Agent can register themself with the worker
|
||||||
type Agent interface {
|
type Agent interface {
|
||||||
Work() chan<- *Work
|
Work() chan<- *types.Block
|
||||||
SetReturnCh(chan<- *Result)
|
SetReturnCh(chan<- *types.Block)
|
||||||
Stop()
|
Stop()
|
||||||
Start()
|
Start()
|
||||||
GetHashRate() int64
|
GetHashRate() int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const miningLogAtDepth = 5
|
||||||
|
|
||||||
type uint64RingBuffer struct {
|
type uint64RingBuffer struct {
|
||||||
ints []uint64 //array of all integers in buffer
|
ints []uint64 //array of all integers in buffer
|
||||||
next int //where is the next insertion? assert 0 <= next < len(ints)
|
next int //where is the next insertion? assert 0 <= next < len(ints)
|
||||||
@ -59,7 +64,7 @@ type uint64RingBuffer struct {
|
|||||||
|
|
||||||
// environment is the workers current environment and holds
|
// environment is the workers current environment and holds
|
||||||
// all of the current state information
|
// all of the current state information
|
||||||
type Work struct {
|
type environment struct {
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
coinbase *state.StateObject // the miner's account
|
coinbase *state.StateObject // the miner's account
|
||||||
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
||||||
@ -73,18 +78,11 @@ type Work struct {
|
|||||||
lowGasTxs types.Transactions
|
lowGasTxs types.Transactions
|
||||||
localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
|
localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
|
||||||
|
|
||||||
Block *types.Block // the new block
|
block *types.Block // the new block
|
||||||
|
|
||||||
header *types.Header
|
header *types.Header
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
receipts []*types.Receipt
|
receipts []*types.Receipt
|
||||||
|
|
||||||
createdAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result struct {
|
|
||||||
Work *Work
|
|
||||||
Block *types.Block
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// worker is the main object which takes care of applying messages to the new state
|
// worker is the main object which takes care of applying messages to the new state
|
||||||
@ -92,7 +90,7 @@ type worker struct {
|
|||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
agents []Agent
|
agents []Agent
|
||||||
recv chan *Result
|
recv chan *types.Block
|
||||||
mux *event.TypeMux
|
mux *event.TypeMux
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
pow pow.PoW
|
pow pow.PoW
|
||||||
@ -107,7 +105,7 @@ type worker struct {
|
|||||||
extra []byte
|
extra []byte
|
||||||
|
|
||||||
currentMu sync.Mutex
|
currentMu sync.Mutex
|
||||||
current *Work
|
current *environment
|
||||||
|
|
||||||
uncleMu sync.Mutex
|
uncleMu sync.Mutex
|
||||||
possibleUncles map[common.Hash]*types.Block
|
possibleUncles map[common.Hash]*types.Block
|
||||||
@ -118,8 +116,6 @@ type worker struct {
|
|||||||
// atomic status counters
|
// atomic status counters
|
||||||
mining int32
|
mining int32
|
||||||
atWork int32
|
atWork int32
|
||||||
|
|
||||||
fullValidation bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWorker(coinbase common.Address, eth core.Backend) *worker {
|
func newWorker(coinbase common.Address, eth core.Backend) *worker {
|
||||||
@ -127,7 +123,7 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
|
|||||||
eth: eth,
|
eth: eth,
|
||||||
mux: eth.EventMux(),
|
mux: eth.EventMux(),
|
||||||
extraDb: eth.ExtraDb(),
|
extraDb: eth.ExtraDb(),
|
||||||
recv: make(chan *Result, resultQueueSize),
|
recv: make(chan *types.Block),
|
||||||
gasPrice: new(big.Int),
|
gasPrice: new(big.Int),
|
||||||
chain: eth.ChainManager(),
|
chain: eth.ChainManager(),
|
||||||
proc: eth.BlockProcessor(),
|
proc: eth.BlockProcessor(),
|
||||||
@ -135,7 +131,6 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
|
|||||||
coinbase: coinbase,
|
coinbase: coinbase,
|
||||||
txQueue: make(map[common.Hash]*types.Transaction),
|
txQueue: make(map[common.Hash]*types.Transaction),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
fullValidation: false,
|
|
||||||
}
|
}
|
||||||
go worker.update()
|
go worker.update()
|
||||||
go worker.wait()
|
go worker.wait()
|
||||||
@ -169,7 +164,7 @@ func (self *worker) pendingBlock() *types.Block {
|
|||||||
self.current.receipts,
|
self.current.receipts,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return self.current.Block
|
return self.current.block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) start() {
|
func (self *worker) start() {
|
||||||
@ -256,55 +251,34 @@ func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *uint64RingBuffer) (
|
|||||||
|
|
||||||
func (self *worker) wait() {
|
func (self *worker) wait() {
|
||||||
for {
|
for {
|
||||||
for result := range self.recv {
|
for block := range self.recv {
|
||||||
atomic.AddInt32(&self.atWork, -1)
|
atomic.AddInt32(&self.atWork, -1)
|
||||||
|
|
||||||
if result == nil {
|
if block == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
block := result.Block
|
|
||||||
work := result.Work
|
|
||||||
|
|
||||||
work.state.Sync()
|
parent := self.chain.GetBlock(block.ParentHash())
|
||||||
if self.fullValidation {
|
if parent == nil {
|
||||||
if _, err := self.chain.InsertChain(types.Blocks{block}); err != nil {
|
glog.V(logger.Error).Infoln("Invalid block found during mining")
|
||||||
glog.V(logger.Error).Infoln("mining err", err)
|
continue
|
||||||
continue
|
}
|
||||||
}
|
if err := core.ValidateHeader(self.eth.BlockProcessor().Pow, block.Header(), parent, true); err != nil && err != core.BlockFutureErr {
|
||||||
go self.mux.Post(core.NewMinedBlockEvent{block})
|
glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
|
||||||
} else {
|
continue
|
||||||
parent := self.chain.GetBlock(block.ParentHash())
|
}
|
||||||
if parent == nil {
|
|
||||||
glog.V(logger.Error).Infoln("Invalid block found during mining")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := core.ValidateHeader(self.eth.BlockProcessor().Pow, block.Header(), parent, true); err != nil && err != core.BlockFutureErr {
|
|
||||||
glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
stat, err := self.chain.WriteBlock(block, false)
|
stat, err := self.chain.WriteBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infoln("error writing block to chain", err)
|
glog.V(logger.Error).Infoln("error writing block to chain", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// check if canon block and write transactions
|
// check if canon block and write transactions
|
||||||
if stat == core.CanonStatTy {
|
if stat == core.CanonStatTy {
|
||||||
// This puts transactions in a extra db for rpc
|
// This puts transactions in a extra db for rpc
|
||||||
core.PutTransactions(self.extraDb, block, block.Transactions())
|
core.PutTransactions(self.extraDb, block, block.Transactions())
|
||||||
// store the receipts
|
// store the receipts
|
||||||
core.PutReceipts(self.extraDb, work.receipts)
|
core.PutReceipts(self.extraDb, self.current.receipts)
|
||||||
}
|
|
||||||
|
|
||||||
// broadcast before waiting for validation
|
|
||||||
go func(block *types.Block, logs state.Logs) {
|
|
||||||
self.mux.Post(core.NewMinedBlockEvent{block})
|
|
||||||
self.mux.Post(core.ChainEvent{block, block.Hash(), logs})
|
|
||||||
if stat == core.CanonStatTy {
|
|
||||||
self.mux.Post(core.ChainHeadEvent{block})
|
|
||||||
self.mux.Post(logs)
|
|
||||||
}
|
|
||||||
}(block, work.state.Logs())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check staleness and display confirmation
|
// check staleness and display confirmation
|
||||||
@ -314,18 +288,29 @@ func (self *worker) wait() {
|
|||||||
stale = "stale "
|
stale = "stale "
|
||||||
} else {
|
} else {
|
||||||
confirm = "Wait 5 blocks for confirmation"
|
confirm = "Wait 5 blocks for confirmation"
|
||||||
work.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), work.localMinedBlocks)
|
self.current.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), self.current.localMinedBlocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)
|
glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)
|
||||||
|
|
||||||
|
// broadcast before waiting for validation
|
||||||
|
go func(block *types.Block, logs state.Logs) {
|
||||||
|
self.mux.Post(core.NewMinedBlockEvent{block})
|
||||||
|
self.mux.Post(core.ChainEvent{block, block.Hash(), logs})
|
||||||
|
if stat == core.CanonStatTy {
|
||||||
|
self.mux.Post(core.ChainHeadEvent{block})
|
||||||
|
self.mux.Post(logs)
|
||||||
|
}
|
||||||
|
}(block, self.current.state.Logs())
|
||||||
|
|
||||||
self.commitNewWork()
|
self.commitNewWork()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) push(work *Work) {
|
func (self *worker) push() {
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&self.mining) == 1 {
|
||||||
if core.Canary(work.state) {
|
if core.Canary(self.current.state) {
|
||||||
glog.Infoln("Toxicity levels rising to deadly levels. Your canary has died. You can go back or continue down the mineshaft --more--")
|
glog.Infoln("Toxicity levels rising to deadly levels. Your canary has died. You can go back or continue down the mineshaft --more--")
|
||||||
glog.Infoln("You turn back and abort mining")
|
glog.Infoln("You turn back and abort mining")
|
||||||
return
|
return
|
||||||
@ -336,7 +321,7 @@ func (self *worker) push(work *Work) {
|
|||||||
atomic.AddInt32(&self.atWork, 1)
|
atomic.AddInt32(&self.atWork, 1)
|
||||||
|
|
||||||
if agent.Work() != nil {
|
if agent.Work() != nil {
|
||||||
agent.Work() <- work
|
agent.Work() <- self.current.block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,36 +330,35 @@ func (self *worker) push(work *Work) {
|
|||||||
// makeCurrent creates a new environment for the current cycle.
|
// makeCurrent creates a new environment for the current cycle.
|
||||||
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
|
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
|
||||||
state := state.New(parent.Root(), self.eth.StateDb())
|
state := state.New(parent.Root(), self.eth.StateDb())
|
||||||
work := &Work{
|
current := &environment{
|
||||||
state: state,
|
state: state,
|
||||||
ancestors: set.New(),
|
ancestors: set.New(),
|
||||||
family: set.New(),
|
family: set.New(),
|
||||||
uncles: set.New(),
|
uncles: set.New(),
|
||||||
header: header,
|
header: header,
|
||||||
coinbase: state.GetOrNewStateObject(self.coinbase),
|
coinbase: state.GetOrNewStateObject(self.coinbase),
|
||||||
createdAt: time.Now(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when 08 is processed ancestors contain 07 (quick block)
|
// when 08 is processed ancestors contain 07 (quick block)
|
||||||
for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
||||||
for _, uncle := range ancestor.Uncles() {
|
for _, uncle := range ancestor.Uncles() {
|
||||||
work.family.Add(uncle.Hash())
|
current.family.Add(uncle.Hash())
|
||||||
}
|
}
|
||||||
work.family.Add(ancestor.Hash())
|
current.family.Add(ancestor.Hash())
|
||||||
work.ancestors.Add(ancestor.Hash())
|
current.ancestors.Add(ancestor.Hash())
|
||||||
}
|
}
|
||||||
accounts, _ := self.eth.AccountManager().Accounts()
|
accounts, _ := self.eth.AccountManager().Accounts()
|
||||||
|
|
||||||
// Keep track of transactions which return errors so they can be removed
|
// Keep track of transactions which return errors so they can be removed
|
||||||
work.remove = set.New()
|
current.remove = set.New()
|
||||||
work.tcount = 0
|
current.tcount = 0
|
||||||
work.ignoredTransactors = set.New()
|
current.ignoredTransactors = set.New()
|
||||||
work.lowGasTransactors = set.New()
|
current.lowGasTransactors = set.New()
|
||||||
work.ownedAccounts = accountAddressesSet(accounts)
|
current.ownedAccounts = accountAddressesSet(accounts)
|
||||||
if self.current != nil {
|
if self.current != nil {
|
||||||
work.localMinedBlocks = self.current.localMinedBlocks
|
current.localMinedBlocks = self.current.localMinedBlocks
|
||||||
}
|
}
|
||||||
self.current = work
|
self.current = current
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) setGasPrice(p *big.Int) {
|
func (w *worker) setGasPrice(p *big.Int) {
|
||||||
@ -388,13 +372,13 @@ func (w *worker) setGasPrice(p *big.Int) {
|
|||||||
w.mux.Post(core.GasPriceChanged{w.gasPrice})
|
w.mux.Post(core.GasPriceChanged{w.gasPrice})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) isBlockLocallyMined(current *Work, deepBlockNum uint64) bool {
|
func (self *worker) isBlockLocallyMined(deepBlockNum uint64) bool {
|
||||||
//Did this instance mine a block at {deepBlockNum} ?
|
//Did this instance mine a block at {deepBlockNum} ?
|
||||||
var isLocal = false
|
var isLocal = false
|
||||||
for idx, blockNum := range current.localMinedBlocks.ints {
|
for idx, blockNum := range self.current.localMinedBlocks.ints {
|
||||||
if deepBlockNum == blockNum {
|
if deepBlockNum == blockNum {
|
||||||
isLocal = true
|
isLocal = true
|
||||||
current.localMinedBlocks.ints[idx] = 0 //prevent showing duplicate logs
|
self.current.localMinedBlocks.ints[idx] = 0 //prevent showing duplicate logs
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -408,12 +392,12 @@ func (self *worker) isBlockLocallyMined(current *Work, deepBlockNum uint64) bool
|
|||||||
return block != nil && block.Coinbase() == self.coinbase
|
return block != nil && block.Coinbase() == self.coinbase
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) logLocalMinedBlocks(current, previous *Work) {
|
func (self *worker) logLocalMinedBlocks(previous *environment) {
|
||||||
if previous != nil && current.localMinedBlocks != nil {
|
if previous != nil && self.current.localMinedBlocks != nil {
|
||||||
nextBlockNum := current.Block.NumberU64()
|
nextBlockNum := self.current.block.NumberU64()
|
||||||
for checkBlockNum := previous.Block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
|
for checkBlockNum := previous.block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
|
||||||
inspectBlockNum := checkBlockNum - miningLogAtDepth
|
inspectBlockNum := checkBlockNum - miningLogAtDepth
|
||||||
if self.isBlockLocallyMined(current, inspectBlockNum) {
|
if self.isBlockLocallyMined(inspectBlockNum) {
|
||||||
glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum)
|
glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +429,7 @@ func (self *worker) commitNewWork() {
|
|||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Number: num.Add(num, common.Big1),
|
Number: num.Add(num, common.Big1),
|
||||||
Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time(), parent.Number(), parent.Difficulty()),
|
Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time(), parent.Difficulty()),
|
||||||
GasLimit: core.CalcGasLimit(parent),
|
GasLimit: core.CalcGasLimit(parent),
|
||||||
GasUsed: new(big.Int),
|
GasUsed: new(big.Int),
|
||||||
Coinbase: self.coinbase,
|
Coinbase: self.coinbase,
|
||||||
@ -455,47 +439,14 @@ func (self *worker) commitNewWork() {
|
|||||||
|
|
||||||
previous := self.current
|
previous := self.current
|
||||||
self.makeCurrent(parent, header)
|
self.makeCurrent(parent, header)
|
||||||
work := self.current
|
current := self.current
|
||||||
|
|
||||||
/* //approach 1
|
// commit transactions for this run.
|
||||||
transactions := self.eth.TxPool().GetTransactions()
|
transactions := self.eth.TxPool().GetTransactions()
|
||||||
sort.Sort(types.TxByNonce{transactions})
|
sort.Sort(types.TxByNonce{transactions})
|
||||||
*/
|
current.coinbase.SetGasLimit(header.GasLimit)
|
||||||
|
current.commitTransactions(transactions, self.gasPrice, self.proc)
|
||||||
//approach 2
|
self.eth.TxPool().RemoveTransactions(current.lowGasTxs)
|
||||||
transactions := self.eth.TxPool().GetTransactions()
|
|
||||||
sort.Sort(types.TxByPriceAndNonce{transactions})
|
|
||||||
|
|
||||||
/* // approach 3
|
|
||||||
// commit transactions for this run.
|
|
||||||
txPerOwner := make(map[common.Address]types.Transactions)
|
|
||||||
// Sort transactions by owner
|
|
||||||
for _, tx := range self.eth.TxPool().GetTransactions() {
|
|
||||||
from, _ := tx.From() // we can ignore the sender error
|
|
||||||
txPerOwner[from] = append(txPerOwner[from], tx)
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
singleTxOwner types.Transactions
|
|
||||||
multiTxOwner types.Transactions
|
|
||||||
)
|
|
||||||
// Categorise transactions by
|
|
||||||
// 1. 1 owner tx per block
|
|
||||||
// 2. multi txs owner per block
|
|
||||||
for _, txs := range txPerOwner {
|
|
||||||
if len(txs) == 1 {
|
|
||||||
singleTxOwner = append(singleTxOwner, txs[0])
|
|
||||||
} else {
|
|
||||||
multiTxOwner = append(multiTxOwner, txs...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Sort(types.TxByPrice{singleTxOwner})
|
|
||||||
sort.Sort(types.TxByNonce{multiTxOwner})
|
|
||||||
transactions := append(singleTxOwner, multiTxOwner...)
|
|
||||||
*/
|
|
||||||
|
|
||||||
work.coinbase.SetGasLimit(header.GasLimit)
|
|
||||||
work.commitTransactions(transactions, self.gasPrice, self.proc)
|
|
||||||
self.eth.TxPool().RemoveTransactions(work.lowGasTxs)
|
|
||||||
|
|
||||||
// compute uncles for the new block.
|
// compute uncles for the new block.
|
||||||
var (
|
var (
|
||||||
@ -506,7 +457,7 @@ func (self *worker) commitNewWork() {
|
|||||||
if len(uncles) == 2 {
|
if len(uncles) == 2 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err := self.commitUncle(work, uncle.Header()); err != nil {
|
if err := self.commitUncle(uncle.Header()); err != nil {
|
||||||
if glog.V(logger.Ridiculousness) {
|
if glog.V(logger.Ridiculousness) {
|
||||||
glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
|
glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
|
||||||
glog.V(logger.Detail).Infoln(uncle)
|
glog.V(logger.Detail).Infoln(uncle)
|
||||||
@ -523,40 +474,41 @@ func (self *worker) commitNewWork() {
|
|||||||
|
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&self.mining) == 1 {
|
||||||
// commit state root after all state transitions.
|
// commit state root after all state transitions.
|
||||||
core.AccumulateRewards(work.state, header, uncles)
|
core.AccumulateRewards(self.current.state, header, uncles)
|
||||||
work.state.SyncObjects()
|
current.state.SyncObjects()
|
||||||
header.Root = work.state.Root()
|
self.current.state.Sync()
|
||||||
|
header.Root = current.state.Root()
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the new block whose nonce will be mined.
|
// create the new block whose nonce will be mined.
|
||||||
work.Block = types.NewBlock(header, work.txs, uncles, work.receipts)
|
current.block = types.NewBlock(header, current.txs, uncles, current.receipts)
|
||||||
work.Block.Td = new(big.Int).Set(core.CalcTD(work.Block, self.chain.GetBlock(work.Block.ParentHash())))
|
self.current.block.Td = new(big.Int).Set(core.CalcTD(self.current.block, self.chain.GetBlock(self.current.block.ParentHash())))
|
||||||
|
|
||||||
// We only care about logging if we're actually mining.
|
// We only care about logging if we're actually mining.
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&self.mining) == 1 {
|
||||||
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart))
|
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", current.block.Number(), current.tcount, len(uncles), time.Since(tstart))
|
||||||
self.logLocalMinedBlocks(work, previous)
|
self.logLocalMinedBlocks(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push(work)
|
self.push()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
|
func (self *worker) commitUncle(uncle *types.Header) error {
|
||||||
hash := uncle.Hash()
|
hash := uncle.Hash()
|
||||||
if work.uncles.Has(hash) {
|
if self.current.uncles.Has(hash) {
|
||||||
return core.UncleError("Uncle not unique")
|
return core.UncleError("Uncle not unique")
|
||||||
}
|
}
|
||||||
if !work.ancestors.Has(uncle.ParentHash) {
|
if !self.current.ancestors.Has(uncle.ParentHash) {
|
||||||
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||||
}
|
}
|
||||||
if work.family.Has(hash) {
|
if self.current.family.Has(hash) {
|
||||||
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash))
|
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash))
|
||||||
}
|
}
|
||||||
work.uncles.Add(uncle.Hash())
|
self.current.uncles.Add(uncle.Hash())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
|
func (env *environment) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
|
||||||
for _, tx := range transactions {
|
for _, tx := range transactions {
|
||||||
// We can skip err. It has already been validated in the tx pool
|
// We can skip err. It has already been validated in the tx pool
|
||||||
from, _ := tx.From()
|
from, _ := tx.From()
|
||||||
@ -614,7 +566,7 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *Work) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error {
|
func (env *environment) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error {
|
||||||
snap := env.state.Copy()
|
snap := env.state.Copy()
|
||||||
receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, env.header, tx, env.header.GasUsed, true)
|
receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, env.header, tx, env.header.GasUsed, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
@ -213,7 +212,6 @@ func (t *dialTask) Do(srv *Server) {
|
|||||||
glog.V(logger.Detail).Infof("dial error: %v", err)
|
glog.V(logger.Detail).Infof("dial error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fd = fdtrack.WrapConn("p2p", fd)
|
|
||||||
mfd := newMeteredConn(fd, false)
|
mfd := newMeteredConn(fd, false)
|
||||||
|
|
||||||
srv.setupConn(mfd, t.flags, t.dest)
|
srv.setupConn(mfd, t.flags, t.dest)
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
@ -198,7 +197,6 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBP
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fdtrack.Open("p2p")
|
|
||||||
conn, err := net.ListenUDP("udp", addr)
|
conn, err := net.ListenUDP("udp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -236,7 +234,6 @@ func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath strin
|
|||||||
|
|
||||||
func (t *udp) close() {
|
func (t *udp) close() {
|
||||||
close(t.closing)
|
close(t.closing)
|
||||||
fdtrack.Close("p2p")
|
|
||||||
t.conn.Close()
|
t.conn.Close()
|
||||||
// TODO: wait for the loops to end.
|
// TODO: wait for the loops to end.
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ var (
|
|||||||
// meteredConn is a wrapper around a network TCP connection that meters both the
|
// meteredConn is a wrapper around a network TCP connection that meters both the
|
||||||
// inbound and outbound network traffic.
|
// inbound and outbound network traffic.
|
||||||
type meteredConn struct {
|
type meteredConn struct {
|
||||||
net.Conn
|
*net.TCPConn // Network connection to wrap with metering
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMeteredConn creates a new metered connection, also bumping the ingress or
|
// newMeteredConn creates a new metered connection, also bumping the ingress or
|
||||||
@ -45,13 +45,13 @@ func newMeteredConn(conn net.Conn, ingress bool) net.Conn {
|
|||||||
} else {
|
} else {
|
||||||
egressConnectMeter.Mark(1)
|
egressConnectMeter.Mark(1)
|
||||||
}
|
}
|
||||||
return &meteredConn{conn}
|
return &meteredConn{conn.(*net.TCPConn)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read delegates a network read to the underlying connection, bumping the ingress
|
// Read delegates a network read to the underlying connection, bumping the ingress
|
||||||
// traffic meter along the way.
|
// traffic meter along the way.
|
||||||
func (c *meteredConn) Read(b []byte) (n int, err error) {
|
func (c *meteredConn) Read(b []byte) (n int, err error) {
|
||||||
n, err = c.Conn.Read(b)
|
n, err = c.TCPConn.Read(b)
|
||||||
ingressTrafficMeter.Mark(int64(n))
|
ingressTrafficMeter.Mark(int64(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ func (c *meteredConn) Read(b []byte) (n int, err error) {
|
|||||||
// Write delegates a network write to the underlying connection, bumping the
|
// Write delegates a network write to the underlying connection, bumping the
|
||||||
// egress traffic meter along the way.
|
// egress traffic meter along the way.
|
||||||
func (c *meteredConn) Write(b []byte) (n int, err error) {
|
func (c *meteredConn) Write(b []byte) (n int, err error) {
|
||||||
n, err = c.Conn.Write(b)
|
n, err = c.TCPConn.Write(b)
|
||||||
egressTrafficMeter.Mark(int64(n))
|
egressTrafficMeter.Mark(int64(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
@ -373,7 +372,7 @@ func (srv *Server) startListening() error {
|
|||||||
}
|
}
|
||||||
laddr := listener.Addr().(*net.TCPAddr)
|
laddr := listener.Addr().(*net.TCPAddr)
|
||||||
srv.ListenAddr = laddr.String()
|
srv.ListenAddr = laddr.String()
|
||||||
srv.listener = fdtrack.WrapListener("p2p", listener)
|
srv.listener = listener
|
||||||
srv.loopWG.Add(1)
|
srv.loopWG.Add(1)
|
||||||
go srv.listenLoop()
|
go srv.listenLoop()
|
||||||
// Map the TCP listening port if NAT is configured.
|
// Map the TCP listening port if NAT is configured.
|
||||||
|
@ -39,8 +39,8 @@ var (
|
|||||||
EcrecoverGas = big.NewInt(3000) //
|
EcrecoverGas = big.NewInt(3000) //
|
||||||
Sha256WordGas = big.NewInt(12) //
|
Sha256WordGas = big.NewInt(12) //
|
||||||
|
|
||||||
MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be.
|
MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be.
|
||||||
GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
|
GenesisGasLimit = big.NewInt(5000) // Gas limit of the Genesis block.
|
||||||
|
|
||||||
Sha3Gas = big.NewInt(30) // Once per SHA3 operation.
|
Sha3Gas = big.NewInt(30) // Once per SHA3 operation.
|
||||||
Sha256Gas = big.NewInt(60) //
|
Sha256Gas = big.NewInt(60) //
|
||||||
|
@ -935,9 +935,9 @@ func TestCallArgsNotStrings(t *testing.T) {
|
|||||||
func TestCallArgsToEmpty(t *testing.T) {
|
func TestCallArgsToEmpty(t *testing.T) {
|
||||||
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]`
|
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]`
|
||||||
args := new(CallArgs)
|
args := new(CallArgs)
|
||||||
err := json.Unmarshal([]byte(input), &args)
|
str := ExpectValidationError(json.Unmarshal([]byte(input), &args))
|
||||||
if err != nil {
|
if len(str) > 0 {
|
||||||
t.Error("Did not expect error. Got", err)
|
t.Error(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
@ -323,7 +322,7 @@ func (self *ethApi) EstimateGas(req *shared.Request) (interface{}, error) {
|
|||||||
if len(gas) == 0 {
|
if len(gas) == 0 {
|
||||||
return newHexNum(0), nil
|
return newHexNum(0), nil
|
||||||
} else {
|
} else {
|
||||||
return newHexNum(common.String2Big(gas)), err
|
return newHexNum(gas), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,17 +578,14 @@ func (self *ethApi) Resend(req *shared.Request) (interface{}, error) {
|
|||||||
return nil, shared.NewDecodeParamError(err.Error())
|
return nil, shared.NewDecodeParamError(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
from := common.HexToAddress(args.Tx.From)
|
ret, err := self.xeth.Transact(args.Tx.From, args.Tx.To, args.Tx.Nonce, args.Tx.Value, args.GasLimit, args.GasPrice, args.Tx.Data)
|
||||||
|
if err != nil {
|
||||||
pending := self.ethereum.TxPool().GetTransactions()
|
return nil, err
|
||||||
for _, p := range pending {
|
|
||||||
if pFrom, err := p.From(); err == nil && pFrom == from && p.SigHash() == args.Tx.tx.SigHash() {
|
|
||||||
self.ethereum.TxPool().RemoveTx(common.HexToHash(args.Tx.Hash))
|
|
||||||
return self.xeth.Transact(args.Tx.From, args.Tx.To, args.Tx.Nonce, args.Tx.Value, args.GasLimit, args.GasPrice, args.Tx.Data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("Transaction %s not found", args.Tx.Hash)
|
self.ethereum.TxPool().RemoveTransactions(types.Transactions{args.Tx.tx})
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ethApi) PendingTransactions(req *shared.Request) (interface{}, error) {
|
func (self *ethApi) PendingTransactions(req *shared.Request) (interface{}, error) {
|
||||||
|
@ -469,6 +469,10 @@ func (args *CallArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
args.From = ext.From
|
args.From = ext.From
|
||||||
|
|
||||||
|
if len(ext.To) == 0 {
|
||||||
|
return shared.NewValidationError("to", "is required")
|
||||||
|
}
|
||||||
args.To = ext.To
|
args.To = ext.To
|
||||||
|
|
||||||
var num *big.Int
|
var num *big.Int
|
||||||
@ -884,7 +888,6 @@ type tx struct {
|
|||||||
Data string
|
Data string
|
||||||
GasLimit string
|
GasLimit string
|
||||||
GasPrice string
|
GasPrice string
|
||||||
Hash string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTx(t *types.Transaction) *tx {
|
func newTx(t *types.Transaction) *tx {
|
||||||
@ -903,7 +906,6 @@ func newTx(t *types.Transaction) *tx {
|
|||||||
Data: "0x" + common.Bytes2Hex(t.Data()),
|
Data: "0x" + common.Bytes2Hex(t.Data()),
|
||||||
GasLimit: t.Gas().String(),
|
GasLimit: t.Gas().String(),
|
||||||
GasPrice: t.GasPrice().String(),
|
GasPrice: t.GasPrice().String(),
|
||||||
Hash: t.Hash().Hex(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,12 +931,6 @@ func (tx *tx) UnmarshalJSON(b []byte) (err error) {
|
|||||||
contractCreation = true
|
contractCreation = true
|
||||||
)
|
)
|
||||||
|
|
||||||
if val, found := fields["Hash"]; found {
|
|
||||||
if hashVal, ok := val.(string); ok {
|
|
||||||
tx.Hash = hashVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if val, found := fields["To"]; found {
|
if val, found := fields["To"]; found {
|
||||||
if strVal, ok := val.(string); ok && len(strVal) > 0 {
|
if strVal, ok := val.(string); ok && len(strVal) > 0 {
|
||||||
tx.To = strVal
|
tx.To = strVal
|
||||||
|
@ -32,22 +32,16 @@ var (
|
|||||||
AutoCompletion = map[string][]string{
|
AutoCompletion = map[string][]string{
|
||||||
"admin": []string{
|
"admin": []string{
|
||||||
"addPeer",
|
"addPeer",
|
||||||
"chainSyncStatus",
|
|
||||||
"datadir",
|
|
||||||
"exportChain",
|
|
||||||
"getContractInfo",
|
|
||||||
"importChain",
|
|
||||||
"nodeInfo",
|
|
||||||
"peers",
|
"peers",
|
||||||
"register",
|
"nodeInfo",
|
||||||
"registerUrl",
|
"exportChain",
|
||||||
"setSolc",
|
"importChain",
|
||||||
"sleepBlocks",
|
|
||||||
"startNatSpec",
|
|
||||||
"startRPC",
|
|
||||||
"stopNatSpec",
|
|
||||||
"stopRPC",
|
|
||||||
"verbosity",
|
"verbosity",
|
||||||
|
"chainSyncStatus",
|
||||||
|
"setSolc",
|
||||||
|
"datadir",
|
||||||
|
"startRPC",
|
||||||
|
"stopRPC",
|
||||||
},
|
},
|
||||||
"db": []string{
|
"db": []string{
|
||||||
"getString",
|
"getString",
|
||||||
@ -103,7 +97,6 @@ var (
|
|||||||
"miner": []string{
|
"miner": []string{
|
||||||
"hashrate",
|
"hashrate",
|
||||||
"makeDAG",
|
"makeDAG",
|
||||||
"setEtherbase",
|
|
||||||
"setExtra",
|
"setExtra",
|
||||||
"setGasPrice",
|
"setGasPrice",
|
||||||
"startAutoDAG",
|
"startAutoDAG",
|
||||||
|
@ -17,19 +17,13 @@
|
|||||||
package comms
|
package comms
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
@ -37,15 +31,10 @@ import (
|
|||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
serverIdleTimeout = 10 * time.Second // idle keep-alive connections
|
|
||||||
serverReadTimeout = 15 * time.Second // per-request read timeout
|
|
||||||
serverWriteTimeout = 15 * time.Second // per-request read timeout
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
httpServerMu sync.Mutex
|
// main HTTP rpc listener
|
||||||
httpServer *stopServer
|
httpListener *stoppableTCPListener
|
||||||
|
listenerStoppedError = fmt.Errorf("Listener has stopped")
|
||||||
)
|
)
|
||||||
|
|
||||||
type HttpConfig struct {
|
type HttpConfig struct {
|
||||||
@ -54,172 +43,42 @@ type HttpConfig struct {
|
|||||||
CorsDomain string
|
CorsDomain string
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopServer augments http.Server with idle connection tracking.
|
|
||||||
// Idle keep-alive connections are shut down when Close is called.
|
|
||||||
type stopServer struct {
|
|
||||||
*http.Server
|
|
||||||
l net.Listener
|
|
||||||
// connection tracking state
|
|
||||||
mu sync.Mutex
|
|
||||||
shutdown bool // true when Stop has returned
|
|
||||||
idle map[net.Conn]struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type handler struct {
|
|
||||||
codec codec.Codec
|
|
||||||
api shared.EthereumApi
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartHTTP starts listening for RPC requests sent via HTTP.
|
|
||||||
func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error {
|
func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error {
|
||||||
httpServerMu.Lock()
|
if httpListener != nil {
|
||||||
defer httpServerMu.Unlock()
|
if fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort) != httpListener.Addr().String() {
|
||||||
|
return fmt.Errorf("RPC service already running on %s ", httpListener.Addr().String())
|
||||||
addr := fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort)
|
|
||||||
if httpServer != nil {
|
|
||||||
if addr != httpServer.Addr {
|
|
||||||
return fmt.Errorf("RPC service already running on %s ", httpServer.Addr)
|
|
||||||
}
|
}
|
||||||
return nil // RPC service already running on given host/port
|
return nil // RPC service already running on given host/port
|
||||||
}
|
}
|
||||||
// Set up the request handler, wrapping it with CORS headers if configured.
|
|
||||||
handler := http.Handler(&handler{codec, api})
|
l, err := newStoppableTCPListener(fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort))
|
||||||
if len(cfg.CorsDomain) > 0 {
|
|
||||||
opts := cors.Options{
|
|
||||||
AllowedMethods: []string{"POST"},
|
|
||||||
AllowedOrigins: strings.Split(cfg.CorsDomain, " "),
|
|
||||||
}
|
|
||||||
handler = cors.New(opts).Handler(handler)
|
|
||||||
}
|
|
||||||
// Start the server.
|
|
||||||
s, err := listenHTTP(addr, handler)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", cfg.ListenAddress, cfg.ListenPort, err)
|
glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", cfg.ListenAddress, cfg.ListenPort, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
httpServer = s
|
httpListener = l
|
||||||
|
|
||||||
|
var handler http.Handler
|
||||||
|
if len(cfg.CorsDomain) > 0 {
|
||||||
|
var opts cors.Options
|
||||||
|
opts.AllowedMethods = []string{"POST"}
|
||||||
|
opts.AllowedOrigins = strings.Split(cfg.CorsDomain, " ")
|
||||||
|
|
||||||
|
c := cors.New(opts)
|
||||||
|
handler = newStoppableHandler(c.Handler(gethHttpHandler(codec, api)), l.stop)
|
||||||
|
} else {
|
||||||
|
handler = newStoppableHandler(gethHttpHandler(codec, api), l.stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
go http.Serve(l, handler)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
// Limit request size to resist DoS
|
|
||||||
if req.ContentLength > maxHttpSizeReqLength {
|
|
||||||
err := fmt.Errorf("Request too large")
|
|
||||||
response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
|
|
||||||
sendJSON(w, &response)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer req.Body.Close()
|
|
||||||
payload, err := ioutil.ReadAll(req.Body)
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Could not read request body")
|
|
||||||
response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
|
|
||||||
sendJSON(w, &response)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c := h.codec.New(nil)
|
|
||||||
var rpcReq shared.Request
|
|
||||||
if err = c.Decode(payload, &rpcReq); err == nil {
|
|
||||||
reply, err := h.api.Execute(&rpcReq)
|
|
||||||
res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
|
|
||||||
sendJSON(w, &res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var reqBatch []shared.Request
|
|
||||||
if err = c.Decode(payload, &reqBatch); err == nil {
|
|
||||||
resBatch := make([]*interface{}, len(reqBatch))
|
|
||||||
resCount := 0
|
|
||||||
for i, rpcReq := range reqBatch {
|
|
||||||
reply, err := h.api.Execute(&rpcReq)
|
|
||||||
if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal
|
|
||||||
resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
|
|
||||||
resCount += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// make response omitting nil entries
|
|
||||||
sendJSON(w, resBatch[:resCount])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// invalid request
|
|
||||||
err = fmt.Errorf("Could not decode request")
|
|
||||||
res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err)
|
|
||||||
sendJSON(w, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendJSON(w io.Writer, v interface{}) {
|
|
||||||
if glog.V(logger.Detail) {
|
|
||||||
if payload, err := json.MarshalIndent(v, "", "\t"); err == nil {
|
|
||||||
glog.Infof("Sending payload: %s", payload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := json.NewEncoder(w).Encode(v); err != nil {
|
|
||||||
glog.V(logger.Error).Infoln("Error sending JSON:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop closes all active HTTP connections and shuts down the server.
|
|
||||||
func StopHttp() {
|
func StopHttp() {
|
||||||
httpServerMu.Lock()
|
if httpListener != nil {
|
||||||
defer httpServerMu.Unlock()
|
httpListener.Stop()
|
||||||
if httpServer != nil {
|
httpListener = nil
|
||||||
httpServer.Close()
|
|
||||||
httpServer = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func listenHTTP(addr string, h http.Handler) (*stopServer, error) {
|
|
||||||
l, err := net.Listen("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
l = fdtrack.WrapListener("rpc", l)
|
|
||||||
s := &stopServer{l: l, idle: make(map[net.Conn]struct{})}
|
|
||||||
s.Server = &http.Server{
|
|
||||||
Addr: addr,
|
|
||||||
Handler: h,
|
|
||||||
ReadTimeout: serverReadTimeout,
|
|
||||||
WriteTimeout: serverWriteTimeout,
|
|
||||||
ConnState: s.connState,
|
|
||||||
}
|
|
||||||
go s.Serve(l)
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stopServer) connState(c net.Conn, state http.ConnState) {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
// Close c immediately if we're past shutdown.
|
|
||||||
if s.shutdown {
|
|
||||||
if state != http.StateClosed {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if state == http.StateIdle {
|
|
||||||
s.idle[c] = struct{}{}
|
|
||||||
} else {
|
|
||||||
delete(s.idle, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stopServer) Close() {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
// Shut down the acceptor. No new connections can be created.
|
|
||||||
s.l.Close()
|
|
||||||
// Drop all idle connections. Non-idle connections will be
|
|
||||||
// closed by connState as soon as they become idle.
|
|
||||||
s.shutdown = true
|
|
||||||
for c := range s.idle {
|
|
||||||
glog.V(logger.Detail).Infof("closing idle connection %v", c.RemoteAddr())
|
|
||||||
c.Close()
|
|
||||||
delete(s.idle, c)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
182
rpc/comms/http_net.go
Normal file
182
rpc/comms/http_net.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package comms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
// When https://github.com/golang/go/issues/4674 is implemented this could be replaced
|
||||||
|
type stoppableTCPListener struct {
|
||||||
|
*net.TCPListener
|
||||||
|
stop chan struct{} // closed when the listener must stop
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStoppableTCPListener(addr string) (*stoppableTCPListener, error) {
|
||||||
|
wl, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcpl, ok := wl.(*net.TCPListener); ok {
|
||||||
|
stop := make(chan struct{})
|
||||||
|
return &stoppableTCPListener{tcpl, stop}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Unable to create TCP listener for RPC service")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the listener and all accepted and still active connections.
|
||||||
|
func (self *stoppableTCPListener) Stop() {
|
||||||
|
close(self.stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *stoppableTCPListener) Accept() (net.Conn, error) {
|
||||||
|
for {
|
||||||
|
self.SetDeadline(time.Now().Add(time.Duration(1 * time.Second)))
|
||||||
|
c, err := self.TCPListener.AcceptTCP()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-self.stop:
|
||||||
|
if c != nil { // accept timeout
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
self.TCPListener.Close()
|
||||||
|
return nil, listenerStoppedError
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() && netErr.Temporary() {
|
||||||
|
continue // regular timeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &closableConnection{c, self.stop}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type closableConnection struct {
|
||||||
|
*net.TCPConn
|
||||||
|
closed chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *closableConnection) Read(b []byte) (n int, err error) {
|
||||||
|
select {
|
||||||
|
case <-self.closed:
|
||||||
|
self.TCPConn.Close()
|
||||||
|
return 0, io.EOF
|
||||||
|
default:
|
||||||
|
return self.TCPConn.Read(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wraps the default handler and checks if the RPC service was stopped. In that case it returns an
|
||||||
|
// error indicating that the service was stopped. This will only happen for connections which are
|
||||||
|
// kept open (HTTP keep-alive) when the RPC service was shutdown.
|
||||||
|
func newStoppableHandler(h http.Handler, stop chan struct{}) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
select {
|
||||||
|
case <-stop:
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
err := fmt.Errorf("RPC service stopped")
|
||||||
|
response := shared.NewRpcResponse(-1, shared.JsonRpcVersion, nil, err)
|
||||||
|
httpSend(w, response)
|
||||||
|
default:
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpSend(writer io.Writer, v interface{}) (n int, err error) {
|
||||||
|
var payload []byte
|
||||||
|
payload, err = json.MarshalIndent(v, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infoln("Error marshalling JSON", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
glog.V(logger.Detail).Infof("Sending payload: %s", payload)
|
||||||
|
|
||||||
|
return writer.Write(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gethHttpHandler(codec codec.Codec, a shared.EthereumApi) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
// Limit request size to resist DoS
|
||||||
|
if req.ContentLength > maxHttpSizeReqLength {
|
||||||
|
err := fmt.Errorf("Request too large")
|
||||||
|
response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
|
||||||
|
httpSend(w, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer req.Body.Close()
|
||||||
|
payload, err := ioutil.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Could not read request body")
|
||||||
|
response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
|
||||||
|
httpSend(w, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c := codec.New(nil)
|
||||||
|
var rpcReq shared.Request
|
||||||
|
if err = c.Decode(payload, &rpcReq); err == nil {
|
||||||
|
reply, err := a.Execute(&rpcReq)
|
||||||
|
res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
|
||||||
|
httpSend(w, &res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqBatch []shared.Request
|
||||||
|
if err = c.Decode(payload, &reqBatch); err == nil {
|
||||||
|
resBatch := make([]*interface{}, len(reqBatch))
|
||||||
|
resCount := 0
|
||||||
|
|
||||||
|
for i, rpcReq := range reqBatch {
|
||||||
|
reply, err := a.Execute(&rpcReq)
|
||||||
|
if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal
|
||||||
|
resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
|
||||||
|
resCount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make response omitting nil entries
|
||||||
|
resBatch = resBatch[:resCount]
|
||||||
|
httpSend(w, resBatch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid request
|
||||||
|
err = fmt.Errorf("Could not decode request")
|
||||||
|
res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err)
|
||||||
|
httpSend(w, res)
|
||||||
|
})
|
||||||
|
}
|
@ -22,7 +22,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/fdtrack"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
@ -51,16 +50,15 @@ func (self *ipcClient) reconnect() error {
|
|||||||
func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
|
func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
|
||||||
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
|
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
|
||||||
|
|
||||||
l, err := net.Listen("unix", cfg.Endpoint)
|
l, err := net.ListenUnix("unix", &net.UnixAddr{Name: cfg.Endpoint, Net: "unix"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l = fdtrack.WrapListener("ipc", l)
|
|
||||||
os.Chmod(cfg.Endpoint, 0600)
|
os.Chmod(cfg.Endpoint, 0600)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
conn, err := l.Accept()
|
conn, err := l.AcceptUnix()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err)
|
glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err)
|
||||||
continue
|
continue
|
||||||
|
@ -150,7 +150,7 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error {
|
|||||||
|
|
||||||
// test the block
|
// test the block
|
||||||
if err := runBlockTest(test); err != nil {
|
if err := runBlockTest(test); err != nil {
|
||||||
return fmt.Errorf("%s: %v", name, err)
|
return err
|
||||||
}
|
}
|
||||||
glog.Infoln("Block test passed: ", name)
|
glog.Infoln("Block test passed: ", name)
|
||||||
|
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"preExpDiffIncrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "42",
|
|
||||||
"currentDifficulty" : "1000488"
|
|
||||||
},
|
|
||||||
"preExpDiffDecrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "42",
|
|
||||||
"currentDifficulty" : "999512"
|
|
||||||
},
|
|
||||||
"ExpDiffAtBlock200000Increase" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "200000",
|
|
||||||
"currentDifficulty" : "1000489"
|
|
||||||
},
|
|
||||||
"ExpDiffAtBlock200000Decrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "200000",
|
|
||||||
"currentDifficulty" : "999513"
|
|
||||||
},
|
|
||||||
"ExpDiffPostBlock200000Increase" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "200001",
|
|
||||||
"currentDifficulty" : "1000489"
|
|
||||||
},
|
|
||||||
"ExpDiffPostBlock200000Decrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "200001",
|
|
||||||
"currentDifficulty" : "999513"
|
|
||||||
},
|
|
||||||
"ExpDiffPreBlock300000Increase" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "299999",
|
|
||||||
"currentDifficulty" : "1000489"
|
|
||||||
},
|
|
||||||
"ExpDiffPreBlock300000Decrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "299999",
|
|
||||||
"currentDifficulty" : "999513"
|
|
||||||
},
|
|
||||||
"ExpDiffAtBlock300000Increase" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "300000",
|
|
||||||
"currentDifficulty" : "1000490"
|
|
||||||
},
|
|
||||||
"ExpDiffAtBlock300000Decrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "300000",
|
|
||||||
"currentDifficulty" : "999514"
|
|
||||||
},
|
|
||||||
"ExpDiffPostBlock300000Increase" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "300001",
|
|
||||||
"currentDifficulty" : "1000490"
|
|
||||||
},
|
|
||||||
"ExpDiffPostBlock300000Decrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "300001",
|
|
||||||
"currentDifficulty" : "999514"
|
|
||||||
},
|
|
||||||
"ExpDiffInAYearIncrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "43",
|
|
||||||
"currentBlockNumber" : "2302400",
|
|
||||||
"currentDifficulty" : "3097640"
|
|
||||||
},
|
|
||||||
"ExpDiffInAYearDecrease" : {
|
|
||||||
"parentTimestamp" : "42",
|
|
||||||
"parentDifficulty" : "1000000",
|
|
||||||
"currentTimestamp" : "60",
|
|
||||||
"currentBlockNumber" : "2302400",
|
|
||||||
"currentDifficulty" : "3096664"
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
30
xeth/xeth.go
30
xeth/xeth.go
@ -20,10 +20,8 @@ package xeth
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"regexp"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -47,7 +45,6 @@ var (
|
|||||||
defaultGasPrice = big.NewInt(10000000000000) //150000000000
|
defaultGasPrice = big.NewInt(10000000000000) //150000000000
|
||||||
defaultGas = big.NewInt(90000) //500000
|
defaultGas = big.NewInt(90000) //500000
|
||||||
dappStorePre = []byte("dapp-")
|
dappStorePre = []byte("dapp-")
|
||||||
addrReg = regexp.MustCompile(`^(0x)?[a-fA-F0-9]{40}$`)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// byte will be inferred
|
// byte will be inferred
|
||||||
@ -126,7 +123,7 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth {
|
|||||||
if frontend == nil {
|
if frontend == nil {
|
||||||
xeth.frontend = dummyFrontend{}
|
xeth.frontend = dummyFrontend{}
|
||||||
}
|
}
|
||||||
xeth.state = NewState(xeth, xeth.backend.ChainManager().State())
|
xeth.state = NewState(xeth, xeth.backend.ChainManager().TransState())
|
||||||
|
|
||||||
go xeth.start()
|
go xeth.start()
|
||||||
go xeth.filterManager.Start()
|
go xeth.filterManager.Start()
|
||||||
@ -313,12 +310,7 @@ func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blha
|
|||||||
// some chain, this probably needs to be refactored for more expressiveness
|
// some chain, this probably needs to be refactored for more expressiveness
|
||||||
data, _ := self.backend.ExtraDb().Get(common.FromHex(hash))
|
data, _ := self.backend.ExtraDb().Get(common.FromHex(hash))
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
dtx := new(types.Transaction)
|
tx = types.NewTransactionFromBytes(data)
|
||||||
if err := rlp.DecodeBytes(data, dtx); err != nil {
|
|
||||||
glog.V(logger.Error).Infoln(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tx = dtx
|
|
||||||
} else { // check pending transactions
|
} else { // check pending transactions
|
||||||
tx = self.backend.TxPool().GetTransaction(common.HexToHash(hash))
|
tx = self.backend.TxPool().GetTransaction(common.HexToHash(hash))
|
||||||
}
|
}
|
||||||
@ -781,14 +773,8 @@ func (self *XEth) FromNumber(str string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) PushTx(encodedTx string) (string, error) {
|
func (self *XEth) PushTx(encodedTx string) (string, error) {
|
||||||
tx := new(types.Transaction)
|
tx := types.NewTransactionFromBytes(common.FromHex(encodedTx))
|
||||||
err := rlp.DecodeBytes(common.FromHex(encodedTx), tx)
|
err := self.backend.TxPool().Add(tx)
|
||||||
if err != nil {
|
|
||||||
glog.V(logger.Error).Infoln(err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = self.backend.TxPool().Add(tx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -881,10 +867,6 @@ func (self *XEth) Sign(fromStr, hashStr string, didUnlock bool) (string, error)
|
|||||||
return common.ToHex(sig), nil
|
return common.ToHex(sig), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAddress(addr string) bool {
|
|
||||||
return addrReg.MatchString(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||||
|
|
||||||
// this minimalistic recoding is enough (works for natspec.js)
|
// this minimalistic recoding is enough (works for natspec.js)
|
||||||
@ -894,10 +876,6 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(toStr) > 0 && toStr != "0x" && !isAddress(toStr) {
|
|
||||||
return "", errors.New("Invalid address")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
from = common.HexToAddress(fromStr)
|
from = common.HexToAddress(fromStr)
|
||||||
to = common.HexToAddress(toStr)
|
to = common.HexToAddress(toStr)
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
package xeth
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestIsAddress(t *testing.T) {
|
|
||||||
for _, invalid := range []string{
|
|
||||||
"0x00",
|
|
||||||
"0xNN",
|
|
||||||
"0x00000000000000000000000000000000000000NN",
|
|
||||||
"0xAAar000000000000000000000000000000000000",
|
|
||||||
} {
|
|
||||||
if isAddress(invalid) {
|
|
||||||
t.Error("Expected", invalid, "to be invalid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, valid := range []string{
|
|
||||||
"0x0000000000000000000000000000000000000000",
|
|
||||||
"0xAABBbbCCccff9900000000000000000000000000",
|
|
||||||
"AABBbbCCccff9900000000000000000000000000",
|
|
||||||
} {
|
|
||||||
if !isAddress(valid) {
|
|
||||||
t.Error("Expected", valid, "to be valid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user