mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
Merge pull request #2 from ethereum/master
pull latest changes from go-ethereum
This commit is contained in:
commit
abb644ade2
62 changed files with 548 additions and 219 deletions
29
.travis.yml
29
.travis.yml
|
|
@ -14,11 +14,22 @@ matrix:
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||||
|
|
||||||
# These are the latest Go versions.
|
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.10.x
|
go: 1.10.x
|
||||||
|
script:
|
||||||
|
- sudo modprobe fuse
|
||||||
|
- sudo chmod 666 /dev/fuse
|
||||||
|
- sudo chown root:$USER /etc/fuse.conf
|
||||||
|
- go run build/ci.go install
|
||||||
|
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||||
|
|
||||||
|
# These are the latest Go versions.
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
go: 1.11.x
|
||||||
script:
|
script:
|
||||||
- sudo modprobe fuse
|
- sudo modprobe fuse
|
||||||
- sudo chmod 666 /dev/fuse
|
- sudo chmod 666 /dev/fuse
|
||||||
|
|
@ -27,7 +38,7 @@ matrix:
|
||||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
script:
|
script:
|
||||||
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
|
|
@ -36,7 +47,7 @@ matrix:
|
||||||
# This builder only tests code linters on latest version of Go
|
# This builder only tests code linters on latest version of Go
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
env:
|
env:
|
||||||
- lint
|
- lint
|
||||||
git:
|
git:
|
||||||
|
|
@ -47,7 +58,7 @@ matrix:
|
||||||
# This builder does the Ubuntu PPA upload
|
# This builder does the Ubuntu PPA upload
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
env:
|
env:
|
||||||
- ubuntu-ppa
|
- ubuntu-ppa
|
||||||
git:
|
git:
|
||||||
|
|
@ -66,7 +77,7 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
env:
|
env:
|
||||||
- azure-linux
|
- azure-linux
|
||||||
git:
|
git:
|
||||||
|
|
@ -100,7 +111,7 @@ matrix:
|
||||||
dist: trusty
|
dist: trusty
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
env:
|
env:
|
||||||
- azure-linux-mips
|
- azure-linux-mips
|
||||||
git:
|
git:
|
||||||
|
|
@ -144,7 +155,7 @@ matrix:
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
before_install:
|
before_install:
|
||||||
- curl https://storage.googleapis.com/golang/go1.10.3.linux-amd64.tar.gz | tar -xz
|
- curl https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz | tar -xz
|
||||||
- export PATH=`pwd`/go/bin:$PATH
|
- export PATH=`pwd`/go/bin:$PATH
|
||||||
- export GOROOT=`pwd`/go
|
- export GOROOT=`pwd`/go
|
||||||
- export GOPATH=$HOME/go
|
- export GOPATH=$HOME/go
|
||||||
|
|
@ -161,7 +172,7 @@ matrix:
|
||||||
|
|
||||||
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
- azure-ios
|
- azure-ios
|
||||||
|
|
@ -190,7 +201,7 @@ matrix:
|
||||||
# This builder does the Azure archive purges to avoid accumulating junk
|
# This builder does the Azure archive purges to avoid accumulating junk
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.10.x
|
go: 1.11.x
|
||||||
env:
|
env:
|
||||||
- azure-purge
|
- azure-purge
|
||||||
git:
|
git:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.10-alpine as builder
|
FROM golang:1.11-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.10-alpine as builder
|
FROM golang:1.11-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBac
|
||||||
database := ethdb.NewMemDatabase()
|
database := ethdb.NewMemDatabase()
|
||||||
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
||||||
genesis.MustCommit(database)
|
genesis.MustCommit(database)
|
||||||
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
|
|
||||||
backend := &SimulatedBackend{
|
backend := &SimulatedBackend{
|
||||||
database: database,
|
database: database,
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,12 @@ func NewType(t string) (typ Type, err error) {
|
||||||
return typ, err
|
return typ, err
|
||||||
}
|
}
|
||||||
// parse the type and size of the abi-type.
|
// parse the type and size of the abi-type.
|
||||||
parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
|
matches := typeRegex.FindAllStringSubmatch(t, -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return Type{}, fmt.Errorf("invalid type '%v'", t)
|
||||||
|
}
|
||||||
|
parsedType := matches[0]
|
||||||
|
|
||||||
// varSize is the size of the variable
|
// varSize is the size of the variable
|
||||||
var varSize int
|
var varSize int
|
||||||
if len(parsedType[3]) > 0 {
|
if len(parsedType[3]) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -179,26 +179,34 @@ func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Accou
|
||||||
return key, a, err
|
return key, a, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeKeyFile(file string, content []byte) error {
|
func writeTemporaryKeyFile(file string, content []byte) (string, error) {
|
||||||
// Create the keystore directory with appropriate permissions
|
// Create the keystore directory with appropriate permissions
|
||||||
// in case it is not present yet.
|
// in case it is not present yet.
|
||||||
const dirPerm = 0700
|
const dirPerm = 0700
|
||||||
if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
|
if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
// Atomic write: create a temporary hidden file first
|
// Atomic write: create a temporary hidden file first
|
||||||
// then move it into place. TempFile assigns mode 0600.
|
// then move it into place. TempFile assigns mode 0600.
|
||||||
f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp")
|
f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
if _, err := f.Write(content); err != nil {
|
if _, err := f.Write(content); err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
os.Remove(f.Name())
|
os.Remove(f.Name())
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
return os.Rename(f.Name(), file)
|
return f.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeKeyFile(file string, content []byte) error {
|
||||||
|
name, err := writeTemporaryKeyFile(file, content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.Rename(name, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// keyFileName implements the naming convention for keyfiles:
|
// keyFileName implements the naming convention for keyfiles:
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ type unlocked struct {
|
||||||
// NewKeyStore creates a keystore for the given directory.
|
// NewKeyStore creates a keystore for the given directory.
|
||||||
func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
|
func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
|
||||||
keydir, _ = filepath.Abs(keydir)
|
keydir, _ = filepath.Abs(keydir)
|
||||||
ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP}}
|
ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP, false}}
|
||||||
ks.init(keydir)
|
ks.init(keydir)
|
||||||
return ks
|
return ks
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -72,6 +73,10 @@ type keyStorePassphrase struct {
|
||||||
keysDirPath string
|
keysDirPath string
|
||||||
scryptN int
|
scryptN int
|
||||||
scryptP int
|
scryptP int
|
||||||
|
// skipKeyFileVerification disables the security-feature which does
|
||||||
|
// reads and decrypts any newly created keyfiles. This should be 'false' in all
|
||||||
|
// cases except tests -- setting this to 'true' is not recommended.
|
||||||
|
skipKeyFileVerification bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
|
func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
|
||||||
|
|
@ -93,7 +98,7 @@ func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string)
|
||||||
|
|
||||||
// StoreKey generates a key, encrypts with 'auth' and stores in the given directory
|
// StoreKey generates a key, encrypts with 'auth' and stores in the given directory
|
||||||
func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
|
func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
|
||||||
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, rand.Reader, auth)
|
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP, false}, rand.Reader, auth)
|
||||||
return a.Address, err
|
return a.Address, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +107,25 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return writeKeyFile(filename, keyjson)
|
// Write into temporary file
|
||||||
|
tmpName, err := writeTemporaryKeyFile(filename, keyjson)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ks.skipKeyFileVerification {
|
||||||
|
// Verify that we can decrypt the file with the given password.
|
||||||
|
_, err = ks.GetKey(key.Address, tmpName, auth)
|
||||||
|
if err != nil {
|
||||||
|
msg := "An error was encountered when saving and verifying the keystore file. \n" +
|
||||||
|
"This indicates that the keystore is corrupted. \n" +
|
||||||
|
"The corrupted file is stored at \n%v\n" +
|
||||||
|
"Please file a ticket at:\n\n" +
|
||||||
|
"https://github.com/ethereum/go-ethereum/issues." +
|
||||||
|
"The error was : %s"
|
||||||
|
return fmt.Errorf(msg, tmpName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.Rename(tmpName, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ks keyStorePassphrase) JoinPath(filename string) string {
|
func (ks keyStorePassphrase) JoinPath(filename string) string {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if encrypted {
|
if encrypted {
|
||||||
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP}
|
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP, true}
|
||||||
} else {
|
} else {
|
||||||
ks = &keyStorePlain{d}
|
ks = &keyStorePlain{d}
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +191,7 @@ func TestV1_1(t *testing.T) {
|
||||||
|
|
||||||
func TestV1_2(t *testing.T) {
|
func TestV1_2(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP}
|
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP, true}
|
||||||
addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
|
addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
|
||||||
file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
|
file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
|
||||||
k, err := ks.GetKey(addr, file, "g")
|
k, err := ks.GetKey(addr, file, "g")
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ environment:
|
||||||
install:
|
install:
|
||||||
- git submodule update --init
|
- git submodule update --init
|
||||||
- rmdir C:\go /s /q
|
- rmdir C:\go /s /q
|
||||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.3.windows-%GETH_ARCH%.zip
|
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.windows-%GETH_ARCH%.zip
|
||||||
- 7z x go1.10.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
- 7z x go1.11.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||||
- go version
|
- go version
|
||||||
- gcc --version
|
- gcc --version
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
build/env.sh /usr/lib/go-1.11/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
build/env.sh /usr/lib/go-1.11/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,13 +80,13 @@ func runCmd(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tracer vm.Tracer
|
tracer vm.Tracer
|
||||||
debugLogger *vm.StructLogger
|
debugLogger *vm.StructLogger
|
||||||
statedb *state.StateDB
|
statedb *state.StateDB
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
sender = common.BytesToAddress([]byte("sender"))
|
sender = common.BytesToAddress([]byte("sender"))
|
||||||
receiver = common.BytesToAddress([]byte("receiver"))
|
receiver = common.BytesToAddress([]byte("receiver"))
|
||||||
blockNumber uint64
|
genesisConfig *core.Genesis
|
||||||
)
|
)
|
||||||
if ctx.GlobalBool(MachineFlag.Name) {
|
if ctx.GlobalBool(MachineFlag.Name) {
|
||||||
tracer = NewJSONLogger(logconfig, os.Stdout)
|
tracer = NewJSONLogger(logconfig, os.Stdout)
|
||||||
|
|
@ -98,13 +98,14 @@ func runCmd(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
if ctx.GlobalString(GenesisFlag.Name) != "" {
|
if ctx.GlobalString(GenesisFlag.Name) != "" {
|
||||||
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
|
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
|
||||||
|
genesisConfig = gen
|
||||||
db := ethdb.NewMemDatabase()
|
db := ethdb.NewMemDatabase()
|
||||||
genesis := gen.ToBlock(db)
|
genesis := gen.ToBlock(db)
|
||||||
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
|
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
|
||||||
chainConfig = gen.Config
|
chainConfig = gen.Config
|
||||||
blockNumber = gen.Number
|
|
||||||
} else {
|
} else {
|
||||||
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
|
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
|
||||||
|
genesisConfig = new(core.Genesis)
|
||||||
}
|
}
|
||||||
if ctx.GlobalString(SenderFlag.Name) != "" {
|
if ctx.GlobalString(SenderFlag.Name) != "" {
|
||||||
sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name))
|
sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name))
|
||||||
|
|
@ -156,13 +157,19 @@ func runCmd(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
initialGas := ctx.GlobalUint64(GasFlag.Name)
|
initialGas := ctx.GlobalUint64(GasFlag.Name)
|
||||||
|
if genesisConfig.GasLimit != 0 {
|
||||||
|
initialGas = genesisConfig.GasLimit
|
||||||
|
}
|
||||||
runtimeConfig := runtime.Config{
|
runtimeConfig := runtime.Config{
|
||||||
Origin: sender,
|
Origin: sender,
|
||||||
State: statedb,
|
State: statedb,
|
||||||
GasLimit: initialGas,
|
GasLimit: initialGas,
|
||||||
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
|
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
|
||||||
Value: utils.GlobalBig(ctx, ValueFlag.Name),
|
Value: utils.GlobalBig(ctx, ValueFlag.Name),
|
||||||
BlockNumber: new(big.Int).SetUint64(blockNumber),
|
Difficulty: genesisConfig.Difficulty,
|
||||||
|
Time: new(big.Int).SetUint64(genesisConfig.Timestamp),
|
||||||
|
Coinbase: genesisConfig.Coinbase,
|
||||||
|
BlockNumber: new(big.Int).SetUint64(genesisConfig.Number),
|
||||||
EVMConfig: vm.Config{
|
EVMConfig: vm.Config{
|
||||||
Tracer: tracer,
|
Tracer: tracer,
|
||||||
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
||||||
|
|
|
||||||
|
|
@ -340,9 +340,9 @@ func importPreimages(ctx *cli.Context) error {
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
|
if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||||
utils.Fatalf("Export error: %v\n", err)
|
utils.Fatalf("Import error: %v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Export done in %v\n", time.Since(start))
|
fmt.Printf("Import done in %v\n", time.Since(start))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ var (
|
||||||
utils.NoCompactionFlag,
|
utils.NoCompactionFlag,
|
||||||
utils.GpoBlocksFlag,
|
utils.GpoBlocksFlag,
|
||||||
utils.GpoPercentileFlag,
|
utils.GpoPercentileFlag,
|
||||||
|
utils.EWASMInterpreterFlag,
|
||||||
|
utils.EVMInterpreterFlag,
|
||||||
configFileFlag,
|
configFileFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,8 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
Name: "VIRTUAL MACHINE",
|
Name: "VIRTUAL MACHINE",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
utils.VMEnableDebugFlag,
|
utils.VMEnableDebugFlag,
|
||||||
|
utils.EVMInterpreterFlag,
|
||||||
|
utils.EWASMInterpreterFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ func (w *wizard) deployDashboard() {
|
||||||
pages = append(pages, page)
|
pages = append(pages, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Promt the user to chose one, enter manually or simply not list this service
|
// Prompt the user to chose one, enter manually or simply not list this service
|
||||||
defLabel, defChoice := "don't list", len(pages)+2
|
defLabel, defChoice := "don't list", len(pages)+2
|
||||||
if len(pages) > 0 {
|
if len(pages) > 0 {
|
||||||
defLabel, defChoice = pages[0], 1
|
defLabel, defChoice = pages[0], 1
|
||||||
|
|
|
||||||
|
|
@ -610,6 +610,17 @@ var (
|
||||||
Usage: "InfluxDB `host` tag attached to all measurements",
|
Usage: "InfluxDB `host` tag attached to all measurements",
|
||||||
Value: "localhost",
|
Value: "localhost",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EWASMInterpreterFlag = cli.StringFlag{
|
||||||
|
Name: "vm.ewasm",
|
||||||
|
Usage: "External ewasm configuration (default = built-in interpreter)",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
|
EVMInterpreterFlag = cli.StringFlag{
|
||||||
|
Name: "vm.evm",
|
||||||
|
Usage: "External EVM configuration (default = built-in interpreter)",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeDataDir retrieves the currently requested data directory, terminating
|
// MakeDataDir retrieves the currently requested data directory, terminating
|
||||||
|
|
@ -1184,6 +1195,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
|
||||||
cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
|
cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
|
||||||
|
cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
|
||||||
|
cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// Override any default configs for hard coded networks.
|
// Override any default configs for hard coded networks.
|
||||||
switch {
|
switch {
|
||||||
case ctx.GlobalBool(TestnetFlag.Name):
|
case ctx.GlobalBool(TestnetFlag.Name):
|
||||||
|
|
@ -1379,7 +1398,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
||||||
cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
||||||
}
|
}
|
||||||
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
||||||
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg)
|
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,45 @@ func (d PrettyDuration) String() string {
|
||||||
}
|
}
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrettyAge is a pretty printed version of a time.Duration value that rounds
|
||||||
|
// the values up to a single most significant unit, days/weeks/years included.
|
||||||
|
type PrettyAge time.Time
|
||||||
|
|
||||||
|
// ageUnits is a list of units the age pretty printing uses.
|
||||||
|
var ageUnits = []struct {
|
||||||
|
Size time.Duration
|
||||||
|
Symbol string
|
||||||
|
}{
|
||||||
|
{12 * 30 * 24 * time.Hour, "y"},
|
||||||
|
{30 * 24 * time.Hour, "mo"},
|
||||||
|
{7 * 24 * time.Hour, "w"},
|
||||||
|
{24 * time.Hour, "d"},
|
||||||
|
{time.Hour, "h"},
|
||||||
|
{time.Minute, "m"},
|
||||||
|
{time.Second, "s"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the Stringer interface, allowing pretty printing of duration
|
||||||
|
// values rounded to the most significant time unit.
|
||||||
|
func (t PrettyAge) String() string {
|
||||||
|
// Calculate the time difference and handle the 0 cornercase
|
||||||
|
diff := time.Since(time.Time(t))
|
||||||
|
if diff < time.Second {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
// Accumulate a precision of 3 components before returning
|
||||||
|
result, prec := "", 0
|
||||||
|
|
||||||
|
for _, unit := range ageUnits {
|
||||||
|
if diff > unit.Size {
|
||||||
|
result = fmt.Sprintf("%s%d%s", result, diff/unit.Size, unit.Symbol)
|
||||||
|
diff %= unit.Size
|
||||||
|
|
||||||
|
if prec += 1; prec >= 3 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,11 +134,6 @@ var (
|
||||||
// errRecentlySigned is returned if a header is signed by an authorized entity
|
// errRecentlySigned is returned if a header is signed by an authorized entity
|
||||||
// that already signed a header recently, thus is temporarily not allowed to.
|
// that already signed a header recently, thus is temporarily not allowed to.
|
||||||
errRecentlySigned = errors.New("recently signed")
|
errRecentlySigned = errors.New("recently signed")
|
||||||
|
|
||||||
// errWaitTransactions is returned if an empty block is attempted to be sealed
|
|
||||||
// on an instant chain (0 second period). It's important to refuse these as the
|
|
||||||
// block reward is zero, so an empty block just bloats the chain... fast.
|
|
||||||
errWaitTransactions = errors.New("waiting for transactions")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignerFn is a signer callback function to request a hash to be signed by a
|
// SignerFn is a signer callback function to request a hash to be signed by a
|
||||||
|
|
@ -615,7 +610,8 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
|
||||||
}
|
}
|
||||||
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
|
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
|
||||||
if c.config.Period == 0 && len(block.Transactions()) == 0 {
|
if c.config.Period == 0 && len(block.Transactions()) == 0 {
|
||||||
return errWaitTransactions
|
log.Info("Sealing paused, waiting for transactions")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// Don't hold the signer fields for the entire sealing procedure
|
// Don't hold the signer fields for the entire sealing procedure
|
||||||
c.lock.RLock()
|
c.lock.RLock()
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,7 @@ func TestClique(t *testing.T) {
|
||||||
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||||
}
|
}
|
||||||
// Pass all the headers through clique and ensure tallying succeeds
|
// Pass all the headers through clique and ensure tallying succeeds
|
||||||
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{})
|
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
|
|
||||||
// Time the insertion of the new chain.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -287,7 +287,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{})
|
chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func TestHeaderVerification(t *testing.T) {
|
||||||
headers[i] = block.Header()
|
headers[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{})
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
for i := 0; i < len(blocks); i++ {
|
for i := 0; i < len(blocks); i++ {
|
||||||
|
|
@ -106,11 +106,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) {
|
||||||
var results <-chan error
|
var results <-chan error
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{})
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
} else {
|
} else {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{})
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
||||||
defer runtime.GOMAXPROCS(old)
|
defer runtime.GOMAXPROCS(old)
|
||||||
|
|
||||||
// Start the verifications and immediately abort
|
// Start the verifications and immediately abort
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{})
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"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"
|
||||||
|
|
@ -128,13 +129,14 @@ type BlockChain struct {
|
||||||
validator Validator // block and state validator interface
|
validator Validator // block and state validator interface
|
||||||
vmConfig vm.Config
|
vmConfig vm.Config
|
||||||
|
|
||||||
badBlocks *lru.Cache // Bad block cache
|
badBlocks *lru.Cache // Bad block cache
|
||||||
|
isLocalFn func(common.Address) bool // Function used to determine whether the block author is a local miner account.
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialises the default Ethereum Validator and
|
// available in the database. It initialises the default Ethereum Validator and
|
||||||
// Processor.
|
// Processor.
|
||||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) {
|
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, isLocalFn func(common.Address) bool) (*BlockChain, error) {
|
||||||
if cacheConfig == nil {
|
if cacheConfig == nil {
|
||||||
cacheConfig = &CacheConfig{
|
cacheConfig = &CacheConfig{
|
||||||
TrieNodeLimit: 256 * 1024 * 1024,
|
TrieNodeLimit: 256 * 1024 * 1024,
|
||||||
|
|
@ -154,6 +156,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
triegc: prque.New(nil),
|
triegc: prque.New(nil),
|
||||||
stateCache: state.NewDatabase(db),
|
stateCache: state.NewDatabase(db),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
|
isLocalFn: isLocalFn,
|
||||||
bodyCache: bodyCache,
|
bodyCache: bodyCache,
|
||||||
bodyRLPCache: bodyRLPCache,
|
bodyRLPCache: bodyRLPCache,
|
||||||
blockCache: blockCache,
|
blockCache: blockCache,
|
||||||
|
|
@ -251,9 +254,9 @@ func (bc *BlockChain) loadLastState() error {
|
||||||
blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
|
blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
|
||||||
fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64())
|
fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64())
|
||||||
|
|
||||||
log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd)
|
log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(currentHeader.Time.Int64(), 0)))
|
||||||
log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd)
|
log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(currentBlock.Time().Int64(), 0)))
|
||||||
log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd)
|
log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(currentFastBlock.Time().Int64(), 0)))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -850,13 +853,16 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
}
|
}
|
||||||
bc.mu.Unlock()
|
bc.mu.Unlock()
|
||||||
|
|
||||||
log.Info("Imported new block receipts",
|
context := []interface{}{
|
||||||
"count", stats.processed,
|
"count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
|
||||||
"elapsed", common.PrettyDuration(time.Since(start)),
|
"number", head.Number(), "hash", head.Hash(), "age", common.PrettyAge(time.Unix(head.Time().Int64(), 0)),
|
||||||
"number", head.Number(),
|
|
||||||
"hash", head.Hash(),
|
|
||||||
"size", common.StorageSize(bytes),
|
"size", common.StorageSize(bytes),
|
||||||
"ignored", stats.ignored)
|
}
|
||||||
|
if stats.ignored > 0 {
|
||||||
|
context = append(context, []interface{}{"ignored", stats.ignored}...)
|
||||||
|
}
|
||||||
|
log.Info("Imported new block receipts", context...)
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -964,8 +970,45 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
|
||||||
reorg := externTd.Cmp(localTd) > 0
|
reorg := externTd.Cmp(localTd) > 0
|
||||||
currentBlock = bc.CurrentBlock()
|
currentBlock = bc.CurrentBlock()
|
||||||
if !reorg && externTd.Cmp(localTd) == 0 {
|
if !reorg && externTd.Cmp(localTd) == 0 {
|
||||||
// Split same-difficulty blocks by number, then at random
|
// Split same-difficulty blocks by number, then preferentially select
|
||||||
reorg = block.NumberU64() < currentBlock.NumberU64() || (block.NumberU64() == currentBlock.NumberU64() && mrand.Float64() < 0.5)
|
// the block generated by the local miner as the canonical block.
|
||||||
|
if block.NumberU64() < currentBlock.NumberU64() {
|
||||||
|
reorg = true
|
||||||
|
} else if block.NumberU64() == currentBlock.NumberU64() {
|
||||||
|
if _, ok := bc.engine.(*clique.Clique); ok {
|
||||||
|
// The reason we need to disable the self-reorg preserving for clique
|
||||||
|
// is it can be probable to introduce a deadlock.
|
||||||
|
//
|
||||||
|
// e.g. If there are 7 available signers
|
||||||
|
//
|
||||||
|
// r1 A
|
||||||
|
// r2 B
|
||||||
|
// r3 C
|
||||||
|
// r4 D
|
||||||
|
// r5 A [X] F G
|
||||||
|
// r6 [X]
|
||||||
|
//
|
||||||
|
// In the round5, the inturn signer E is offline, so the worst case
|
||||||
|
// is A, F and G sign the block of round5 and reject the block of opponents
|
||||||
|
// and in the round6, the last available signer B is offline, the whole
|
||||||
|
// network is stuck.
|
||||||
|
reorg = mrand.Float64() < 0.5
|
||||||
|
} else {
|
||||||
|
currentAuthor, err := bc.engine.Author(currentBlock.Header())
|
||||||
|
if err != nil {
|
||||||
|
return NonStatTy, err
|
||||||
|
}
|
||||||
|
blockAuthor, err := bc.engine.Author(block.Header())
|
||||||
|
if err != nil {
|
||||||
|
return NonStatTy, err
|
||||||
|
}
|
||||||
|
var currentLocal, blockLocal bool
|
||||||
|
if bc.isLocalFn != nil {
|
||||||
|
currentLocal, blockLocal = bc.isLocalFn(currentAuthor), bc.isLocalFn(blockAuthor)
|
||||||
|
}
|
||||||
|
reorg = !currentLocal && (blockLocal || mrand.Float64() < 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if reorg {
|
if reorg {
|
||||||
// Reorganise the chain if the parent is not the head block
|
// Reorganise the chain if the parent is not the head block
|
||||||
|
|
@ -1229,8 +1272,13 @@ func (st *insertStats) report(chain []*types.Block, index int, cache common.Stor
|
||||||
context := []interface{}{
|
context := []interface{}{
|
||||||
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
||||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
|
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
|
||||||
"number", end.Number(), "hash", end.Hash(), "cache", cache,
|
"number", end.Number(), "hash", end.Hash(),
|
||||||
}
|
}
|
||||||
|
if timestamp := time.Unix(end.Time().Int64(), 0); time.Since(timestamp) > time.Minute {
|
||||||
|
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||||
|
}
|
||||||
|
context = append(context, []interface{}{"cache", cache}...)
|
||||||
|
|
||||||
if st.queued > 0 {
|
if st.queued > 0 {
|
||||||
context = append(context, []interface{}{"queued", st.queued}...)
|
context = append(context, []interface{}{"queued", st.queued}...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize a fresh chain with only a genesis block
|
// Initialize a fresh chain with only a genesis block
|
||||||
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil)
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
|
@ -523,7 +523,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
blockchain.Stop()
|
blockchain.Stop()
|
||||||
|
|
||||||
// Create a new BlockChain and check that it rolled back the state.
|
// Create a new BlockChain and check that it rolled back the state.
|
||||||
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{})
|
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -635,7 +635,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Import the chain as an archive node for the comparison baseline
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb := ethdb.NewMemDatabase()
|
archiveDb := ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer archive.Stop()
|
defer archive.Stop()
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
|
|
@ -644,7 +644,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb := ethdb.NewMemDatabase()
|
fastDb := ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -722,7 +722,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
archiveDb := ethdb.NewMemDatabase()
|
archiveDb := ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -735,7 +735,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb := ethdb.NewMemDatabase()
|
fastDb := ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -756,7 +756,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
lightDb := ethdb.NewMemDatabase()
|
lightDb := ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(lightDb)
|
gspec.MustCommit(lightDb)
|
||||||
|
|
||||||
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -825,7 +825,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -896,7 +896,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
rmLogsCh := make(chan RemovedLogsEvent)
|
rmLogsCh := make(chan RemovedLogsEvent)
|
||||||
|
|
@ -943,7 +943,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -1072,7 +1072,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1179,7 +1179,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1254,7 +1254,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := ethdb.NewMemDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1298,7 +1298,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := ethdb.NewMemDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1337,7 +1337,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := ethdb.NewMemDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1419,7 +1419,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to create tester chain: %v", err)
|
b.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||||
// TODO(karalabe): This is needed for clique, which depends on multiple blocks.
|
// TODO(karalabe): This is needed for clique, which depends on multiple blocks.
|
||||||
// It's nonetheless ugly to spin up a blockchain here. Get rid of this somehow.
|
// It's nonetheless ugly to spin up a blockchain here. Get rid of this somehow.
|
||||||
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine}
|
b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func ExampleGenerateChain() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
proConf.DAOForkBlock = forkBlock
|
proConf.DAOForkBlock = forkBlock
|
||||||
proConf.DAOForkSupport = true
|
proConf.DAOForkSupport = true
|
||||||
|
|
||||||
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{})
|
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer proBc.Stop()
|
defer proBc.Stop()
|
||||||
|
|
||||||
conDb := ethdb.NewMemDatabase()
|
conDb := ethdb.NewMemDatabase()
|
||||||
|
|
@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
conConf.DAOForkBlock = forkBlock
|
conConf.DAOForkBlock = forkBlock
|
||||||
conConf.DAOForkSupport = false
|
conConf.DAOForkSupport = false
|
||||||
|
|
||||||
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{})
|
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer conBc.Stop()
|
defer conBc.Stop()
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||||
|
|
@ -69,7 +69,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db = ethdb.NewMemDatabase()
|
db = ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{})
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -94,7 +94,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db = ethdb.NewMemDatabase()
|
db = ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{})
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -120,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db = ethdb.NewMemDatabase()
|
db = ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{})
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -140,7 +140,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db = ethdb.NewMemDatabase()
|
db = ethdb.NewMemDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{})
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
|
||||||
|
|
@ -355,7 +355,7 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
||||||
common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
|
common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
|
||||||
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||||
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
|
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
// Advance to block #4, past the homestead transition block of customg.
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
genesis := oldcustomg.MustCommit(db)
|
genesis := oldcustomg.MustCommit(db)
|
||||||
|
|
||||||
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{})
|
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
||||||
|
|
|
||||||
|
|
@ -281,8 +281,18 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCa
|
||||||
}
|
}
|
||||||
// Report some public statistics so the user has a clue what's going on
|
// Report some public statistics so the user has a clue what's going on
|
||||||
last := chain[len(chain)-1]
|
last := chain[len(chain)-1]
|
||||||
log.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
|
|
||||||
"number", last.Number, "hash", last.Hash(), "ignored", stats.ignored)
|
context := []interface{}{
|
||||||
|
"count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
|
||||||
|
"number", last.Number, "hash", last.Hash(),
|
||||||
|
}
|
||||||
|
if timestamp := time.Unix(last.Time.Int64(), 0); time.Since(timestamp) > time.Minute {
|
||||||
|
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||||
|
}
|
||||||
|
if stats.ignored > 0 {
|
||||||
|
context = append(context, []interface{}{"ignored", stats.ignored}...)
|
||||||
|
}
|
||||||
|
log.Info("Imported new block headers", context...)
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,10 +136,28 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
|
||||||
vmConfig: vmConfig,
|
vmConfig: vmConfig,
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
chainRules: chainConfig.Rules(ctx.BlockNumber),
|
chainRules: chainConfig.Rules(ctx.BlockNumber),
|
||||||
interpreters: make([]Interpreter, 1),
|
interpreters: make([]Interpreter, 0, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.interpreters[0] = NewEVMInterpreter(evm, vmConfig)
|
if chainConfig.IsEWASM(ctx.BlockNumber) {
|
||||||
|
// to be implemented by EVM-C and Wagon PRs.
|
||||||
|
// if vmConfig.EWASMInterpreter != "" {
|
||||||
|
// extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":")
|
||||||
|
// path := extIntOpts[0]
|
||||||
|
// options := []string{}
|
||||||
|
// if len(extIntOpts) > 1 {
|
||||||
|
// options = extIntOpts[1..]
|
||||||
|
// }
|
||||||
|
// evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options))
|
||||||
|
// } else {
|
||||||
|
// evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig))
|
||||||
|
// }
|
||||||
|
panic("No supported ewasm interpreter yet.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
|
||||||
|
// as we always want to have the built-in EVM as the failover option.
|
||||||
|
evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig))
|
||||||
evm.interpreter = evm.interpreters[0]
|
evm.interpreter = evm.interpreters[0]
|
||||||
|
|
||||||
return evm
|
return evm
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ type Config struct {
|
||||||
// may be left uninitialised and will be set to the default
|
// may be left uninitialised and will be set to the default
|
||||||
// table.
|
// table.
|
||||||
JumpTable [256]operation
|
JumpTable [256]operation
|
||||||
|
|
||||||
|
// Type of the EWASM interpreter
|
||||||
|
EWASMInterpreter string
|
||||||
|
// Type of the EVM interpreter
|
||||||
|
EVMInterpreter string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpreter is used to run Ethereum based contracts and will utilise the
|
// Interpreter is used to run Ethereum based contracts and will utilise the
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.Block
|
||||||
|
|
||||||
// traceChain configures a new tracer according to the provided configuration, and
|
// traceChain configures a new tracer according to the provided configuration, and
|
||||||
// executes all the transactions contained within. The return value will be one item
|
// executes all the transactions contained within. The return value will be one item
|
||||||
// per transaction, dependent on the requestd tracer.
|
// per transaction, dependent on the requested tracer.
|
||||||
func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
|
func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
|
||||||
// Tracing a chain is a **long** operation, only do with subscriptions
|
// Tracing a chain is a **long** operation, only do with subscriptions
|
||||||
notifier, supported := rpc.NotifierFromContext(ctx)
|
notifier, supported := rpc.NotifierFromContext(ctx)
|
||||||
|
|
|
||||||
|
|
@ -149,10 +149,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion)
|
rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
|
vmConfig = vm.Config{
|
||||||
|
EnablePreimageRecording: config.EnablePreimageRecording,
|
||||||
|
EWASMInterpreter: config.EWASMInterpreter,
|
||||||
|
EVMInterpreter: config.EVMInterpreter,
|
||||||
|
}
|
||||||
cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout}
|
cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout}
|
||||||
)
|
)
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig)
|
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.isMinerAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -339,6 +343,30 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
||||||
return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
|
return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isMinerAccount checks whether the specified address is a miner account.
|
||||||
|
//
|
||||||
|
// This function is used during block chain reorg checking to determine
|
||||||
|
// whether a block is mined by local accounts. We regard two types of
|
||||||
|
// accounts as local account: etherbase and accounts specified via
|
||||||
|
// `txpool.locals` flag.
|
||||||
|
func (s *Ethereum) isMinerAccount(addr common.Address) bool {
|
||||||
|
// Check whether the given address is etherbase.
|
||||||
|
s.lock.RLock()
|
||||||
|
etherbase := s.etherbase
|
||||||
|
s.lock.RUnlock()
|
||||||
|
if addr == etherbase {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Check whether the given address is specified by `txpool.local`
|
||||||
|
// CLI flag.
|
||||||
|
for _, account := range s.config.TxPool.Locals {
|
||||||
|
if account == addr {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// SetEtherbase sets the mining reward address.
|
// SetEtherbase sets the mining reward address.
|
||||||
func (s *Ethereum) SetEtherbase(etherbase common.Address) {
|
func (s *Ethereum) SetEtherbase(etherbase common.Address) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
|
|
@ -371,7 +399,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
s.lock.RUnlock()
|
s.lock.RUnlock()
|
||||||
s.txPool.SetGasPrice(price)
|
s.txPool.SetGasPrice(price)
|
||||||
|
|
||||||
// Configure the local mining addess
|
// Configure the local mining address
|
||||||
eb, err := s.Etherbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot start mining without etherbase", "err", err)
|
log.Error("Cannot start mining without etherbase", "err", err)
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,11 @@ type Config struct {
|
||||||
|
|
||||||
// Miscellaneous options
|
// Miscellaneous options
|
||||||
DocRoot string `toml:"-"`
|
DocRoot string `toml:"-"`
|
||||||
|
|
||||||
|
// Type of the EWASM interpreter ("" for detault)
|
||||||
|
EWASMInterpreter string
|
||||||
|
// Type of the EVM interpreter ("" for default)
|
||||||
|
EVMInterpreter string
|
||||||
}
|
}
|
||||||
|
|
||||||
type configMarshaling struct {
|
type configMarshaling struct {
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ type PublicDownloaderAPI struct {
|
||||||
// installSyncSubscription channel.
|
// installSyncSubscription channel.
|
||||||
func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAPI {
|
func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAPI {
|
||||||
api := &PublicDownloaderAPI{
|
api := &PublicDownloaderAPI{
|
||||||
d: d,
|
d: d,
|
||||||
mux: m,
|
mux: m,
|
||||||
installSyncSubscription: make(chan chan interface{}),
|
installSyncSubscription: make(chan chan interface{}),
|
||||||
uninstallSyncSubscription: make(chan *uninstallSyncSubscriptionRequest),
|
uninstallSyncSubscription: make(chan *uninstallSyncSubscriptionRequest),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,10 +242,10 @@ func testGetBlockBodies(t *testing.T, protocol int) {
|
||||||
available []bool // Availability of explicitly requested blocks
|
available []bool // Availability of explicitly requested blocks
|
||||||
expected int // Total number of existing blocks to expect
|
expected int // Total number of existing blocks to expect
|
||||||
}{
|
}{
|
||||||
{1, nil, nil, 1}, // A single random block should be retrievable
|
{1, nil, nil, 1}, // A single random block should be retrievable
|
||||||
{10, nil, nil, 10}, // Multiple random blocks should be retrievable
|
{10, nil, nil, 10}, // Multiple random blocks should be retrievable
|
||||||
{limit, nil, nil, limit}, // The maximum possible blocks should be retrievable
|
{limit, nil, nil, limit}, // The maximum possible blocks should be retrievable
|
||||||
{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
|
{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
|
||||||
{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable
|
{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable
|
||||||
{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
|
{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
|
||||||
{0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned
|
{0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned
|
||||||
|
|
@ -472,7 +472,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
||||||
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
||||||
gspec = &core.Genesis{Config: config}
|
gspec = &core.Genesis{Config: config}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = core.NewBlockChain(db, nil, config, pow, vm.Config{})
|
blockchain, _ = core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil)
|
||||||
)
|
)
|
||||||
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
|
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
|
||||||
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{})
|
blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
||||||
)
|
)
|
||||||
chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator)
|
chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator)
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -143,9 +143,9 @@ func CopyFile(dst, src string, mode os.FileMode) {
|
||||||
// so that go commands executed by build use the same version of Go as the 'host' that runs
|
// so that go commands executed by build use the same version of Go as the 'host' that runs
|
||||||
// build code. e.g.
|
// build code. e.g.
|
||||||
//
|
//
|
||||||
// /usr/lib/go-1.8/bin/go run build/ci.go ...
|
// /usr/lib/go-1.11/bin/go run build/ci.go ...
|
||||||
//
|
//
|
||||||
// runs using go 1.8 and invokes go 1.8 tools from the same GOROOT. This is also important
|
// runs using go 1.11 and invokes go 1.11 tools from the same GOROOT. This is also important
|
||||||
// because runtime.Version checks on the host should match the tools that are run.
|
// because runtime.Version checks on the host should match the tools that are run.
|
||||||
func GoTool(tool string, args ...string) *exec.Cmd {
|
func GoTool(tool string, args ...string) *exec.Cmd {
|
||||||
args = append([]string{tool}, args...)
|
args = append([]string{tool}, args...)
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,12 @@ type lesCommons struct {
|
||||||
// NodeInfo represents a short summary of the Ethereum sub-protocol metadata
|
// NodeInfo represents a short summary of the Ethereum sub-protocol metadata
|
||||||
// known about the host peer.
|
// known about the host peer.
|
||||||
type NodeInfo struct {
|
type NodeInfo struct {
|
||||||
Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4)
|
Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4)
|
||||||
Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain
|
Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain
|
||||||
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
||||||
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
||||||
Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block
|
Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block
|
||||||
CHT light.TrustedCheckpoint `json:"cht"` // Trused CHT checkpoint for fast catchup
|
CHT params.TrustedCheckpoint `json:"cht"` // Trused CHT checkpoint for fast catchup
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeProtocols creates protocol descriptors for the given LES versions.
|
// makeProtocols creates protocol descriptors for the given LES versions.
|
||||||
|
|
@ -76,7 +76,7 @@ func (c *lesCommons) makeProtocols(versions []uint) []p2p.Protocol {
|
||||||
|
|
||||||
// nodeInfo retrieves some protocol metadata about the running host node.
|
// nodeInfo retrieves some protocol metadata about the running host node.
|
||||||
func (c *lesCommons) nodeInfo() interface{} {
|
func (c *lesCommons) nodeInfo() interface{} {
|
||||||
var cht light.TrustedCheckpoint
|
var cht params.TrustedCheckpoint
|
||||||
sections, _, _ := c.chtIndexer.Sections()
|
sections, _, _ := c.chtIndexer.Sections()
|
||||||
sections2, _, _ := c.bloomTrieIndexer.Sections()
|
sections2, _, _ := c.bloomTrieIndexer.Sections()
|
||||||
|
|
||||||
|
|
@ -98,11 +98,11 @@ func (c *lesCommons) nodeInfo() interface{} {
|
||||||
idxV2 := (sectionIndex+1)*c.iConfig.PairChtSize/c.iConfig.ChtSize - 1
|
idxV2 := (sectionIndex+1)*c.iConfig.PairChtSize/c.iConfig.ChtSize - 1
|
||||||
chtRoot = light.GetChtRoot(c.chainDb, idxV2, sectionHead)
|
chtRoot = light.GetChtRoot(c.chainDb, idxV2, sectionHead)
|
||||||
}
|
}
|
||||||
cht = light.TrustedCheckpoint{
|
cht = params.TrustedCheckpoint{
|
||||||
SectionIdx: sectionIndex,
|
SectionIndex: sectionIndex,
|
||||||
SectionHead: sectionHead,
|
SectionHead: sectionHead,
|
||||||
CHTRoot: chtRoot,
|
CHTRoot: chtRoot,
|
||||||
BloomRoot: light.GetBloomTrieRoot(c.chainDb, sectionIndex, sectionHead),
|
BloomRoot: light.GetBloomTrieRoot(c.chainDb, sectionIndex, sectionHead),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
||||||
if lightSync {
|
if lightSync {
|
||||||
chain, _ = light.NewLightChain(odr, gspec.Config, engine)
|
chain, _ = light.NewLightChain(odr, gspec.Config, engine)
|
||||||
} else {
|
} else {
|
||||||
blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{})
|
blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
||||||
gchain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator)
|
gchain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -478,7 +478,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type BloomReq struct {
|
type BloomReq struct {
|
||||||
BloomTrieNum, BitIdx, SectionIdx, FromLevel uint64
|
BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
|
// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
|
||||||
|
|
@ -487,7 +487,7 @@ type BloomRequest light.BloomRequest
|
||||||
// GetCost returns the cost of the given ODR request according to the serving
|
// GetCost returns the cost of the given ODR request according to the serving
|
||||||
// peer's cost table (implementation of LesOdrRequest)
|
// peer's cost table (implementation of LesOdrRequest)
|
||||||
func (r *BloomRequest) GetCost(peer *peer) uint64 {
|
func (r *BloomRequest) GetCost(peer *peer) uint64 {
|
||||||
return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIdxList))
|
return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanSend tells if a certain peer is suitable for serving the given request
|
// CanSend tells if a certain peer is suitable for serving the given request
|
||||||
|
|
@ -503,13 +503,13 @@ func (r *BloomRequest) CanSend(peer *peer) bool {
|
||||||
|
|
||||||
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
|
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
|
||||||
func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
|
func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
|
||||||
peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList)
|
peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
|
||||||
reqs := make([]HelperTrieReq, len(r.SectionIdxList))
|
reqs := make([]HelperTrieReq, len(r.SectionIndexList))
|
||||||
|
|
||||||
var encNumber [10]byte
|
var encNumber [10]byte
|
||||||
binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
|
binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
|
||||||
|
|
||||||
for i, sectionIdx := range r.SectionIdxList {
|
for i, sectionIdx := range r.SectionIndexList {
|
||||||
binary.BigEndian.PutUint64(encNumber[2:], sectionIdx)
|
binary.BigEndian.PutUint64(encNumber[2:], sectionIdx)
|
||||||
reqs[i] = HelperTrieReq{
|
reqs[i] = HelperTrieReq{
|
||||||
Type: htBloomBits,
|
Type: htBloomBits,
|
||||||
|
|
@ -524,7 +524,7 @@ func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
|
||||||
// returns true and stores results in memory if the message was a valid reply
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// to the request (implementation of LesOdrRequest)
|
||||||
func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
|
func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
|
||||||
log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList)
|
log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
|
||||||
|
|
||||||
// Ensure we have a correct message with a single proof element
|
// Ensure we have a correct message with a single proof element
|
||||||
if msg.MsgType != MsgHelperTrieProofs {
|
if msg.MsgType != MsgHelperTrieProofs {
|
||||||
|
|
@ -535,13 +535,13 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
|
||||||
nodeSet := proofs.NodeSet()
|
nodeSet := proofs.NodeSet()
|
||||||
reads := &readTraceDB{db: nodeSet}
|
reads := &readTraceDB{db: nodeSet}
|
||||||
|
|
||||||
r.BloomBits = make([][]byte, len(r.SectionIdxList))
|
r.BloomBits = make([][]byte, len(r.SectionIndexList))
|
||||||
|
|
||||||
// Verify the proofs
|
// Verify the proofs
|
||||||
var encNumber [10]byte
|
var encNumber [10]byte
|
||||||
binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
|
binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
|
||||||
|
|
||||||
for i, idx := range r.SectionIdxList {
|
for i, idx := range r.SectionIndexList {
|
||||||
binary.BigEndian.PutUint64(encNumber[2:], idx)
|
binary.BigEndian.PutUint64(encNumber[2:], idx)
|
||||||
value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads)
|
value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ func (r *sentReq) stateRequesting() reqStateFn {
|
||||||
// no need to go to stopped state because waiting() already returned false
|
// no need to go to stopped state because waiting() already returned false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case rpSoftTimeout:
|
case rpSoftTimeout, rpDeliveredInvalid:
|
||||||
// last request timed out, try asking a new peer
|
// last request timed out, try asking a new peer
|
||||||
go r.tryRequest()
|
go r.tryRequest()
|
||||||
r.lastReqQueued = true
|
r.lastReqQueued = true
|
||||||
|
|
@ -242,7 +242,11 @@ func (r *sentReq) stateNoMorePeers() reqStateFn {
|
||||||
r.stop(nil)
|
r.stop(nil)
|
||||||
return r.stateStopped
|
return r.stateStopped
|
||||||
}
|
}
|
||||||
return r.stateNoMorePeers
|
if r.waiting() {
|
||||||
|
return r.stateNoMorePeers
|
||||||
|
}
|
||||||
|
r.stop(light.ErrNoPeers)
|
||||||
|
return nil
|
||||||
case <-r.stopCh:
|
case <-r.stopCh:
|
||||||
return r.stateStopped
|
return r.stateStopped
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,19 +118,19 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.
|
||||||
}
|
}
|
||||||
|
|
||||||
// addTrustedCheckpoint adds a trusted checkpoint to the blockchain
|
// addTrustedCheckpoint adds a trusted checkpoint to the blockchain
|
||||||
func (self *LightChain) addTrustedCheckpoint(cp TrustedCheckpoint) {
|
func (self *LightChain) addTrustedCheckpoint(cp *params.TrustedCheckpoint) {
|
||||||
if self.odr.ChtIndexer() != nil {
|
if self.odr.ChtIndexer() != nil {
|
||||||
StoreChtRoot(self.chainDb, cp.SectionIdx, cp.SectionHead, cp.CHTRoot)
|
StoreChtRoot(self.chainDb, cp.SectionIndex, cp.SectionHead, cp.CHTRoot)
|
||||||
self.odr.ChtIndexer().AddCheckpoint(cp.SectionIdx, cp.SectionHead)
|
self.odr.ChtIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead)
|
||||||
}
|
}
|
||||||
if self.odr.BloomTrieIndexer() != nil {
|
if self.odr.BloomTrieIndexer() != nil {
|
||||||
StoreBloomTrieRoot(self.chainDb, cp.SectionIdx, cp.SectionHead, cp.BloomRoot)
|
StoreBloomTrieRoot(self.chainDb, cp.SectionIndex, cp.SectionHead, cp.BloomRoot)
|
||||||
self.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIdx, cp.SectionHead)
|
self.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead)
|
||||||
}
|
}
|
||||||
if self.odr.BloomIndexer() != nil {
|
if self.odr.BloomIndexer() != nil {
|
||||||
self.odr.BloomIndexer().AddCheckpoint(cp.SectionIdx, cp.SectionHead)
|
self.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead)
|
||||||
}
|
}
|
||||||
log.Info("Added trusted checkpoint", "chain", cp.name, "block", (cp.SectionIdx+1)*self.indexerConfig.ChtSize-1, "hash", cp.SectionHead)
|
log.Info("Added trusted checkpoint", "chain", cp.Name, "block", (cp.SectionIndex+1)*self.indexerConfig.ChtSize-1, "hash", cp.SectionHead)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LightChain) getProcInterrupt() bool {
|
func (self *LightChain) getProcInterrupt() bool {
|
||||||
|
|
@ -157,7 +157,7 @@ func (self *LightChain) loadLastState() error {
|
||||||
// Issue a status log and return
|
// Issue a status log and return
|
||||||
header := self.hc.CurrentHeader()
|
header := self.hc.CurrentHeader()
|
||||||
headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
|
headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
|
||||||
log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
|
log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(header.Time.Int64(), 0)))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -488,7 +488,7 @@ func (self *LightChain) SyncCht(ctx context.Context) bool {
|
||||||
|
|
||||||
// Ensure the chain didn't move past the latest block while retrieving it
|
// Ensure the chain didn't move past the latest block while retrieving it
|
||||||
if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() {
|
if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() {
|
||||||
log.Info("Updated latest header based on CHT", "number", header.Number, "hash", header.Hash())
|
log.Info("Updated latest header based on CHT", "number", header.Number, "hash", header.Hash(), "age", common.PrettyAge(time.Unix(header.Time.Int64(), 0)))
|
||||||
self.hc.SetCurrentHeader(header)
|
self.hc.SetCurrentHeader(header)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
16
light/odr.go
16
light/odr.go
|
|
@ -157,18 +157,18 @@ func (req *ChtRequest) StoreResult(db ethdb.Database) {
|
||||||
// BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure
|
// BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure
|
||||||
type BloomRequest struct {
|
type BloomRequest struct {
|
||||||
OdrRequest
|
OdrRequest
|
||||||
Config *IndexerConfig
|
Config *IndexerConfig
|
||||||
BloomTrieNum uint64
|
BloomTrieNum uint64
|
||||||
BitIdx uint
|
BitIdx uint
|
||||||
SectionIdxList []uint64
|
SectionIndexList []uint64
|
||||||
BloomTrieRoot common.Hash
|
BloomTrieRoot common.Hash
|
||||||
BloomBits [][]byte
|
BloomBits [][]byte
|
||||||
Proofs *NodeSet
|
Proofs *NodeSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// StoreResult stores the retrieved data in local database
|
||||||
func (req *BloomRequest) StoreResult(db ethdb.Database) {
|
func (req *BloomRequest) StoreResult(db ethdb.Database) {
|
||||||
for i, sectionIdx := range req.SectionIdxList {
|
for i, sectionIdx := range req.SectionIndexList {
|
||||||
sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1)
|
sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1)
|
||||||
// if we don't have the canonical hash stored for this section head number, we'll still store it under
|
// if we don't have the canonical hash stored for this section head number, we'll still store it under
|
||||||
// a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical
|
// a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{})
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1,
|
r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1,
|
||||||
BitIdx: bitIdx, SectionIdxList: reqList, Config: odr.IndexerConfig()}
|
BitIdx: bitIdx, SectionIndexList: reqList, Config: odr.IndexerConfig()}
|
||||||
if err := odr.Retrieve(ctx, r); err != nil {
|
if err := odr.Retrieve(ctx, r); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -104,38 +104,11 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// trustedCheckpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with
|
|
||||||
// the appropriate section index and head hash. It is used to start light syncing from this checkpoint
|
|
||||||
// and avoid downloading the entire header chain while still being able to securely access old headers/logs.
|
|
||||||
type TrustedCheckpoint struct {
|
|
||||||
name string
|
|
||||||
SectionIdx uint64
|
|
||||||
SectionHead, CHTRoot, BloomRoot common.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// trustedCheckpoints associates each known checkpoint with the genesis hash of the chain it belongs to
|
// trustedCheckpoints associates each known checkpoint with the genesis hash of the chain it belongs to
|
||||||
var trustedCheckpoints = map[common.Hash]TrustedCheckpoint{
|
var trustedCheckpoints = map[common.Hash]*params.TrustedCheckpoint{
|
||||||
params.MainnetGenesisHash: {
|
params.MainnetGenesisHash: params.MainnetTrustedCheckpoint,
|
||||||
name: "mainnet",
|
params.TestnetGenesisHash: params.TestnetTrustedCheckpoint,
|
||||||
SectionIdx: 187,
|
params.RinkebyGenesisHash: params.RinkebyTrustedCheckpoint,
|
||||||
SectionHead: common.HexToHash("e6baa034efa31562d71ff23676512dec6562c1ad0301e08843b907e81958c696"),
|
|
||||||
CHTRoot: common.HexToHash("28001955219719cf06de1b08648969139d123a9835fc760547a1e4dabdabc15a"),
|
|
||||||
BloomRoot: common.HexToHash("395ca2373fc662720ac6b58b3bbe71f68aa0f38b63b2d3553dd32ff3c51eebc4"),
|
|
||||||
},
|
|
||||||
params.TestnetGenesisHash: {
|
|
||||||
name: "ropsten",
|
|
||||||
SectionIdx: 117,
|
|
||||||
SectionHead: common.HexToHash("9529b38631ae30783f56cbe4c3b9f07575b770ecba4f6e20a274b1e2f40fede1"),
|
|
||||||
CHTRoot: common.HexToHash("6f48e9f101f1fac98e7d74fbbcc4fda138358271ffd974d40d2506f0308bb363"),
|
|
||||||
BloomRoot: common.HexToHash("8242342e66e942c0cd893484e6736b9862ceb88b43ca344bb06a8285ac1b6d64"),
|
|
||||||
},
|
|
||||||
params.RinkebyGenesisHash: {
|
|
||||||
name: "rinkeby",
|
|
||||||
SectionIdx: 85,
|
|
||||||
SectionHead: common.HexToHash("92cfa67afc4ad8ab0dcbc6fa49efd14b5b19402442e7317e6bc879d85f89d64d"),
|
|
||||||
CHTRoot: common.HexToHash("2802ec92cd7a54a75bca96afdc666ae7b99e5d96cf8192dcfb09588812f51564"),
|
|
||||||
BloomRoot: common.HexToHash("ebefeb31a9a42866d8cf2d2477704b4c3d7c20d0e4e9b5aaa77f396e016a1263"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -329,7 +302,7 @@ func (b *BloomTrieIndexerBackend) fetchMissingNodes(ctx context.Context, section
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
for bitIndex := range indexCh {
|
for bitIndex := range indexCh {
|
||||||
r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIdxList: []uint64{section - 1}, Config: b.odr.IndexerConfig()}
|
r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIndexList: []uint64{section - 1}, Config: b.odr.IndexerConfig()}
|
||||||
for {
|
for {
|
||||||
if err := b.odr.Retrieve(ctx, r); err == ErrNoPeers {
|
if err := b.odr.Retrieve(ctx, r); err == ErrNoPeers {
|
||||||
// if there are no peers to serve, retry later
|
// if there are no peers to serve, retry later
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func TestNodeIterator(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(fulldb)
|
genesis = gspec.MustCommit(fulldb)
|
||||||
)
|
)
|
||||||
gspec.MustCommit(lightdb)
|
gspec.MustCommit(lightdb)
|
||||||
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{})
|
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ func TestTxPool(t *testing.T) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{})
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
||||||
}
|
}
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{})
|
chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
||||||
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
||||||
|
|
||||||
// Generate a small n-block chain and an uncle block for it
|
// Generate a small n-block chain and an uncle block for it
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,15 @@ var (
|
||||||
Ethash: new(EthashConfig),
|
Ethash: new(EthashConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network.
|
||||||
|
MainnetTrustedCheckpoint = &TrustedCheckpoint{
|
||||||
|
Name: "mainnet",
|
||||||
|
SectionIndex: 193,
|
||||||
|
SectionHead: common.HexToHash("0xc2d574295ecedc4d58530ae24c31a5a98be7d2b3327fba0dd0f4ed3913828a55"),
|
||||||
|
CHTRoot: common.HexToHash("0x5d1027dfae688c77376e842679ceada87fd94738feb9b32ef165473bfbbb317b"),
|
||||||
|
BloomRoot: common.HexToHash("0xd38be1a06aabd568e10957fee4fcc523bc64996bcf31bae3f55f86e0a583919f"),
|
||||||
|
}
|
||||||
|
|
||||||
// TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
|
// TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
|
||||||
TestnetChainConfig = &ChainConfig{
|
TestnetChainConfig = &ChainConfig{
|
||||||
ChainID: big.NewInt(3),
|
ChainID: big.NewInt(3),
|
||||||
|
|
@ -61,6 +70,15 @@ var (
|
||||||
Ethash: new(EthashConfig),
|
Ethash: new(EthashConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network.
|
||||||
|
TestnetTrustedCheckpoint = &TrustedCheckpoint{
|
||||||
|
Name: "testnet",
|
||||||
|
SectionIndex: 123,
|
||||||
|
SectionHead: common.HexToHash("0xa372a53decb68ce453da12bea1c8ee7b568b276aa2aab94d9060aa7c81fc3dee"),
|
||||||
|
CHTRoot: common.HexToHash("0x6b02e7fada79cd2a80d4b3623df9c44384d6647fc127462e1c188ccd09ece87b"),
|
||||||
|
BloomRoot: common.HexToHash("0xf2d27490914968279d6377d42868928632573e823b5d1d4a944cba6009e16259"),
|
||||||
|
}
|
||||||
|
|
||||||
// RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network.
|
// RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network.
|
||||||
RinkebyChainConfig = &ChainConfig{
|
RinkebyChainConfig = &ChainConfig{
|
||||||
ChainID: big.NewInt(4),
|
ChainID: big.NewInt(4),
|
||||||
|
|
@ -79,24 +97,45 @@ var (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network.
|
||||||
|
RinkebyTrustedCheckpoint = &TrustedCheckpoint{
|
||||||
|
Name: "rinkeby",
|
||||||
|
SectionIndex: 91,
|
||||||
|
SectionHead: common.HexToHash("0x435b7b2d8a7922f3b9a522f2fb02730e95e0e1782f0f5443894d5415bba37154"),
|
||||||
|
CHTRoot: common.HexToHash("0x0664bf7ecccfb6775c4eca6f0f264fb5282a22754a2135a1ac4bff2ef02898dd"),
|
||||||
|
BloomRoot: common.HexToHash("0x2a64df2400c3a2cb6400639bb6ed29389abdb4d93e2e525aa7c21f38767cd96f"),
|
||||||
|
}
|
||||||
|
|
||||||
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Ethash consensus.
|
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||||
//
|
//
|
||||||
// This configuration is intentionally not using keyed fields to force anyone
|
// This configuration is intentionally not using keyed fields to force anyone
|
||||||
// adding flags to the config to also have to set these fields.
|
// adding flags to the config to also have to set these fields.
|
||||||
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}
|
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil}
|
||||||
|
|
||||||
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Clique consensus.
|
// and accepted by the Ethereum core developers into the Clique consensus.
|
||||||
//
|
//
|
||||||
// This configuration is intentionally not using keyed fields to force anyone
|
// This configuration is intentionally not using keyed fields to force anyone
|
||||||
// adding flags to the config to also have to set these fields.
|
// adding flags to the config to also have to set these fields.
|
||||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
|
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
|
||||||
|
|
||||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}
|
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil}
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
||||||
|
// BloomTrie) associated with the appropriate section index and head hash. It is
|
||||||
|
// used to start light syncing from this checkpoint and avoid downloading the
|
||||||
|
// entire header chain while still being able to securely access old headers/logs.
|
||||||
|
type TrustedCheckpoint struct {
|
||||||
|
Name string `json:"-"`
|
||||||
|
SectionIndex uint64 `json:"sectionIndex"`
|
||||||
|
SectionHead common.Hash `json:"sectionHead"`
|
||||||
|
CHTRoot common.Hash `json:"chtRoot"`
|
||||||
|
BloomRoot common.Hash `json:"bloomRoot"`
|
||||||
|
}
|
||||||
|
|
||||||
// ChainConfig is the core config which determines the blockchain settings.
|
// ChainConfig is the core config which determines the blockchain settings.
|
||||||
//
|
//
|
||||||
// ChainConfig is stored in the database on a per block basis. This means
|
// ChainConfig is stored in the database on a per block basis. This means
|
||||||
|
|
@ -119,6 +158,7 @@ type ChainConfig struct {
|
||||||
|
|
||||||
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
|
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
|
||||||
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
|
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
|
||||||
|
EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated)
|
||||||
|
|
||||||
// Various consensus engines
|
// Various consensus engines
|
||||||
Ethash *EthashConfig `json:"ethash,omitempty"`
|
Ethash *EthashConfig `json:"ethash,omitempty"`
|
||||||
|
|
@ -204,6 +244,11 @@ func (c *ChainConfig) IsConstantinople(num *big.Int) bool {
|
||||||
return isForked(c.ConstantinopleBlock, num)
|
return isForked(c.ConstantinopleBlock, num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEWASM returns whether num represents a block number after the EWASM fork
|
||||||
|
func (c *ChainConfig) IsEWASM(num *big.Int) bool {
|
||||||
|
return isForked(c.EWASMBlock, num)
|
||||||
|
}
|
||||||
|
|
||||||
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
|
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
|
||||||
//
|
//
|
||||||
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
|
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
|
||||||
|
|
@ -269,6 +314,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi
|
||||||
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
|
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
|
||||||
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
|
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
|
||||||
}
|
}
|
||||||
|
if isForkIncompatible(c.EWASMBlock, newcfg.EWASMBlock, head) {
|
||||||
|
return newCompatError("ewasm fork block", c.EWASMBlock, newcfg.EWASMBlock)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
@ -118,12 +119,7 @@ func wsHandshakeValidator(allowedOrigins []string) func(*websocket.Config, *http
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialWebsocket creates a new RPC client that communicates with a JSON-RPC server
|
func wsGetConfig(endpoint, origin string) (*websocket.Config, error) {
|
||||||
// that is listening on the given endpoint.
|
|
||||||
//
|
|
||||||
// The context is used for the initial connection establishment. It does not
|
|
||||||
// affect subsequent interactions with the client.
|
|
||||||
func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error) {
|
|
||||||
if origin == "" {
|
if origin == "" {
|
||||||
var err error
|
var err error
|
||||||
if origin, err = os.Hostname(); err != nil {
|
if origin, err = os.Hostname(); err != nil {
|
||||||
|
|
@ -140,6 +136,25 @@ func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Location.User != nil {
|
||||||
|
b64auth := base64.StdEncoding.EncodeToString([]byte(config.Location.User.String()))
|
||||||
|
config.Header.Add("Authorization", "Basic "+b64auth)
|
||||||
|
config.Location.User = nil
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialWebsocket creates a new RPC client that communicates with a JSON-RPC server
|
||||||
|
// that is listening on the given endpoint.
|
||||||
|
//
|
||||||
|
// The context is used for the initial connection establishment. It does not
|
||||||
|
// affect subsequent interactions with the client.
|
||||||
|
func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error) {
|
||||||
|
config, err := wsGetConfig(endpoint, origin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return newClient(ctx, func(ctx context.Context) (net.Conn, error) {
|
return newClient(ctx, func(ctx context.Context) (net.Conn, error) {
|
||||||
return wsDialContext(ctx, config)
|
return wsDialContext(ctx, config)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
54
rpc/websocket_test.go
Normal file
54
rpc/websocket_test.go
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2016 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 rpc
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestWSGetConfigNoAuth(t *testing.T) {
|
||||||
|
config, err := wsGetConfig("ws://example.com:1234", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("wsGetConfig failed: %s", err)
|
||||||
|
t.Fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if config.Location.User != nil {
|
||||||
|
t.Log("User should have been stripped from the URL")
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if config.Location.Hostname() != "example.com" ||
|
||||||
|
config.Location.Port() != "1234" || config.Location.Scheme != "ws" {
|
||||||
|
t.Logf("Unexpected URL: %s", config.Location)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWSGetConfigWithBasicAuth(t *testing.T) {
|
||||||
|
config, err := wsGetConfig("wss://testuser:test-PASS_01@example.com:1234", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("wsGetConfig failed: %s", err)
|
||||||
|
t.Fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if config.Location.User != nil {
|
||||||
|
t.Log("User should have been stripped from the URL")
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if config.Header.Get("Authorization") != "Basic dGVzdHVzZXI6dGVzdC1QQVNTXzAx" {
|
||||||
|
t.Log("Basic auth header is incorrect")
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -100,16 +100,6 @@ func TestNewUnpacker(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func TestReflect(t *testing.T) {
|
|
||||||
a := big.NewInt(0)
|
|
||||||
b := new(big.Int).SetBytes([]byte{0x00})
|
|
||||||
if !reflect.DeepEqual(a, b) {
|
|
||||||
t.Fatalf("Nope, %v != %v", a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func TestCalldataDecoding(t *testing.T) {
|
func TestCalldataDecoding(t *testing.T) {
|
||||||
|
|
||||||
// send(uint256) : a52c101e
|
// send(uint256) : a52c101e
|
||||||
|
|
@ -123,7 +113,7 @@ func TestCalldataDecoding(t *testing.T) {
|
||||||
{"type":"function","name":"sam","inputs":[{"name":"a","type":"bytes"},{"name":"a","type":"bool"},{"name":"a","type":"uint256[]"}]}
|
{"type":"function","name":"sam","inputs":[{"name":"a","type":"bytes"},{"name":"a","type":"bool"},{"name":"a","type":"uint256[]"}]}
|
||||||
]`
|
]`
|
||||||
//Expected failures
|
//Expected failures
|
||||||
for _, hexdata := range []string{
|
for i, hexdata := range []string{
|
||||||
"a52c101e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
|
"a52c101e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
|
||||||
"a52c101e000000000000000000000000000000000000000000000000000000000000001200",
|
"a52c101e000000000000000000000000000000000000000000000000000000000000001200",
|
||||||
"a52c101e00000000000000000000000000000000000000000000000000000000000000",
|
"a52c101e00000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
|
@ -145,12 +135,11 @@ func TestCalldataDecoding(t *testing.T) {
|
||||||
} {
|
} {
|
||||||
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
|
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected decoding to fail: %s", hexdata)
|
t.Errorf("test %d: expected decoding to fail: %s", i, hexdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Expected success
|
//Expected success
|
||||||
for _, hexdata := range []string{
|
for i, hexdata := range []string{
|
||||||
// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||||
"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
|
"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
|
||||||
"a52c101e0000000000000000000000000000000000000000000000000000000000000012",
|
"a52c101e0000000000000000000000000000000000000000000000000000000000000012",
|
||||||
|
|
@ -169,7 +158,7 @@ func TestCalldataDecoding(t *testing.T) {
|
||||||
} {
|
} {
|
||||||
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
|
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected failure on input %s:\n %v (%d bytes) ", hexdata, err, len(common.Hex2Bytes(hexdata)))
|
t.Errorf("test %d: unexpected failure on input %s:\n %v (%d bytes) ", i, hexdata, err, len(common.Hex2Bytes(hexdata)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -245,3 +234,18 @@ func TestCustomABI(t *testing.T) {
|
||||||
t.Fatalf("Save failed: should find a match for abi signature after loading from disk")
|
t.Fatalf("Save failed: should find a match for abi signature after loading from disk")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMaliciousAbiStrings(t *testing.T) {
|
||||||
|
tests := []string{
|
||||||
|
"func(uint256,uint256,[]uint256)",
|
||||||
|
"func(uint256,uint256,uint256,)",
|
||||||
|
"func(,uint256,uint256,uint256)",
|
||||||
|
}
|
||||||
|
data := common.Hex2Bytes("4401a6e40000000000000000000000000000000000000000000000000000000000000012")
|
||||||
|
for i, tt := range tests {
|
||||||
|
_, err := testSelector(tt, data)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("test %d: expected error for selector '%v'", i, tt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ type Result struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run calls the RunFunc function while taking care of
|
// Run calls the RunFunc function while taking care of
|
||||||
// cancelation provided through the Context.
|
// cancellation provided through the Context.
|
||||||
func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) {
|
func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) {
|
||||||
//if the option is set to run a HTTP server with the simulation,
|
//if the option is set to run a HTTP server with the simulation,
|
||||||
//init the server and start it
|
//init the server and start it
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// true only when quiting
|
// true only when quitting
|
||||||
if len(hashes) == 0 {
|
if len(hashes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,11 @@ OR distance over finite set of integers).
|
||||||
|
|
||||||
Methods take a comparison operator (pof, proximity order function) to compare two
|
Methods take a comparison operator (pof, proximity order function) to compare two
|
||||||
value types. The default pof assumes Val to be or project to a byte slice using
|
value types. The default pof assumes Val to be or project to a byte slice using
|
||||||
the reverse rank on the MSB first XOR logarithmic disctance.
|
the reverse rank on the MSB first XOR logarithmic distance.
|
||||||
|
|
||||||
If the address space if limited, equality is defined as the maximum proximity order.
|
If the address space if limited, equality is defined as the maximum proximity order.
|
||||||
|
|
||||||
The container offers applicative (funcional) style methods on PO trees:
|
The container offers applicative (functional) style methods on PO trees:
|
||||||
* adding/removing en element
|
* adding/removing en element
|
||||||
* swap (value based add/remove)
|
* swap (value based add/remove)
|
||||||
* merging two PO trees (union)
|
* merging two PO trees (union)
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,8 @@ type NetStore struct {
|
||||||
closeC chan struct{}
|
closeC chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fetcherTimeout = 2 * time.Minute // timeout to cancel the fetcher even if requests are coming in
|
||||||
|
|
||||||
// NewNetStore creates a new NetStore object using the given local store. newFetchFunc is a
|
// NewNetStore creates a new NetStore object using the given local store. newFetchFunc is a
|
||||||
// constructor function that can create a fetch function for a specific chunk address.
|
// constructor function that can create a fetch function for a specific chunk address.
|
||||||
func NewNetStore(store SyncChunkStore, nnf NewNetFetcherFunc) (*NetStore, error) {
|
func NewNetStore(store SyncChunkStore, nnf NewNetFetcherFunc) (*NetStore, error) {
|
||||||
|
|
@ -168,7 +170,7 @@ func (n *NetStore) getOrCreateFetcher(ref Address) *fetcher {
|
||||||
// no fetcher for the given address, we have to create a new one
|
// no fetcher for the given address, we have to create a new one
|
||||||
key := hex.EncodeToString(ref)
|
key := hex.EncodeToString(ref)
|
||||||
// create the context during which fetching is kept alive
|
// create the context during which fetching is kept alive
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithTimeout(context.Background(), fetcherTimeout)
|
||||||
// destroy is called when all requests finish
|
// destroy is called when all requests finish
|
||||||
destroy := func() {
|
destroy := func() {
|
||||||
// remove fetcher from fetchers
|
// remove fetcher from fetchers
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ func (t *BlockTest) Run() error {
|
||||||
return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
|
return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, nil, config, ethash.NewShared(), vm.Config{})
|
chain, err := core.NewBlockChain(db, nil, config, ethash.NewShared(), vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, bl
|
||||||
var err error
|
var err error
|
||||||
var zero common.Hash
|
var zero common.Hash
|
||||||
kl := NewDbKey(lower, zero)
|
kl := NewDbKey(lower, zero)
|
||||||
ku := NewDbKey(upper, zero)
|
ku := NewDbKey(upper+1, zero) // LevelDB is exclusive, while the Whisper API is inclusive
|
||||||
i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil)
|
i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil)
|
||||||
defer i.Release()
|
defer i.Release()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue