mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
c9daec2cbe
315 changed files with 9244 additions and 6857 deletions
46
.github/CONTRIBUTING.md
vendored
46
.github/CONTRIBUTING.md
vendored
|
|
@ -1,16 +1,40 @@
|
|||
# Contributing
|
||||
|
||||
Thank you for considering to help out with the source code! We welcome
|
||||
contributions from anyone on the internet, and are grateful for even the
|
||||
smallest of fixes!
|
||||
|
||||
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a
|
||||
pull request for the maintainers to review and merge into the main code base. If
|
||||
you wish to submit more complex changes though, please check up with the core
|
||||
devs first on [our gitter channel](https://gitter.im/ethereum/go-ethereum) to
|
||||
ensure those changes are in line with the general philosophy of the project
|
||||
and/or get some early feedback which can make both your efforts much lighter as
|
||||
well as our review and merge procedures quick and simple.
|
||||
|
||||
## Coding guidelines
|
||||
|
||||
Please make sure your contributions adhere to our coding guidelines:
|
||||
|
||||
* Code must adhere to the official Go
|
||||
[formatting](https://golang.org/doc/effective_go.html#formatting) guidelines
|
||||
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
* Code must be documented adhering to the official Go
|
||||
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
* Pull requests need to be based on and opened against the `master` branch.
|
||||
* Commit messages should be prefixed with the package(s) they modify.
|
||||
* E.g. "eth, rpc: make trace configs optional"
|
||||
|
||||
## Can I have feature X
|
||||
|
||||
Before you do a feature request please check and make sure that it isn't possible
|
||||
through some other means. The JavaScript enabled console is a powerful feature
|
||||
in the right hands. Please check our [Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
|
||||
Before you submit a feature request, please check and make sure that it isn't
|
||||
possible through some other means. The JavaScript-enabled console is a powerful
|
||||
feature in the right hands. Please check our
|
||||
[Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
|
||||
and help.
|
||||
|
||||
## Contributing
|
||||
## Configuration, dependencies, and tests
|
||||
|
||||
If you'd like to contribute to go-ethereum please fork, fix, commit and
|
||||
send a pull request. Commits which do not comply with the coding standards
|
||||
are ignored (use gofmt!).
|
||||
|
||||
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
|
||||
for more details on configuring your environment, testing, and
|
||||
dependency management.
|
||||
Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
|
||||
for more details on configuring your environment, managing project dependencies
|
||||
and testing procedures.
|
||||
|
|
|
|||
4
.github/no-response.yml
vendored
4
.github/no-response.yml
vendored
|
|
@ -7,5 +7,5 @@ closeComment: >
|
|||
This issue has been automatically closed because there has been no response
|
||||
to our request for more information from the original author. With only the
|
||||
information that is currently in the issue, we don't have enough information
|
||||
to take action. Please reach out if you have or find the answers we need so
|
||||
that we can investigate further.
|
||||
to take action. Please reach out if you have more relevant information or
|
||||
answers to our questions so that we can investigate further.
|
||||
|
|
|
|||
29
.travis.yml
29
.travis.yml
|
|
@ -14,7 +14,6 @@ matrix:
|
|||
- 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
|
||||
|
|
@ -26,8 +25,20 @@ matrix:
|
|||
- 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:
|
||||
- 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
|
||||
|
||||
- os: osx
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
script:
|
||||
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
||||
- go run build/ci.go install
|
||||
|
|
@ -36,7 +47,7 @@ matrix:
|
|||
# This builder only tests code linters on latest version of Go
|
||||
- os: linux
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
env:
|
||||
- lint
|
||||
git:
|
||||
|
|
@ -47,7 +58,7 @@ matrix:
|
|||
# This builder does the Ubuntu PPA upload
|
||||
- os: linux
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
git:
|
||||
|
|
@ -66,7 +77,7 @@ matrix:
|
|||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
|
|
@ -100,7 +111,7 @@ matrix:
|
|||
dist: trusty
|
||||
services:
|
||||
- docker
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
env:
|
||||
- azure-linux-mips
|
||||
git:
|
||||
|
|
@ -144,7 +155,7 @@ matrix:
|
|||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
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 GOROOT=`pwd`/go
|
||||
- export GOPATH=$HOME/go
|
||||
|
|
@ -161,7 +172,7 @@ matrix:
|
|||
|
||||
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||
- os: osx
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
env:
|
||||
- azure-osx
|
||||
- azure-ios
|
||||
|
|
@ -190,7 +201,7 @@ matrix:
|
|||
# This builder does the Azure archive purges to avoid accumulating junk
|
||||
- os: linux
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
go: 1.11.x
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/6874
|
|||
)](https://godoc.org/github.com/ethereum/go-ethereum)
|
||||
[](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
|
||||
[](https://travis-ci.org/ethereum/go-ethereum)
|
||||
[](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://discord.gg/nthXNEv)
|
||||
|
||||
Automated builds are available for stable releases and the unstable master branch.
|
||||
Binary archives are published at https://geth.ethereum.org/downloads/.
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBac
|
|||
database := ethdb.NewMemDatabase()
|
||||
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
||||
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{
|
||||
database: database,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,12 @@ func NewType(t string) (typ Type, err error) {
|
|||
return typ, err
|
||||
}
|
||||
// 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
|
||||
var varSize int
|
||||
if len(parsedType[3]) > 0 {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,17 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
var (
|
||||
maxUint256 = big.NewInt(0).Add(
|
||||
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil),
|
||||
big.NewInt(-1))
|
||||
maxInt256 = big.NewInt(0).Add(
|
||||
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil),
|
||||
big.NewInt(-1))
|
||||
)
|
||||
|
||||
// reads the integer based on its kind
|
||||
func readInteger(kind reflect.Kind, b []byte) interface{} {
|
||||
func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
|
||||
switch kind {
|
||||
case reflect.Uint8:
|
||||
return b[len(b)-1]
|
||||
|
|
@ -45,7 +54,20 @@ func readInteger(kind reflect.Kind, b []byte) interface{} {
|
|||
case reflect.Int64:
|
||||
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
|
||||
default:
|
||||
return new(big.Int).SetBytes(b)
|
||||
// the only case lefts for integer is int256/uint256.
|
||||
// big.SetBytes can't tell if a number is negative, positive on itself.
|
||||
// On EVM, if the returned number > max int256, it is negative.
|
||||
ret := new(big.Int).SetBytes(b)
|
||||
if typ == UintTy {
|
||||
return ret
|
||||
}
|
||||
|
||||
if ret.Cmp(maxInt256) > 0 {
|
||||
ret.Add(maxUint256, big.NewInt(0).Neg(ret))
|
||||
ret.Add(ret, big.NewInt(1))
|
||||
ret.Neg(ret)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +201,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
|||
case StringTy: // variable arrays are written at the end of the return bytes
|
||||
return string(output[begin : begin+end]), nil
|
||||
case IntTy, UintTy:
|
||||
return readInteger(t.Kind, returnOutput), nil
|
||||
return readInteger(t.T, t.Kind, returnOutput), nil
|
||||
case BoolTy:
|
||||
return readBool(returnOutput)
|
||||
case AddressTy:
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ var unpackTests = []unpackTest{
|
|||
enc: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
want: big.NewInt(1),
|
||||
},
|
||||
{
|
||||
def: `[{"type": "int256"}]`,
|
||||
enc: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
want: big.NewInt(-1),
|
||||
},
|
||||
{
|
||||
def: `[{"type": "address"}]`,
|
||||
enc: "0000000000000000000000000100000000000000000000000000000000000000",
|
||||
|
|
|
|||
|
|
@ -179,26 +179,34 @@ func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Accou
|
|||
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
|
||||
// in case it is not present yet.
|
||||
const dirPerm = 0700
|
||||
if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
// Atomic write: create a temporary hidden file first
|
||||
// then move it into place. TempFile assigns mode 0600.
|
||||
f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if _, err := f.Write(content); err != nil {
|
||||
f.Close()
|
||||
os.Remove(f.Name())
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ type unlocked struct {
|
|||
// NewKeyStore creates a keystore for the given directory.
|
||||
func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
|
||||
keydir, _ = filepath.Abs(keydir)
|
||||
ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP}}
|
||||
ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP, false}}
|
||||
ks.init(keydir)
|
||||
return ks
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -72,6 +73,10 @@ type keyStorePassphrase struct {
|
|||
keysDirPath string
|
||||
scryptN 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) {
|
||||
|
|
@ -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
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +107,25 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er
|
|||
if err != nil {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
if encrypted {
|
||||
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP}
|
||||
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP, true}
|
||||
} else {
|
||||
ks = &keyStorePlain{d}
|
||||
}
|
||||
|
|
@ -191,7 +191,7 @@ func TestV1_1(t *testing.T) {
|
|||
|
||||
func TestV1_2(t *testing.T) {
|
||||
t.Parallel()
|
||||
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP}
|
||||
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP, true}
|
||||
addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
|
||||
file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
|
||||
k, err := ks.GetKey(addr, file, "g")
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ environment:
|
|||
install:
|
||||
- git submodule update --init
|
||||
- rmdir C:\go /s /q
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.3.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.10.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.11.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- go version
|
||||
- gcc --version
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||
)
|
||||
|
|
@ -85,7 +86,7 @@ func main() {
|
|||
}
|
||||
|
||||
if *writeAddr {
|
||||
fmt.Printf("%v\n", discover.PubkeyID(&nodeKey.PublicKey))
|
||||
fmt.Printf("%v\n", enode.PubkeyToIDV4(&nodeKey.PublicKey))
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
### Changelog for external API
|
||||
|
||||
#### 4.0.0
|
||||
|
||||
* The external `account_Ecrecover`-method was removed.
|
||||
* The external `account_Import`-method was removed.
|
||||
|
||||
#### 3.0.0
|
||||
|
||||
* The external `account_List`-method was changed to not expose `url`, which contained info about the local filesystem. It now returns only a list of addresses.
|
||||
|
||||
#### 2.0.0
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import (
|
|||
)
|
||||
|
||||
// ExternalAPIVersion -- see extapi_changelog.md
|
||||
const ExternalAPIVersion = "2.0.0"
|
||||
const ExternalAPIVersion = "3.0.0"
|
||||
|
||||
// InternalAPIVersion -- see intapi_changelog.md
|
||||
const InternalAPIVersion = "2.0.0"
|
||||
|
|
@ -70,6 +70,10 @@ var (
|
|||
Value: 4,
|
||||
Usage: "log level to emit to the screen",
|
||||
}
|
||||
advancedMode = cli.BoolFlag{
|
||||
Name: "advanced",
|
||||
Usage: "If enabled, issues warnings instead of rejections for suspicious requests. Default off",
|
||||
}
|
||||
keystoreFlag = cli.StringFlag{
|
||||
Name: "keystore",
|
||||
Value: filepath.Join(node.DefaultDataDir(), "keystore"),
|
||||
|
|
@ -191,6 +195,7 @@ func init() {
|
|||
ruleFlag,
|
||||
stdiouiFlag,
|
||||
testFlag,
|
||||
advancedMode,
|
||||
}
|
||||
app.Action = signer
|
||||
app.Commands = []cli.Command{initCommand, attestCommand, addCredentialCommand}
|
||||
|
|
@ -225,7 +230,7 @@ func initializeSecrets(c *cli.Context) error {
|
|||
if _, err := os.Stat(location); err == nil {
|
||||
return fmt.Errorf("file %v already exists, will not overwrite", location)
|
||||
}
|
||||
err = ioutil.WriteFile(location, masterSeed, 0700)
|
||||
err = ioutil.WriteFile(location, masterSeed, 0400)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -384,7 +389,8 @@ func signer(c *cli.Context) error {
|
|||
c.String(keystoreFlag.Name),
|
||||
c.Bool(utils.NoUSBFlag.Name),
|
||||
ui, db,
|
||||
c.Bool(utils.LightKDFFlag.Name))
|
||||
c.Bool(utils.LightKDFFlag.Name),
|
||||
c.Bool(advancedMode.Name))
|
||||
|
||||
api = apiImpl
|
||||
|
||||
|
|
@ -540,14 +546,14 @@ func readMasterKey(ctx *cli.Context) ([]byte, error) {
|
|||
|
||||
// checkFile is a convenience function to check if a file
|
||||
// * exists
|
||||
// * is mode 0600
|
||||
// * is mode 0400
|
||||
func checkFile(filename string) error {
|
||||
info, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed stat on %s: %v", filename, err)
|
||||
}
|
||||
// Check the unix permission bits
|
||||
if info.Mode().Perm()&077 != 0 {
|
||||
if info.Mode().Perm()&0377 != 0 {
|
||||
return fmt.Errorf("file (%v) has insecure file permissions (%v)", filename, info.Mode().String())
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ INFO [02-21|12:14:38] Ruleset attestation updated sha256=6c21d17374
|
|||
At this point, we then start the signer with the rule-file:
|
||||
|
||||
```text
|
||||
#./signer --rules rules.json
|
||||
#./signer --rules rules.js
|
||||
|
||||
INFO [02-21|12:15:18] Using CLI as UI-channel
|
||||
INFO [02-21|12:15:18] Loaded 4byte db signatures=5509 file=./4byte.json
|
||||
|
|
@ -153,7 +153,7 @@ INFO [02-21|14:36:30] Ruleset attestation updated sha256=2a0cb661da
|
|||
And start the signer:
|
||||
|
||||
```
|
||||
#./signer --rules rules.js
|
||||
#./signer --rules rules.js --rpc
|
||||
|
||||
INFO [02-21|14:41:56] Using CLI as UI-channel
|
||||
INFO [02-21|14:41:56] Loaded 4byte db signatures=5509 file=./4byte.json
|
||||
|
|
@ -190,7 +190,7 @@ INFO [02-21|14:42:56] Op rejected
|
|||
The signer also stores all traffic over the external API in a log file. The last 4 lines shows the two requests and their responses:
|
||||
|
||||
```text
|
||||
#tail audit.log -n 4
|
||||
#tail -n 4 audit.log
|
||||
t=2018-02-21T14:42:41+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49706\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=202062617a6f6e6b2062617a2067617a0a
|
||||
t=2018-02-21T14:42:42+0100 lvl=info msg=Sign api=signer type=response data=93e6161840c3ae1efc26dc68dedab6e8fc233bb3fefa1b4645dbf6609b93dace160572ea4ab33240256bb6d3dadb60dcd9c515d6374d3cf614ee897408d41d541c error=nil
|
||||
t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49708\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=2020626f6e6b2062617a2067617a0a
|
||||
|
|
|
|||
|
|
@ -21,21 +21,33 @@ Private key information can be printed by using the `--private` flag;
|
|||
make sure to use this feature with great caution!
|
||||
|
||||
|
||||
### `ethkey sign <keyfile> <message/file>`
|
||||
### `ethkey signmessage <keyfile> <message/file>`
|
||||
|
||||
Sign the message with a keyfile.
|
||||
It is possible to refer to a file containing the message.
|
||||
To sign a message contained in a file, use the `--msgfile` flag.
|
||||
|
||||
|
||||
### `ethkey verify <address> <signature> <message/file>`
|
||||
### `ethkey verifymessage <address> <signature> <message/file>`
|
||||
|
||||
Verify the signature of the message.
|
||||
It is possible to refer to a file containing the message.
|
||||
To sign a message contained in a file, use the --msgfile flag.
|
||||
|
||||
|
||||
### `ethkey changepassphrase <keyfile>`
|
||||
|
||||
Change the passphrase of a keyfile.
|
||||
use the `--newpasswordfile` to point to the new password file.
|
||||
|
||||
|
||||
## Passphrases
|
||||
|
||||
For every command that uses a keyfile, you will be prompted to provide the
|
||||
passphrase for decrypting the keyfile. To avoid this message, it is possible
|
||||
to pass the passphrase by using the `--passphrase` flag pointing to a file that
|
||||
to pass the passphrase by using the `--passwordfile` flag pointing to a file that
|
||||
contains the passphrase.
|
||||
|
||||
## JSON
|
||||
|
||||
In case you need to output the result in a JSON format, you shall by using the `--json` flag.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ func disasmCmd(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
code := strings.TrimSpace(string(in[:]))
|
||||
code := strings.TrimSpace(string(in))
|
||||
fmt.Printf("%v\n", code)
|
||||
return asm.PrintDisassembled(code)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ func runCmd(ctx *cli.Context) error {
|
|||
chainConfig *params.ChainConfig
|
||||
sender = common.BytesToAddress([]byte("sender"))
|
||||
receiver = common.BytesToAddress([]byte("receiver"))
|
||||
blockNumber uint64
|
||||
genesisConfig *core.Genesis
|
||||
)
|
||||
if ctx.GlobalBool(MachineFlag.Name) {
|
||||
tracer = NewJSONLogger(logconfig, os.Stdout)
|
||||
|
|
@ -98,13 +98,14 @@ func runCmd(ctx *cli.Context) error {
|
|||
}
|
||||
if ctx.GlobalString(GenesisFlag.Name) != "" {
|
||||
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
|
||||
genesisConfig = gen
|
||||
db := ethdb.NewMemDatabase()
|
||||
genesis := gen.ToBlock(db)
|
||||
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
|
||||
chainConfig = gen.Config
|
||||
blockNumber = gen.Number
|
||||
} else {
|
||||
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
|
||||
genesisConfig = new(core.Genesis)
|
||||
}
|
||||
if 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)
|
||||
if genesisConfig.GasLimit != 0 {
|
||||
initialGas = genesisConfig.GasLimit
|
||||
}
|
||||
runtimeConfig := runtime.Config{
|
||||
Origin: sender,
|
||||
State: statedb,
|
||||
GasLimit: initialGas,
|
||||
GasPrice: utils.GlobalBig(ctx, PriceFlag.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{
|
||||
Tracer: tracer,
|
||||
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"golang.org/x/net/websocket"
|
||||
|
|
@ -157,7 +157,8 @@ func main() {
|
|||
if blob, err = ioutil.ReadFile(*accPassFlag); err != nil {
|
||||
log.Crit("Failed to read account password contents", "file", *accPassFlag, "err", err)
|
||||
}
|
||||
pass := string(blob)
|
||||
// Delete trailing newline in password
|
||||
pass := strings.TrimSuffix(string(blob), "\n")
|
||||
|
||||
ks := keystore.NewKeyStore(filepath.Join(os.Getenv("HOME"), ".faucet", "keys"), keystore.StandardScryptN, keystore.StandardScryptP)
|
||||
if blob, err = ioutil.ReadFile(*accJSONFlag); err != nil {
|
||||
|
|
@ -198,6 +199,8 @@ type faucet struct {
|
|||
|
||||
keystore *keystore.KeyStore // Keystore containing the single signer
|
||||
account accounts.Account // Account funding user faucet requests
|
||||
head *types.Header // Current head header of the faucet
|
||||
balance *big.Int // Current balance of the faucet
|
||||
nonce uint64 // Current pending nonce of the faucet
|
||||
price *big.Int // Current gas price to issue funds with
|
||||
|
||||
|
|
@ -252,9 +255,11 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
|
|||
return nil, err
|
||||
}
|
||||
for _, boot := range enodes {
|
||||
old, _ := discover.ParseNode(boot.String())
|
||||
old, err := enode.ParseV4(boot.String())
|
||||
if err != nil {
|
||||
stack.Server().AddPeer(old)
|
||||
}
|
||||
}
|
||||
// Attach to the client and retrieve and interesting metadatas
|
||||
api, err := stack.Attach()
|
||||
if err != nil {
|
||||
|
|
@ -323,33 +328,30 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
|
|||
nonce uint64
|
||||
err error
|
||||
)
|
||||
for {
|
||||
// Attempt to retrieve the stats, may error on no faucet connectivity
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
head, err = f.client.HeaderByNumber(ctx, nil)
|
||||
if err == nil {
|
||||
balance, err = f.client.BalanceAt(ctx, f.account.Address, head.Number)
|
||||
if err == nil {
|
||||
nonce, err = f.client.NonceAt(ctx, f.account.Address, nil)
|
||||
for head == nil || balance == nil {
|
||||
// Retrieve the current stats cached by the faucet
|
||||
f.lock.RLock()
|
||||
if f.head != nil {
|
||||
head = types.CopyHeader(f.head)
|
||||
}
|
||||
if f.balance != nil {
|
||||
balance = new(big.Int).Set(f.balance)
|
||||
}
|
||||
cancel()
|
||||
nonce = f.nonce
|
||||
f.lock.RUnlock()
|
||||
|
||||
// If stats retrieval failed, wait a bit and retry
|
||||
if err != nil {
|
||||
if err = sendError(conn, errors.New("Faucet offline: "+err.Error())); err != nil {
|
||||
if head == nil || balance == nil {
|
||||
// Report the faucet offline until initial stats are ready
|
||||
if err = sendError(conn, errors.New("Faucet offline")); err != nil {
|
||||
log.Warn("Failed to send faucet error to client", "err", err)
|
||||
return
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
continue
|
||||
}
|
||||
// Initial stats reported successfully, proceed with user interaction
|
||||
break
|
||||
}
|
||||
// Send over the initial stats and the latest header
|
||||
if err = send(conn, map[string]interface{}{
|
||||
"funds": balance.Div(balance, ether),
|
||||
"funds": new(big.Int).Div(balance, ether),
|
||||
"funded": nonce,
|
||||
"peers": f.stack.Server().PeerCount(),
|
||||
"requests": f.reqs,
|
||||
|
|
@ -519,6 +521,47 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
|
|||
}
|
||||
}
|
||||
|
||||
// refresh attempts to retrieve the latest header from the chain and extract the
|
||||
// associated faucet balance and nonce for connectivity caching.
|
||||
func (f *faucet) refresh(head *types.Header) error {
|
||||
// Ensure a state update does not run for too long
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// If no header was specified, use the current chain head
|
||||
var err error
|
||||
if head == nil {
|
||||
if head, err = f.client.HeaderByNumber(ctx, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Retrieve the balance, nonce and gas price from the current head
|
||||
var (
|
||||
balance *big.Int
|
||||
nonce uint64
|
||||
price *big.Int
|
||||
)
|
||||
if balance, err = f.client.BalanceAt(ctx, f.account.Address, head.Number); err != nil {
|
||||
return err
|
||||
}
|
||||
if nonce, err = f.client.NonceAt(ctx, f.account.Address, head.Number); err != nil {
|
||||
return err
|
||||
}
|
||||
if price, err = f.client.SuggestGasPrice(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
// Everything succeeded, update the cached stats and eject old requests
|
||||
f.lock.Lock()
|
||||
f.head, f.balance = head, balance
|
||||
f.price, f.nonce = price, nonce
|
||||
for len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() < f.nonce {
|
||||
f.reqs = f.reqs[1:]
|
||||
}
|
||||
f.lock.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loop keeps waiting for interesting events and pushes them out to connected
|
||||
// websockets.
|
||||
func (f *faucet) loop() {
|
||||
|
|
@ -536,45 +579,27 @@ func (f *faucet) loop() {
|
|||
go func() {
|
||||
for head := range update {
|
||||
// New chain head arrived, query the current stats and stream to clients
|
||||
var (
|
||||
balance *big.Int
|
||||
nonce uint64
|
||||
price *big.Int
|
||||
err error
|
||||
)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
balance, err = f.client.BalanceAt(ctx, f.account.Address, head.Number)
|
||||
if err == nil {
|
||||
nonce, err = f.client.NonceAt(ctx, f.account.Address, nil)
|
||||
if err == nil {
|
||||
price, err = f.client.SuggestGasPrice(ctx)
|
||||
timestamp := time.Unix(head.Time.Int64(), 0)
|
||||
if time.Since(timestamp) > time.Hour {
|
||||
log.Warn("Skipping faucet refresh, head too old", "number", head.Number, "hash", head.Hash(), "age", common.PrettyAge(timestamp))
|
||||
continue
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
|
||||
// If querying the data failed, try for the next block
|
||||
if err != nil {
|
||||
if err := f.refresh(head); err != nil {
|
||||
log.Warn("Failed to update faucet state", "block", head.Number, "hash", head.Hash(), "err", err)
|
||||
continue
|
||||
} else {
|
||||
log.Info("Updated faucet state", "block", head.Number, "hash", head.Hash(), "balance", balance, "nonce", nonce, "price", price)
|
||||
}
|
||||
// Faucet state retrieved, update locally and send to clients
|
||||
balance = new(big.Int).Div(balance, ether)
|
||||
|
||||
f.lock.Lock()
|
||||
f.price, f.nonce = price, nonce
|
||||
for len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() < f.nonce {
|
||||
f.reqs = f.reqs[1:]
|
||||
}
|
||||
f.lock.Unlock()
|
||||
|
||||
f.lock.RLock()
|
||||
log.Info("Updated faucet state", "number", head.Number, "hash", head.Hash(), "age", common.PrettyAge(timestamp), "balance", f.balance, "nonce", f.nonce, "price", f.price)
|
||||
|
||||
balance := new(big.Int).Div(f.balance, ether)
|
||||
peers := f.stack.Server().PeerCount()
|
||||
|
||||
for _, conn := range f.conns {
|
||||
if err := send(conn, map[string]interface{}{
|
||||
"funds": balance,
|
||||
"funded": f.nonce,
|
||||
"peers": f.stack.Server().PeerCount(),
|
||||
"peers": peers,
|
||||
"requests": f.reqs,
|
||||
}, time.Second); err != nil {
|
||||
log.Warn("Failed to send stats to client", "err", err)
|
||||
|
|
|
|||
|
|
@ -340,9 +340,9 @@ func importPreimages(ctx *cli.Context) error {
|
|||
|
||||
start := time.Now()
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,6 +168,9 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
|||
if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
|
||||
cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name)
|
||||
}
|
||||
if ctx.GlobalIsSet(utils.WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
|
||||
cfg.Shh.RestrictConnectionBetweenLightClients = true
|
||||
}
|
||||
utils.RegisterShhService(stack, &cfg.Shh)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,8 @@ var (
|
|||
utils.NoCompactionFlag,
|
||||
utils.GpoBlocksFlag,
|
||||
utils.GpoPercentileFlag,
|
||||
utils.EWASMInterpreterFlag,
|
||||
utils.EVMInterpreterFlag,
|
||||
configFileFlag,
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +155,7 @@ var (
|
|||
utils.WhisperEnabledFlag,
|
||||
utils.WhisperMaxMessageSizeFlag,
|
||||
utils.WhisperMinPOWFlag,
|
||||
utils.WhisperRestrictConnectionBetweenLightClientsFlag,
|
||||
}
|
||||
|
||||
metricsFlags = []cli.Flag{
|
||||
|
|
|
|||
|
|
@ -208,6 +208,8 @@ var AppHelpFlagGroups = []flagGroup{
|
|||
Name: "VIRTUAL MACHINE",
|
||||
Flags: []cli.Flag{
|
||||
utils.VMEnableDebugFlag,
|
||||
utils.EVMInterpreterFlag,
|
||||
utils.EWASMInterpreterFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
|
@ -285,7 +285,7 @@ func createNode(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.ID = discover.PubkeyID(&privKey.PublicKey)
|
||||
config.ID = enode.PubkeyToIDV4(&privKey.PublicKey)
|
||||
config.PrivateKey = privKey
|
||||
}
|
||||
if services := ctx.String("services"); services != "" {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ func (w *wizard) deployDashboard() {
|
|||
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
|
||||
if len(pages) > 0 {
|
||||
defLabel, defChoice = pages[0], 1
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ func (w *wizard) makeServer() string {
|
|||
return input
|
||||
}
|
||||
|
||||
// selectServer lists the user all the currnetly known servers to choose from,
|
||||
// selectServer lists the user all the currently known servers to choose from,
|
||||
// also granting the option to add a new one.
|
||||
func (w *wizard) selectServer() string {
|
||||
// List the available server to the user and wait for a choice
|
||||
|
|
@ -115,7 +115,7 @@ func (w *wizard) selectServer() string {
|
|||
// manageComponents displays a list of network components the user can tear down
|
||||
// and an option
|
||||
func (w *wizard) manageComponents() {
|
||||
// List all the componens we can tear down, along with an entry to deploy a new one
|
||||
// List all the components we can tear down, along with an entry to deploy a new one
|
||||
fmt.Println()
|
||||
|
||||
var serviceHosts, serviceNames []string
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func accessNewPass(ctx *cli.Context) {
|
|||
password = getPassPhrase("", 0, makePasswordList(ctx))
|
||||
dryRun = ctx.Bool(SwarmDryRunFlag.Name)
|
||||
)
|
||||
accessKey, ae, err = api.DoPasswordNew(ctx, password, salt)
|
||||
accessKey, ae, err = api.DoPassword(ctx, password, salt)
|
||||
if err != nil {
|
||||
utils.Fatalf("error getting session key: %v", err)
|
||||
}
|
||||
|
|
@ -62,7 +62,6 @@ func accessNewPass(ctx *cli.Context) {
|
|||
utils.Fatalf("had an error printing the manifests: %v", err)
|
||||
}
|
||||
} else {
|
||||
utils.Fatalf("uploading manifests")
|
||||
err = uploadManifests(ctx, m, nil)
|
||||
if err != nil {
|
||||
utils.Fatalf("had an error uploading the manifests: %v", err)
|
||||
|
|
@ -85,7 +84,7 @@ func accessNewPK(ctx *cli.Context) {
|
|||
granteePublicKey = ctx.String(SwarmAccessGrantKeyFlag.Name)
|
||||
dryRun = ctx.Bool(SwarmDryRunFlag.Name)
|
||||
)
|
||||
sessionKey, ae, err = api.DoPKNew(ctx, privateKey, granteePublicKey, salt)
|
||||
sessionKey, ae, err = api.DoPK(ctx, privateKey, granteePublicKey, salt)
|
||||
if err != nil {
|
||||
utils.Fatalf("error getting session key: %v", err)
|
||||
}
|
||||
|
|
@ -115,18 +114,33 @@ func accessNewACT(ctx *cli.Context) {
|
|||
accessKey []byte
|
||||
err error
|
||||
ref = args[0]
|
||||
grantees = []string{}
|
||||
actFilename = ctx.String(SwarmAccessGrantKeysFlag.Name)
|
||||
pkGrantees = []string{}
|
||||
passGrantees = []string{}
|
||||
pkGranteesFilename = ctx.String(SwarmAccessGrantKeysFlag.Name)
|
||||
passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name)
|
||||
privateKey = getPrivKey(ctx)
|
||||
dryRun = ctx.Bool(SwarmDryRunFlag.Name)
|
||||
)
|
||||
if pkGranteesFilename == "" && passGranteesFilename == "" {
|
||||
utils.Fatalf("you have to provide either a grantee public-keys file or an encryption passwords file (or both)")
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadFile(actFilename)
|
||||
if pkGranteesFilename != "" {
|
||||
bytes, err := ioutil.ReadFile(pkGranteesFilename)
|
||||
if err != nil {
|
||||
utils.Fatalf("had an error reading the grantee public key list")
|
||||
}
|
||||
grantees = strings.Split(string(bytes), "\n")
|
||||
accessKey, ae, actManifest, err = api.DoACTNew(ctx, privateKey, salt, grantees)
|
||||
pkGrantees = strings.Split(string(bytes), "\n")
|
||||
}
|
||||
|
||||
if passGranteesFilename != "" {
|
||||
bytes, err := ioutil.ReadFile(passGranteesFilename)
|
||||
if err != nil {
|
||||
utils.Fatalf("could not read password filename: %v", err)
|
||||
}
|
||||
passGrantees = strings.Split(string(bytes), "\n")
|
||||
}
|
||||
accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees)
|
||||
if err != nil {
|
||||
utils.Fatalf("error generating ACT manifest: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,18 +28,26 @@ import (
|
|||
gorand "math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/swarm/api"
|
||||
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
|
||||
"github.com/ethereum/go-ethereum/swarm/testutil"
|
||||
)
|
||||
|
||||
const (
|
||||
hashRegexp = `[a-f\d]{128}`
|
||||
data = "notsorandomdata"
|
||||
)
|
||||
|
||||
var DefaultCurve = crypto.S256()
|
||||
|
||||
// TestAccessPassword tests for the correct creation of an ACT manifest protected by a password.
|
||||
// The test creates bogus content, uploads it encrypted, then creates the wrapping manifest with the Access entry
|
||||
// The parties participating - node (publisher), uploads to second node then disappears. Content which was uploaded
|
||||
|
|
@ -50,23 +58,8 @@ func TestAccessPassword(t *testing.T) {
|
|||
defer cluster.Shutdown()
|
||||
proxyNode := cluster.Nodes[0]
|
||||
|
||||
// create a tmp file
|
||||
tmp, err := ioutil.TempDir("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
// write data to file
|
||||
data := "notsorandomdata"
|
||||
dataFilename := filepath.Join(tmp, "data.txt")
|
||||
|
||||
err = ioutil.WriteFile(dataFilename, []byte(data), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hashRegexp := `[a-f\d]{128}`
|
||||
dataFilename := testutil.TempFileWithContent(t, data)
|
||||
defer os.RemoveAll(dataFilename)
|
||||
|
||||
// upload the file with 'swarm up' and expect a hash
|
||||
up := runSwarm(t,
|
||||
|
|
@ -83,14 +76,14 @@ func TestAccessPassword(t *testing.T) {
|
|||
}
|
||||
|
||||
ref := matches[0]
|
||||
|
||||
password := "smth"
|
||||
passwordFilename := filepath.Join(tmp, "password.txt")
|
||||
|
||||
err = ioutil.WriteFile(passwordFilename, []byte(password), 0666)
|
||||
tmp, err := ioutil.TempDir("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
password := "smth"
|
||||
passwordFilename := testutil.TempFileWithContent(t, "smth")
|
||||
defer os.RemoveAll(passwordFilename)
|
||||
|
||||
up = runSwarm(t,
|
||||
"access",
|
||||
|
|
@ -142,7 +135,9 @@ func TestAccessPassword(t *testing.T) {
|
|||
if a.KdfParams == nil {
|
||||
t.Fatal("manifest access kdf params is nil")
|
||||
}
|
||||
|
||||
if a.Publisher != "" {
|
||||
t.Fatal("should be empty")
|
||||
}
|
||||
client := swarm.NewClient(cluster.Nodes[0].URL)
|
||||
|
||||
hash, err := client.UploadManifest(&m, false)
|
||||
|
|
@ -188,12 +183,8 @@ func TestAccessPassword(t *testing.T) {
|
|||
t.Errorf("expected decrypted data %q, got %q", data, string(d))
|
||||
}
|
||||
|
||||
wrongPasswordFilename := filepath.Join(tmp, "password-wrong.txt")
|
||||
|
||||
err = ioutil.WriteFile(wrongPasswordFilename, []byte("just wr0ng"), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wrongPasswordFilename := testutil.TempFileWithContent(t, "just wr0ng")
|
||||
defer os.RemoveAll(wrongPasswordFilename)
|
||||
|
||||
//download file with 'swarm down' with wrong password
|
||||
up = runSwarm(t,
|
||||
|
|
@ -219,25 +210,11 @@ func TestAccessPassword(t *testing.T) {
|
|||
// the test will fail if the proxy's given private key is not granted on the ACT.
|
||||
func TestAccessPK(t *testing.T) {
|
||||
// Setup Swarm and upload a test file to it
|
||||
cluster := newTestCluster(t, 1)
|
||||
cluster := newTestCluster(t, 2)
|
||||
defer cluster.Shutdown()
|
||||
|
||||
// create a tmp file
|
||||
tmp, err := ioutil.TempFile("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tmp.Close()
|
||||
defer os.Remove(tmp.Name())
|
||||
|
||||
// write data to file
|
||||
data := "notsorandomdata"
|
||||
_, err = io.WriteString(tmp, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hashRegexp := `[a-f\d]{128}`
|
||||
dataFilename := testutil.TempFileWithContent(t, data)
|
||||
defer os.RemoveAll(dataFilename)
|
||||
|
||||
// upload the file with 'swarm up' and expect a hash
|
||||
up := runSwarm(t,
|
||||
|
|
@ -245,7 +222,7 @@ func TestAccessPK(t *testing.T) {
|
|||
cluster.Nodes[0].URL,
|
||||
"up",
|
||||
"--encrypt",
|
||||
tmp.Name())
|
||||
dataFilename)
|
||||
_, matches := up.ExpectRegexp(hashRegexp)
|
||||
up.ExpectExit()
|
||||
|
||||
|
|
@ -254,7 +231,6 @@ func TestAccessPK(t *testing.T) {
|
|||
}
|
||||
|
||||
ref := matches[0]
|
||||
|
||||
pk := cluster.Nodes[0].PrivateKey
|
||||
granteePubKey := crypto.CompressPubkey(&pk.PublicKey)
|
||||
|
||||
|
|
@ -263,22 +239,15 @@ func TestAccessPK(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
passFile, err := ioutil.TempFile("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer passFile.Close()
|
||||
defer os.Remove(passFile.Name())
|
||||
_, err = io.WriteString(passFile, testPassphrase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
passwordFilename := testutil.TempFileWithContent(t, testPassphrase)
|
||||
defer os.RemoveAll(passwordFilename)
|
||||
|
||||
_, publisherAccount := getTestAccount(t, publisherDir)
|
||||
up = runSwarm(t,
|
||||
"--bzzaccount",
|
||||
publisherAccount.Address.String(),
|
||||
"--password",
|
||||
passFile.Name(),
|
||||
passwordFilename,
|
||||
"--datadir",
|
||||
publisherDir,
|
||||
"--bzzapi",
|
||||
|
|
@ -299,6 +268,20 @@ func TestAccessPK(t *testing.T) {
|
|||
t.Fatalf("stdout not matched")
|
||||
}
|
||||
|
||||
//get the public key from the publisher directory
|
||||
publicKeyFromDataDir := runSwarm(t,
|
||||
"--bzzaccount",
|
||||
publisherAccount.Address.String(),
|
||||
"--password",
|
||||
passwordFilename,
|
||||
"--datadir",
|
||||
publisherDir,
|
||||
"print-keys",
|
||||
"--compressed",
|
||||
)
|
||||
_, publicKeyString := publicKeyFromDataDir.ExpectRegexp(".+")
|
||||
publicKeyFromDataDir.ExpectExit()
|
||||
pkComp := strings.Split(publicKeyString[0], "=")[1]
|
||||
var m api.Manifest
|
||||
|
||||
err = json.Unmarshal([]byte(matches[0]), &m)
|
||||
|
|
@ -332,7 +315,9 @@ func TestAccessPK(t *testing.T) {
|
|||
if a.KdfParams != nil {
|
||||
t.Fatal("manifest access kdf params should be nil")
|
||||
}
|
||||
|
||||
if a.Publisher != pkComp {
|
||||
t.Fatal("publisher key did not match")
|
||||
}
|
||||
client := swarm.NewClient(cluster.Nodes[0].URL)
|
||||
|
||||
hash, err := client.UploadManifest(&m, false)
|
||||
|
|
@ -359,36 +344,34 @@ func TestAccessPK(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestAccessACT tests the e2e creation, uploading and downloading of an ACT type access control
|
||||
// the test fires up a 3 node cluster, then randomly picks 2 nodes which will be acting as grantees to the data
|
||||
// set. the third node should fail decoding the reference as it will not be granted access. the publisher uploads through
|
||||
// one of the nodes then disappears.
|
||||
// TestAccessACT tests the creation of the ACT manifest end-to-end, without any bogus entries (i.e. default scenario = 3 nodes 1 unauthorized)
|
||||
func TestAccessACT(t *testing.T) {
|
||||
testAccessACT(t, 0)
|
||||
}
|
||||
|
||||
// TestAccessACTScale tests the creation of the ACT manifest end-to-end, with 1000 bogus entries (i.e. 1000 EC keys + default scenario = 3 nodes 1 unauthorized = 1003 keys in the ACT manifest)
|
||||
func TestAccessACTScale(t *testing.T) {
|
||||
testAccessACT(t, 1000)
|
||||
}
|
||||
|
||||
// TestAccessACT tests the e2e creation, uploading and downloading of an ACT access control with both EC keys AND password protection
|
||||
// the test fires up a 3 node cluster, then randomly picks 2 nodes which will be acting as grantees to the data
|
||||
// set and also protects the ACT with a password. the third node should fail decoding the reference as it will not be granted access.
|
||||
// the third node then then tries to download using a correct password (and succeeds) then uses a wrong password and fails.
|
||||
// the publisher uploads through one of the nodes then disappears.
|
||||
func testAccessACT(t *testing.T, bogusEntries int) {
|
||||
// Setup Swarm and upload a test file to it
|
||||
cluster := newTestCluster(t, 3)
|
||||
const clusterSize = 3
|
||||
cluster := newTestCluster(t, clusterSize)
|
||||
defer cluster.Shutdown()
|
||||
|
||||
var uploadThroughNode = cluster.Nodes[0]
|
||||
client := swarm.NewClient(uploadThroughNode.URL)
|
||||
|
||||
r1 := gorand.New(gorand.NewSource(time.Now().UnixNano()))
|
||||
nodeToSkip := r1.Intn(3) // a number between 0 and 2 (node indices in `cluster`)
|
||||
// create a tmp file
|
||||
tmp, err := ioutil.TempFile("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tmp.Close()
|
||||
defer os.Remove(tmp.Name())
|
||||
|
||||
// write data to file
|
||||
data := "notsorandomdata"
|
||||
_, err = io.WriteString(tmp, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hashRegexp := `[a-f\d]{128}`
|
||||
nodeToSkip := r1.Intn(clusterSize) // a number between 0 and 2 (node indices in `cluster`)
|
||||
dataFilename := testutil.TempFileWithContent(t, data)
|
||||
defer os.RemoveAll(dataFilename)
|
||||
|
||||
// upload the file with 'swarm up' and expect a hash
|
||||
up := runSwarm(t,
|
||||
|
|
@ -396,7 +379,7 @@ func TestAccessACT(t *testing.T) {
|
|||
cluster.Nodes[0].URL,
|
||||
"up",
|
||||
"--encrypt",
|
||||
tmp.Name())
|
||||
dataFilename)
|
||||
_, matches := up.ExpectRegexp(hashRegexp)
|
||||
up.ExpectExit()
|
||||
|
||||
|
|
@ -415,41 +398,42 @@ func TestAccessACT(t *testing.T) {
|
|||
grantees = append(grantees, hex.EncodeToString(granteePubKey))
|
||||
}
|
||||
|
||||
granteesPubkeyListFile, err := ioutil.TempFile("", "grantees-pubkey-list.csv")
|
||||
if bogusEntries > 0 {
|
||||
bogusGrantees := []string{}
|
||||
|
||||
for i := 0; i < bogusEntries; i++ {
|
||||
prv, err := ecies.GenerateKey(rand.Reader, DefaultCurve, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = granteesPubkeyListFile.WriteString(strings.Join(grantees, "\n"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
bogusGrantees = append(bogusGrantees, hex.EncodeToString(crypto.CompressPubkey(&prv.ExportECDSA().PublicKey)))
|
||||
}
|
||||
|
||||
defer granteesPubkeyListFile.Close()
|
||||
defer os.Remove(granteesPubkeyListFile.Name())
|
||||
r2 := gorand.New(gorand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < len(grantees); i++ {
|
||||
insertAtIdx := r2.Intn(len(bogusGrantees))
|
||||
bogusGrantees = append(bogusGrantees[:insertAtIdx], append([]string{grantees[i]}, bogusGrantees[insertAtIdx:]...)...)
|
||||
}
|
||||
grantees = bogusGrantees
|
||||
}
|
||||
granteesPubkeyListFile := testutil.TempFileWithContent(t, strings.Join(grantees, "\n"))
|
||||
defer os.RemoveAll(granteesPubkeyListFile)
|
||||
|
||||
publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(publisherDir)
|
||||
|
||||
passFile, err := ioutil.TempFile("", "swarm-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer passFile.Close()
|
||||
defer os.Remove(passFile.Name())
|
||||
_, err = io.WriteString(passFile, testPassphrase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
passwordFilename := testutil.TempFileWithContent(t, testPassphrase)
|
||||
defer os.RemoveAll(passwordFilename)
|
||||
actPasswordFilename := testutil.TempFileWithContent(t, "smth")
|
||||
defer os.RemoveAll(actPasswordFilename)
|
||||
_, publisherAccount := getTestAccount(t, publisherDir)
|
||||
up = runSwarm(t,
|
||||
"--bzzaccount",
|
||||
publisherAccount.Address.String(),
|
||||
"--password",
|
||||
passFile.Name(),
|
||||
passwordFilename,
|
||||
"--datadir",
|
||||
publisherDir,
|
||||
"--bzzapi",
|
||||
|
|
@ -458,7 +442,9 @@ func TestAccessACT(t *testing.T) {
|
|||
"new",
|
||||
"act",
|
||||
"--grant-keys",
|
||||
granteesPubkeyListFile.Name(),
|
||||
granteesPubkeyListFile,
|
||||
"--password",
|
||||
actPasswordFilename,
|
||||
ref,
|
||||
)
|
||||
|
||||
|
|
@ -468,6 +454,22 @@ func TestAccessACT(t *testing.T) {
|
|||
if len(matches) == 0 {
|
||||
t.Fatalf("stdout not matched")
|
||||
}
|
||||
|
||||
//get the public key from the publisher directory
|
||||
publicKeyFromDataDir := runSwarm(t,
|
||||
"--bzzaccount",
|
||||
publisherAccount.Address.String(),
|
||||
"--password",
|
||||
passwordFilename,
|
||||
"--datadir",
|
||||
publisherDir,
|
||||
"print-keys",
|
||||
"--compressed",
|
||||
)
|
||||
_, publicKeyString := publicKeyFromDataDir.ExpectRegexp(".+")
|
||||
publicKeyFromDataDir.ExpectExit()
|
||||
pkComp := strings.Split(publicKeyString[0], "=")[1]
|
||||
|
||||
hash := matches[0]
|
||||
m, _, err := client.DownloadManifest(hash)
|
||||
if err != nil {
|
||||
|
|
@ -497,10 +499,10 @@ func TestAccessACT(t *testing.T) {
|
|||
if len(a.Salt) < 32 {
|
||||
t.Fatalf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt))
|
||||
}
|
||||
if a.KdfParams != nil {
|
||||
t.Fatal("manifest access kdf params should be nil")
|
||||
}
|
||||
|
||||
if a.Publisher != pkComp {
|
||||
t.Fatal("publisher key did not match")
|
||||
}
|
||||
httpClient := &http.Client{}
|
||||
|
||||
// all nodes except the skipped node should be able to decrypt the content
|
||||
|
|
@ -521,6 +523,25 @@ func TestAccessACT(t *testing.T) {
|
|||
t.Fatalf("should be a 401")
|
||||
}
|
||||
|
||||
// try downloading using a password instead, using the unauthorized node
|
||||
passwordUrl := strings.Replace(url, "http://", "http://:smth@", -1)
|
||||
response, err = httpClient.Get(passwordUrl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
t.Fatal("should be a 200")
|
||||
}
|
||||
|
||||
// now try with the wrong password, expect 401
|
||||
passwordUrl = strings.Replace(url, "http://", "http://:smthWrong@", -1)
|
||||
response, err = httpClient.Get(passwordUrl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if response.StatusCode != http.StatusUnauthorized {
|
||||
t.Fatal("should be a 401")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func hash(ctx *cli.Context) {
|
|||
defer f.Close()
|
||||
|
||||
stat, _ := f.Stat()
|
||||
fileStore := storage.NewFileStore(storage.NewMapChunkStore(), storage.NewFileStoreParams())
|
||||
fileStore := storage.NewFileStore(&storage.FakeChunkStore{}, storage.NewFileStoreParams())
|
||||
addr, _, err := fileStore.Store(context.TODO(), f, stat.Size(), false)
|
||||
if err != nil {
|
||||
utils.Fatalf("%v\n", err)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -37,7 +38,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/debug"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/swarm"
|
||||
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
|
||||
swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
|
||||
|
|
@ -208,6 +209,10 @@ var (
|
|||
Name: "data",
|
||||
Usage: "Initializes the resource with the given hex-encoded data. Data must be prefixed by 0x",
|
||||
}
|
||||
SwarmCompressedFlag = cli.BoolFlag{
|
||||
Name: "compressed",
|
||||
Usage: "Prints encryption keys in compressed form",
|
||||
}
|
||||
)
|
||||
|
||||
//declare a few constant error messages, useful for later error check comparisons in test
|
||||
|
|
@ -252,6 +257,14 @@ func init() {
|
|||
Usage: "Print version numbers",
|
||||
Description: "The output of this command is supposed to be machine-readable",
|
||||
},
|
||||
{
|
||||
Action: keys,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Name: "print-keys",
|
||||
Flags: []cli.Flag{SwarmCompressedFlag},
|
||||
Usage: "Print public key information",
|
||||
Description: "The output of this command is supposed to be machine-readable",
|
||||
},
|
||||
{
|
||||
Action: upload,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
|
|
@ -306,6 +319,7 @@ func init() {
|
|||
Flags: []cli.Flag{
|
||||
SwarmAccessGrantKeysFlag,
|
||||
SwarmDryRunFlag,
|
||||
utils.PasswordFileFlag,
|
||||
},
|
||||
Name: "act",
|
||||
Usage: "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest",
|
||||
|
|
@ -580,6 +594,17 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
func keys(ctx *cli.Context) error {
|
||||
privateKey := getPrivKey(ctx)
|
||||
pub := hex.EncodeToString(crypto.FromECDSAPub(&privateKey.PublicKey))
|
||||
pubCompressed := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey))
|
||||
if !ctx.Bool(SwarmCompressedFlag.Name) {
|
||||
fmt.Println(fmt.Sprintf("publicKey=%s", pub))
|
||||
}
|
||||
fmt.Println(fmt.Sprintf("publicKeyCompressed=%s", pubCompressed))
|
||||
return nil
|
||||
}
|
||||
|
||||
func version(ctx *cli.Context) error {
|
||||
fmt.Println(strings.Title(clientIdentifier))
|
||||
fmt.Println("Version:", sv.VersionWithMeta)
|
||||
|
|
@ -763,10 +788,10 @@ func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) {
|
|||
return
|
||||
}
|
||||
|
||||
cfg.P2P.BootstrapNodes = []*discover.Node{}
|
||||
cfg.P2P.BootstrapNodes = []*enode.Node{}
|
||||
|
||||
for _, url := range SwarmBootnodes {
|
||||
node, err := discover.ParseNode(url)
|
||||
node, err := enode.ParseV4(url)
|
||||
if err != nil {
|
||||
log.Error("Bootstrap URL invalid", "enode", url, "err", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode {
|
|||
// start the node
|
||||
node.Cmd = runSwarm(t,
|
||||
"--port", p2pPort,
|
||||
"--nat", "extip:127.0.0.1",
|
||||
"--nodiscover",
|
||||
"--datadir", dir,
|
||||
"--ipcpath", conf.IPCPath,
|
||||
|
|
@ -241,7 +242,7 @@ func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode {
|
|||
"--bzzaccount", bzzaccount,
|
||||
"--bzznetworkid", "321",
|
||||
"--bzzport", httpPort,
|
||||
"--verbosity", "6",
|
||||
"--verbosity", "3",
|
||||
)
|
||||
node.Cmd.InputLine(testPassphrase)
|
||||
defer func() {
|
||||
|
|
@ -284,8 +285,8 @@ func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode {
|
|||
if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort)
|
||||
|
||||
node.Enode = nodeInfo.Enode
|
||||
node.IpcPath = conf.IPCPath
|
||||
return node
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +310,7 @@ func newTestNode(t *testing.T, dir string) *testNode {
|
|||
// start the node
|
||||
node.Cmd = runSwarm(t,
|
||||
"--port", p2pPort,
|
||||
"--nat", "extip:127.0.0.1",
|
||||
"--nodiscover",
|
||||
"--datadir", dir,
|
||||
"--ipcpath", conf.IPCPath,
|
||||
|
|
@ -316,7 +318,7 @@ func newTestNode(t *testing.T, dir string) *testNode {
|
|||
"--bzzaccount", account.Address.String(),
|
||||
"--bzznetworkid", "321",
|
||||
"--bzzport", httpPort,
|
||||
"--verbosity", "6",
|
||||
"--verbosity", "3",
|
||||
)
|
||||
node.Cmd.InputLine(testPassphrase)
|
||||
defer func() {
|
||||
|
|
@ -359,9 +361,8 @@ func newTestNode(t *testing.T, dir string) *testNode {
|
|||
if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort)
|
||||
node.Enode = nodeInfo.Enode
|
||||
node.IpcPath = conf.IPCPath
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func main() {
|
|||
cli.StringFlag{
|
||||
Name: "cluster-endpoint",
|
||||
Value: "testing",
|
||||
Usage: "cluster to point to (open, or testing)",
|
||||
Usage: "cluster to point to (local, open or testing)",
|
||||
Destination: &cluster,
|
||||
},
|
||||
cli.IntFlag{
|
||||
|
|
@ -76,8 +76,8 @@ func main() {
|
|||
},
|
||||
cli.IntFlag{
|
||||
Name: "filesize",
|
||||
Value: 1,
|
||||
Usage: "file size for generated random file in MB",
|
||||
Value: 1024,
|
||||
Usage: "file size for generated random file in KB",
|
||||
Destination: &filesize,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ import (
|
|||
func generateEndpoints(scheme string, cluster string, from int, to int) {
|
||||
if cluster == "prod" {
|
||||
cluster = ""
|
||||
} else if cluster == "local" {
|
||||
for port := from; port <= to; port++ {
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s://localhost:%v", scheme, port))
|
||||
}
|
||||
return
|
||||
} else {
|
||||
cluster = cluster + "."
|
||||
}
|
||||
|
|
@ -53,13 +58,13 @@ func generateEndpoints(scheme string, cluster string, from int, to int) {
|
|||
}
|
||||
|
||||
func cliUploadAndSync(c *cli.Context) error {
|
||||
defer func(now time.Time) { log.Info("total time", "time", time.Since(now), "size", filesize) }(time.Now())
|
||||
defer func(now time.Time) { log.Info("total time", "time", time.Since(now), "size (kb)", filesize) }(time.Now())
|
||||
|
||||
generateEndpoints(scheme, cluster, from, to)
|
||||
|
||||
log.Info("uploading to " + endpoints[0] + " and syncing")
|
||||
|
||||
f, cleanup := generateRandomFile(filesize * 1000000)
|
||||
f, cleanup := generateRandomFile(filesize * 1000)
|
||||
defer cleanup()
|
||||
|
||||
hash, err := upload(f, endpoints[0])
|
||||
|
|
@ -76,12 +81,7 @@ func cliUploadAndSync(c *cli.Context) error {
|
|||
|
||||
log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash))
|
||||
|
||||
if filesize < 10 {
|
||||
time.Sleep(35 * time.Second)
|
||||
} else {
|
||||
time.Sleep(15 * time.Second)
|
||||
time.Sleep(2 * time.Duration(filesize) * time.Second)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
for _, endpoint := range endpoints {
|
||||
|
|
@ -109,7 +109,7 @@ func cliUploadAndSync(c *cli.Context) error {
|
|||
// fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file
|
||||
func fetch(hash string, endpoint string, original []byte, ruid string) error {
|
||||
log.Trace("sleeping", "ruid", ruid)
|
||||
time.Sleep(5 * time.Second)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
log.Trace("http get request", "ruid", ruid, "api", endpoint, "hash", hash)
|
||||
res, err := http.Get(endpoint + "/bzz:/" + hash + "/")
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/metrics/influxdb"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -348,12 +348,12 @@ var (
|
|||
}
|
||||
MinerGasPriceFlag = BigFlag{
|
||||
Name: "miner.gasprice",
|
||||
Usage: "Minimal gas price for mining a transactions",
|
||||
Usage: "Minimum gas price for mining a transaction",
|
||||
Value: eth.DefaultConfig.MinerGasPrice,
|
||||
}
|
||||
MinerLegacyGasPriceFlag = BigFlag{
|
||||
Name: "gasprice",
|
||||
Usage: "Minimal gas price for mining a transactions (deprecated, use --miner.gasprice)",
|
||||
Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)",
|
||||
Value: eth.DefaultConfig.MinerGasPrice,
|
||||
}
|
||||
MinerEtherbaseFlag = cli.StringFlag{
|
||||
|
|
@ -572,6 +572,10 @@ var (
|
|||
Usage: "Minimum POW accepted",
|
||||
Value: whisper.DefaultMinimumPoW,
|
||||
}
|
||||
WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
|
||||
Name: "shh.restrict-light",
|
||||
Usage: "Restrict connection between two whisper light clients",
|
||||
}
|
||||
|
||||
// Metrics flags
|
||||
MetricsEnabledFlag = cli.BoolFlag{
|
||||
|
|
@ -611,6 +615,17 @@ var (
|
|||
Usage: "InfluxDB `host` tag attached to all measurements",
|
||||
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
|
||||
|
|
@ -682,9 +697,9 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
|||
return // already set, don't apply defaults.
|
||||
}
|
||||
|
||||
cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls))
|
||||
cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
|
||||
for _, url := range urls {
|
||||
node, err := discover.ParseNode(url)
|
||||
node, err := enode.ParseV4(url)
|
||||
if err != nil {
|
||||
log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
|
||||
}
|
||||
|
|
@ -1104,6 +1119,9 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
|
|||
if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
|
||||
cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
|
||||
}
|
||||
if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
|
||||
cfg.RestrictConnectionBetweenLightClients = true
|
||||
}
|
||||
}
|
||||
|
||||
// SetEthConfig applies eth-related command line flags to the config.
|
||||
|
|
@ -1182,6 +1200,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
|
|||
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.
|
||||
switch {
|
||||
case ctx.GlobalBool(TestnetFlag.Name):
|
||||
|
|
@ -1377,7 +1403,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
|||
cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
||||
}
|
||||
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 {
|
||||
Fatalf("Can't create BlockChain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/whisper/mailserver"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
|
|
@ -175,7 +175,7 @@ func initialize() {
|
|||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*argVerbosity), log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||
|
||||
done = make(chan struct{})
|
||||
var peers []*discover.Node
|
||||
var peers []*enode.Node
|
||||
var err error
|
||||
|
||||
if *generateKey {
|
||||
|
|
@ -203,7 +203,7 @@ func initialize() {
|
|||
if len(*argEnode) == 0 {
|
||||
argEnode = scanLineA("Please enter the peer's enode: ")
|
||||
}
|
||||
peer := discover.MustParseNode(*argEnode)
|
||||
peer := enode.MustParseV4(*argEnode)
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
|
|
@ -747,11 +747,11 @@ func requestExpiredMessagesLoop() {
|
|||
}
|
||||
|
||||
func extractIDFromEnode(s string) []byte {
|
||||
n, err := discover.ParseNode(s)
|
||||
n, err := enode.ParseV4(s)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to parse enode: %s", err)
|
||||
}
|
||||
return n.ID[:]
|
||||
return n.ID().Bytes()
|
||||
}
|
||||
|
||||
// obfuscateBloom adds 16 random bits to the bloom
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
|
|||
return h[len(h)-flen:]
|
||||
}
|
||||
hh := make([]byte, flen)
|
||||
copy(hh[flen-len(h):flen], h[:])
|
||||
copy(hh[flen-len(h):flen], h)
|
||||
return hh
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,3 +38,45 @@ func (d PrettyDuration) String() string {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import (
|
|||
const (
|
||||
// HashLength is the expected length of the hash
|
||||
HashLength = 32
|
||||
// AddressLength is the expected length of the adddress
|
||||
// AddressLength is the expected length of the address
|
||||
AddressLength = 20
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -93,27 +93,33 @@ var (
|
|||
|
||||
// errMissingSignature is returned if a block's extra-data section doesn't seem
|
||||
// to contain a 65 byte secp256k1 signature.
|
||||
errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
|
||||
errMissingSignature = errors.New("extra-data 65 byte signature suffix missing")
|
||||
|
||||
// errExtraSigners is returned if non-checkpoint block contain signer data in
|
||||
// their extra-data fields.
|
||||
errExtraSigners = errors.New("non-checkpoint block contains extra signer list")
|
||||
|
||||
// errInvalidCheckpointSigners is returned if a checkpoint block contains an
|
||||
// invalid list of signers (i.e. non divisible by 20 bytes, or not the correct
|
||||
// ones).
|
||||
// invalid list of signers (i.e. non divisible by 20 bytes).
|
||||
errInvalidCheckpointSigners = errors.New("invalid signer list on checkpoint block")
|
||||
|
||||
// errMismatchingCheckpointSigners is returned if a checkpoint block contains a
|
||||
// list of signers different than the one the local node calculated.
|
||||
errMismatchingCheckpointSigners = errors.New("mismatching signer list on checkpoint block")
|
||||
|
||||
// errInvalidMixDigest is returned if a block's mix digest is non-zero.
|
||||
errInvalidMixDigest = errors.New("non-zero mix digest")
|
||||
|
||||
// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
|
||||
errInvalidUncleHash = errors.New("non empty uncle hash")
|
||||
|
||||
// errInvalidDifficulty is returned if the difficulty of a block is not either
|
||||
// of 1 or 2, or if the value does not match the turn of the signer.
|
||||
// errInvalidDifficulty is returned if the difficulty of a block neither 1 or 2.
|
||||
errInvalidDifficulty = errors.New("invalid difficulty")
|
||||
|
||||
// errWrongDifficulty is returned if the difficulty of a block doesn't match the
|
||||
// turn of the signer.
|
||||
errWrongDifficulty = errors.New("wrong difficulty")
|
||||
|
||||
// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
|
||||
// the previous block's timestamp + the minimum block period.
|
||||
ErrInvalidTimestamp = errors.New("invalid timestamp")
|
||||
|
|
@ -122,13 +128,12 @@ var (
|
|||
// be modified via out-of-range or non-contiguous headers.
|
||||
errInvalidVotingChain = errors.New("invalid voting chain")
|
||||
|
||||
// errUnauthorized is returned if a header is signed by a non-authorized entity.
|
||||
errUnauthorized = errors.New("unauthorized")
|
||||
// errUnauthorizedSigner is returned if a header is signed by a non-authorized entity.
|
||||
errUnauthorizedSigner = errors.New("unauthorized signer")
|
||||
|
||||
// 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")
|
||||
// errRecentlySigned is returned if a header is signed by an authorized entity
|
||||
// that already signed a header recently, thus is temporarily not allowed to.
|
||||
errRecentlySigned = errors.New("recently signed")
|
||||
)
|
||||
|
||||
// SignerFn is a signer callback function to request a hash to be signed by a
|
||||
|
|
@ -205,6 +210,9 @@ type Clique struct {
|
|||
signer common.Address // Ethereum address of the signing key
|
||||
signFn SignerFn // Signer function to authorize hashes with
|
||||
lock sync.RWMutex // Protects the signer fields
|
||||
|
||||
// The fields below are for testing only
|
||||
fakeDiff bool // Skip difficulty verifications
|
||||
}
|
||||
|
||||
// New creates a Clique proof-of-authority consensus engine with the initial
|
||||
|
|
@ -359,7 +367,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type
|
|||
}
|
||||
extraSuffix := len(header.Extra) - extraSeal
|
||||
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) {
|
||||
return errInvalidCheckpointSigners
|
||||
return errMismatchingCheckpointSigners
|
||||
}
|
||||
}
|
||||
// All basic checks passed, verify the seal and return
|
||||
|
|
@ -388,7 +396,7 @@ func (c *Clique) snapshot(chain consensus.ChainReader, number uint64, hash commo
|
|||
}
|
||||
}
|
||||
// If we're at an checkpoint block, make a snapshot if it's known
|
||||
if number%c.config.Epoch == 0 {
|
||||
if number == 0 || (number%c.config.Epoch == 0 && chain.GetHeaderByNumber(number-1) == nil) {
|
||||
checkpoint := chain.GetHeaderByNumber(number)
|
||||
if checkpoint != nil {
|
||||
hash := checkpoint.Hash()
|
||||
|
|
@ -481,23 +489,25 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p
|
|||
return err
|
||||
}
|
||||
if _, ok := snap.Signers[signer]; !ok {
|
||||
return errUnauthorized
|
||||
return errUnauthorizedSigner
|
||||
}
|
||||
for seen, recent := range snap.Recents {
|
||||
if recent == signer {
|
||||
// Signer is among recents, only fail if the current block doesn't shift it out
|
||||
if limit := uint64(len(snap.Signers)/2 + 1); seen > number-limit {
|
||||
return errUnauthorized
|
||||
return errRecentlySigned
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure that the difficulty corresponds to the turn-ness of the signer
|
||||
if !c.fakeDiff {
|
||||
inturn := snap.inturn(header.Number.Uint64(), signer)
|
||||
if inturn && header.Difficulty.Cmp(diffInTurn) != 0 {
|
||||
return errInvalidDifficulty
|
||||
return errWrongDifficulty
|
||||
}
|
||||
if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 {
|
||||
return errInvalidDifficulty
|
||||
return errWrongDifficulty
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -600,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)
|
||||
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
|
||||
c.lock.RLock()
|
||||
|
|
@ -613,7 +624,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
|
|||
return err
|
||||
}
|
||||
if _, authorized := snap.Signers[signer]; !authorized {
|
||||
return errUnauthorized
|
||||
return errUnauthorizedSigner
|
||||
}
|
||||
// If we're amongst the recent signers, wait for the next block
|
||||
for seen, recent := range snap.Recents {
|
||||
|
|
|
|||
|
|
@ -57,12 +57,12 @@ type Snapshot struct {
|
|||
Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating
|
||||
}
|
||||
|
||||
// signers implements the sort interface to allow sorting a list of addresses
|
||||
type signers []common.Address
|
||||
// signersAscending implements the sort interface to allow sorting a list of addresses
|
||||
type signersAscending []common.Address
|
||||
|
||||
func (s signers) Len() int { return len(s) }
|
||||
func (s signers) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
|
||||
func (s signers) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s signersAscending) Len() int { return len(s) }
|
||||
func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
|
||||
func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
||||
// method does not initialize the set of recent signers, so only ever use if for
|
||||
|
|
@ -214,11 +214,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
|||
return nil, err
|
||||
}
|
||||
if _, ok := snap.Signers[signer]; !ok {
|
||||
return nil, errUnauthorized
|
||||
return nil, errUnauthorizedSigner
|
||||
}
|
||||
for _, recent := range snap.Recents {
|
||||
if recent == signer {
|
||||
return nil, errUnauthorized
|
||||
return nil, errRecentlySigned
|
||||
}
|
||||
}
|
||||
snap.Recents[number] = signer
|
||||
|
|
@ -298,7 +298,7 @@ func (s *Snapshot) signers() []common.Address {
|
|||
for sig := range s.Signers {
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
sort.Sort(signers(sigs))
|
||||
sort.Sort(signersAscending(sigs))
|
||||
return sigs
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,24 +19,18 @@ package clique
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"math/big"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
type testerVote struct {
|
||||
signer string
|
||||
voted string
|
||||
auth bool
|
||||
}
|
||||
|
||||
// testerAccountPool is a pool to maintain currently active tester accounts,
|
||||
// mapped from textual names used in the tests below to actual Ethereum private
|
||||
// keys capable of signing transactions.
|
||||
|
|
@ -50,17 +44,26 @@ func newTesterAccountPool() *testerAccountPool {
|
|||
}
|
||||
}
|
||||
|
||||
func (ap *testerAccountPool) sign(header *types.Header, signer string) {
|
||||
// Ensure we have a persistent key for the signer
|
||||
if ap.accounts[signer] == nil {
|
||||
ap.accounts[signer], _ = crypto.GenerateKey()
|
||||
// checkpoint creates a Clique checkpoint signer section from the provided list
|
||||
// of authorized signers and embeds it into the provided header.
|
||||
func (ap *testerAccountPool) checkpoint(header *types.Header, signers []string) {
|
||||
auths := make([]common.Address, len(signers))
|
||||
for i, signer := range signers {
|
||||
auths[i] = ap.address(signer)
|
||||
}
|
||||
sort.Sort(signersAscending(auths))
|
||||
for i, auth := range auths {
|
||||
copy(header.Extra[extraVanity+i*common.AddressLength:], auth.Bytes())
|
||||
}
|
||||
// Sign the header and embed the signature in extra data
|
||||
sig, _ := crypto.Sign(sigHash(header).Bytes(), ap.accounts[signer])
|
||||
copy(header.Extra[len(header.Extra)-65:], sig)
|
||||
}
|
||||
|
||||
// address retrieves the Ethereum address of a tester account by label, creating
|
||||
// a new account if no previous one exists yet.
|
||||
func (ap *testerAccountPool) address(account string) common.Address {
|
||||
// Return the zero account for non-addresses
|
||||
if account == "" {
|
||||
return common.Address{}
|
||||
}
|
||||
// Ensure we have a persistent key for the account
|
||||
if ap.accounts[account] == nil {
|
||||
ap.accounts[account], _ = crypto.GenerateKey()
|
||||
|
|
@ -69,32 +72,38 @@ func (ap *testerAccountPool) address(account string) common.Address {
|
|||
return crypto.PubkeyToAddress(ap.accounts[account].PublicKey)
|
||||
}
|
||||
|
||||
// testerChainReader implements consensus.ChainReader to access the genesis
|
||||
// block. All other methods and requests will panic.
|
||||
type testerChainReader struct {
|
||||
db ethdb.Database
|
||||
// sign calculates a Clique digital signature for the given block and embeds it
|
||||
// back into the header.
|
||||
func (ap *testerAccountPool) sign(header *types.Header, signer string) {
|
||||
// Ensure we have a persistent key for the signer
|
||||
if ap.accounts[signer] == nil {
|
||||
ap.accounts[signer], _ = crypto.GenerateKey()
|
||||
}
|
||||
// Sign the header and embed the signature in extra data
|
||||
sig, _ := crypto.Sign(sigHash(header).Bytes(), ap.accounts[signer])
|
||||
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
|
||||
}
|
||||
|
||||
func (r *testerChainReader) Config() *params.ChainConfig { return params.AllCliqueProtocolChanges }
|
||||
func (r *testerChainReader) CurrentHeader() *types.Header { panic("not supported") }
|
||||
func (r *testerChainReader) GetHeader(common.Hash, uint64) *types.Header { panic("not supported") }
|
||||
func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic("not supported") }
|
||||
func (r *testerChainReader) GetHeaderByHash(common.Hash) *types.Header { panic("not supported") }
|
||||
func (r *testerChainReader) GetHeaderByNumber(number uint64) *types.Header {
|
||||
if number == 0 {
|
||||
return rawdb.ReadHeader(r.db, rawdb.ReadCanonicalHash(r.db, 0), 0)
|
||||
}
|
||||
return nil
|
||||
// testerVote represents a single block signed by a parcitular account, where
|
||||
// the account may or may not have cast a Clique vote.
|
||||
type testerVote struct {
|
||||
signer string
|
||||
voted string
|
||||
auth bool
|
||||
checkpoint []string
|
||||
newbatch bool
|
||||
}
|
||||
|
||||
// Tests that voting is evaluated correctly for various simple and complex scenarios.
|
||||
func TestVoting(t *testing.T) {
|
||||
// Tests that Clique signer voting is evaluated correctly for various simple and
|
||||
// complex scenarios, as well as that a few special corner cases fail correctly.
|
||||
func TestClique(t *testing.T) {
|
||||
// Define the various voting scenarios to test
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
signers []string
|
||||
votes []testerVote
|
||||
results []string
|
||||
failure error
|
||||
}{
|
||||
{
|
||||
// Single signer, no votes cast
|
||||
|
|
@ -322,10 +331,49 @@ func TestVoting(t *testing.T) {
|
|||
votes: []testerVote{
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A"}, // Checkpoint block, (don't vote here, it's validated outside of snapshots)
|
||||
{signer: "A", checkpoint: []string{"A", "B"}},
|
||||
{signer: "B", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// An unauthorized signer should not be able to sign blocks
|
||||
signers: []string{"A"},
|
||||
votes: []testerVote{
|
||||
{signer: "B"},
|
||||
},
|
||||
failure: errUnauthorizedSigner,
|
||||
}, {
|
||||
// An authorized signer that signed recenty should not be able to sign again
|
||||
signers: []string{"A", "B"},
|
||||
votes: []testerVote{
|
||||
{signer: "A"},
|
||||
{signer: "A"},
|
||||
},
|
||||
failure: errRecentlySigned,
|
||||
}, {
|
||||
// Recent signatures should not reset on checkpoint blocks imported in a batch
|
||||
epoch: 3,
|
||||
signers: []string{"A", "B", "C"},
|
||||
votes: []testerVote{
|
||||
{signer: "A"},
|
||||
{signer: "B"},
|
||||
{signer: "A", checkpoint: []string{"A", "B", "C"}},
|
||||
{signer: "A"},
|
||||
},
|
||||
failure: errRecentlySigned,
|
||||
}, {
|
||||
// Recent signatures should not reset on checkpoint blocks imported in a new
|
||||
// batch (https://github.com/ethereum/go-ethereum/issues/17593). Whilst this
|
||||
// seems overly specific and weird, it was a Rinkeby consensus split.
|
||||
epoch: 3,
|
||||
signers: []string{"A", "B", "C"},
|
||||
votes: []testerVote{
|
||||
{signer: "A"},
|
||||
{signer: "B"},
|
||||
{signer: "A", checkpoint: []string{"A", "B", "C"}},
|
||||
{signer: "A", newbatch: true},
|
||||
},
|
||||
failure: errRecentlySigned,
|
||||
},
|
||||
}
|
||||
// Run through the scenarios and test them
|
||||
|
|
@ -356,28 +404,78 @@ func TestVoting(t *testing.T) {
|
|||
genesis.Commit(db)
|
||||
|
||||
// Assemble a chain of headers from the cast votes
|
||||
headers := make([]*types.Header, len(tt.votes))
|
||||
for j, vote := range tt.votes {
|
||||
headers[j] = &types.Header{
|
||||
Number: big.NewInt(int64(j) + 1),
|
||||
Time: big.NewInt(int64(j) * 15),
|
||||
Coinbase: accounts.address(vote.voted),
|
||||
Extra: make([]byte, extraVanity+extraSeal),
|
||||
config := *params.TestChainConfig
|
||||
config.Clique = ¶ms.CliqueConfig{
|
||||
Period: 1,
|
||||
Epoch: tt.epoch,
|
||||
}
|
||||
engine := New(config.Clique, db)
|
||||
engine.fakeDiff = true
|
||||
|
||||
blocks, _ := core.GenerateChain(&config, genesis.ToBlock(db), engine, db, len(tt.votes), func(j int, gen *core.BlockGen) {
|
||||
// Cast the vote contained in this block
|
||||
gen.SetCoinbase(accounts.address(tt.votes[j].voted))
|
||||
if tt.votes[j].auth {
|
||||
var nonce types.BlockNonce
|
||||
copy(nonce[:], nonceAuthVote)
|
||||
gen.SetNonce(nonce)
|
||||
}
|
||||
})
|
||||
// Iterate through the blocks and seal them individually
|
||||
for j, block := range blocks {
|
||||
// Geth the header and prepare it for signing
|
||||
header := block.Header()
|
||||
if j > 0 {
|
||||
headers[j].ParentHash = headers[j-1].Hash()
|
||||
header.ParentHash = blocks[j-1].Hash()
|
||||
}
|
||||
if vote.auth {
|
||||
copy(headers[j].Nonce[:], nonceAuthVote)
|
||||
header.Extra = make([]byte, extraVanity+extraSeal)
|
||||
if auths := tt.votes[j].checkpoint; auths != nil {
|
||||
header.Extra = make([]byte, extraVanity+len(auths)*common.AddressLength+extraSeal)
|
||||
accounts.checkpoint(header, auths)
|
||||
}
|
||||
accounts.sign(headers[j], vote.signer)
|
||||
header.Difficulty = diffInTurn // Ignored, we just need a valid number
|
||||
|
||||
// Generate the signature, embed it into the header and the block
|
||||
accounts.sign(header, tt.votes[j].signer)
|
||||
blocks[j] = block.WithSeal(header)
|
||||
}
|
||||
// Split the blocks up into individual import batches (cornercase testing)
|
||||
batches := [][]*types.Block{nil}
|
||||
for j, block := range blocks {
|
||||
if tt.votes[j].newbatch {
|
||||
batches = append(batches, nil)
|
||||
}
|
||||
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||
}
|
||||
// Pass all the headers through clique and ensure tallying succeeds
|
||||
head := headers[len(headers)-1]
|
||||
|
||||
snap, err := New(¶ms.CliqueConfig{Epoch: tt.epoch}, db).snapshot(&testerChainReader{db: db}, head.Number.Uint64(), head.Hash(), headers)
|
||||
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Errorf("test %d: failed to create voting snapshot: %v", i, err)
|
||||
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
||||
continue
|
||||
}
|
||||
failed := false
|
||||
for j := 0; j < len(batches)-1; j++ {
|
||||
if k, err := chain.InsertChain(batches[j]); err != nil {
|
||||
t.Errorf("test %d: failed to import batch %d, block %d: %v", i, j, k, err)
|
||||
failed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if failed {
|
||||
continue
|
||||
}
|
||||
if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure {
|
||||
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
|
||||
}
|
||||
if tt.failure != nil {
|
||||
continue
|
||||
}
|
||||
// No failure was produced or requested, generate the final voting snapshot
|
||||
head := blocks[len(blocks)-1]
|
||||
|
||||
snap, err := engine.snapshot(chain, head.NumberU64(), head.Hash(), nil)
|
||||
if err != nil {
|
||||
t.Errorf("test %d: failed to retrieve voting snapshot: %v", i, err)
|
||||
continue
|
||||
}
|
||||
// Verify the final list of signers against the expected ones
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ type Engine interface {
|
|||
// the result into the given channel.
|
||||
//
|
||||
// Note, the method returns immediately and will send the result async. More
|
||||
// than one result may also be returned depending on the consensus algorothm.
|
||||
// than one result may also be returned depending on the consensus algorithm.
|
||||
Seal(chain ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
|
|
|
|||
|
|
@ -40,8 +40,22 @@ import (
|
|||
var (
|
||||
FrontierBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
|
||||
ByzantiumBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
|
||||
ConstantinopleBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople
|
||||
maxUncles = 2 // Maximum number of uncles allowed in a single block
|
||||
allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
|
||||
|
||||
// calcDifficultyConstantinople is the difficulty adjustment algorithm for Constantinople.
|
||||
// It returns the difficulty that a new block should have when created at time given the
|
||||
// parent block's time and difficulty. The calculation uses the Byzantium rules, but with
|
||||
// bomb offset 5M.
|
||||
// Specification EIP-1234: https://eips.ethereum.org/EIPS/eip-1234
|
||||
calcDifficultyConstantinople = makeDifficultyCalculator(big.NewInt(5000000))
|
||||
|
||||
// calcDifficultyByzantium is the difficulty adjustment algorithm. It returns
|
||||
// the difficulty that a new block should have when created at time given the
|
||||
// parent block's time and difficulty. The calculation uses the Byzantium rules.
|
||||
// Specification EIP-649: https://eips.ethereum.org/EIPS/eip-649
|
||||
calcDifficultyByzantium = makeDifficultyCalculator(big.NewInt(3000000))
|
||||
)
|
||||
|
||||
// Various error messages to mark blocks invalid. These should be private to
|
||||
|
|
@ -299,6 +313,8 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainReader, time uint64, p
|
|||
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
||||
next := new(big.Int).Add(parent.Number, big1)
|
||||
switch {
|
||||
case config.IsConstantinople(next):
|
||||
return calcDifficultyConstantinople(time, parent)
|
||||
case config.IsByzantium(next):
|
||||
return calcDifficultyByzantium(time, parent)
|
||||
case config.IsHomestead(next):
|
||||
|
|
@ -316,13 +332,16 @@ var (
|
|||
big9 = big.NewInt(9)
|
||||
big10 = big.NewInt(10)
|
||||
bigMinus99 = big.NewInt(-99)
|
||||
big2999999 = big.NewInt(2999999)
|
||||
)
|
||||
|
||||
// calcDifficultyByzantium is the difficulty adjustment algorithm. It returns
|
||||
// the difficulty that a new block should have when created at time given the
|
||||
// parent block's time and difficulty. The calculation uses the Byzantium rules.
|
||||
func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int {
|
||||
// makeDifficultyCalculator creates a difficultyCalculator with the given bomb-delay.
|
||||
// the difficulty is calculated with Byzantium rules, which differs from Homestead in
|
||||
// how uncles affect the calculation
|
||||
func makeDifficultyCalculator(bombDelay *big.Int) func(time uint64, parent *types.Header) *big.Int {
|
||||
// Note, the calculations below looks at the parent number, which is 1 below
|
||||
// the block number. Thus we remove one from the delay given
|
||||
bombDelayFromParent := new(big.Int).Sub(bombDelay, big1)
|
||||
return func(time uint64, parent *types.Header) *big.Int {
|
||||
// https://github.com/ethereum/EIPs/issues/100.
|
||||
// algorithm:
|
||||
// diff = (parent_diff +
|
||||
|
|
@ -357,12 +376,11 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int {
|
|||
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||
x.Set(params.MinimumDifficulty)
|
||||
}
|
||||
// calculate a fake block number for the ice-age delay:
|
||||
// https://github.com/ethereum/EIPs/pull/669
|
||||
// fake_block_number = max(0, block.number - 3_000_000)
|
||||
// calculate a fake block number for the ice-age delay
|
||||
// Specification: https://eips.ethereum.org/EIPS/eip-1234
|
||||
fakeBlockNumber := new(big.Int)
|
||||
if parent.Number.Cmp(big2999999) >= 0 {
|
||||
fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) // Note, parent is 1 less than the actual block number
|
||||
if parent.Number.Cmp(bombDelayFromParent) >= 0 {
|
||||
fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, bombDelayFromParent)
|
||||
}
|
||||
// for the exponential factor
|
||||
periodCount := fakeBlockNumber
|
||||
|
|
@ -377,6 +395,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int {
|
|||
}
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
// calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
|
||||
// the difficulty that a new block should have when created at time given the
|
||||
|
|
@ -592,6 +611,9 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
|
|||
if config.IsByzantium(header.Number) {
|
||||
blockReward = ByzantiumBlockReward
|
||||
}
|
||||
if config.IsConstantinople(header.Number) {
|
||||
blockReward = ConstantinopleBlockReward
|
||||
}
|
||||
// Accumulate the rewards for the miner and any included uncles
|
||||
reward := new(big.Int).Set(blockReward)
|
||||
r := new(big.Int)
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ func New(config Config, notify []string, noverify bool) *Ethash {
|
|||
caches: newlru("cache", config.CachesInMem, newCache),
|
||||
datasets: newlru("dataset", config.DatasetsInMem, newDataset),
|
||||
update: make(chan struct{}),
|
||||
hashrate: metrics.NewMeter(),
|
||||
hashrate: metrics.NewMeterForced(),
|
||||
workCh: make(chan *sealTask),
|
||||
fetchWorkCh: make(chan *sealWork),
|
||||
submitWorkCh: make(chan *mineResult),
|
||||
|
|
@ -505,7 +505,7 @@ func NewTester(notify []string, noverify bool) *Ethash {
|
|||
caches: newlru("cache", 1, newCache),
|
||||
datasets: newlru("dataset", 1, newDataset),
|
||||
update: make(chan struct{}),
|
||||
hashrate: metrics.NewMeter(),
|
||||
hashrate: metrics.NewMeterForced(),
|
||||
workCh: make(chan *sealTask),
|
||||
fetchWorkCh: make(chan *sealWork),
|
||||
submitWorkCh: make(chan *mineResult),
|
||||
|
|
|
|||
|
|
@ -40,6 +40,18 @@ func TestRemoteNotify(t *testing.T) {
|
|||
|
||||
go server.Serve(listener)
|
||||
|
||||
// Wait for server to start listening
|
||||
var tries int
|
||||
for tries = 0; tries < 10; tries++ {
|
||||
conn, _ := net.DialTimeout("tcp", listener.Addr().String(), 1*time.Second)
|
||||
if conn != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if tries == 10 {
|
||||
t.Fatal("tcp listener not ready for more than 10 seconds")
|
||||
}
|
||||
|
||||
// Create the custom ethash engine
|
||||
ethash := NewTester([]string{"http://" + listener.Addr().String()}, false)
|
||||
defer ethash.Close()
|
||||
|
|
@ -61,7 +73,7 @@ func TestRemoteNotify(t *testing.T) {
|
|||
if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want {
|
||||
t.Errorf("work packet target mismatch: have %s, want %s", work[2], want)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("notification timed out")
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +120,7 @@ func TestRemoteMultiNotify(t *testing.T) {
|
|||
for i := 0; i < cap(sink); i++ {
|
||||
select {
|
||||
case <-sink:
|
||||
case <-time.After(250 * time.Millisecond):
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("notification %d timed out", i)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
|||
|
||||
// Time the insertion of the new chain.
|
||||
// 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()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
|
@ -287,7 +287,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||
if err != nil {
|
||||
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 {
|
||||
b.Fatalf("error creating chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func TestHeaderVerification(t *testing.T) {
|
|||
headers[i] = block.Header()
|
||||
}
|
||||
// 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()
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
|
|
@ -106,11 +106,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) {
|
|||
var results <-chan error
|
||||
|
||||
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)
|
||||
chain.Stop()
|
||||
} 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)
|
||||
chain.Stop()
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
|||
defer runtime.GOMAXPROCS(old)
|
||||
|
||||
// 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()
|
||||
|
||||
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
|
|
@ -43,7 +44,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -129,12 +129,13 @@ type BlockChain struct {
|
|||
vmConfig vm.Config
|
||||
|
||||
badBlocks *lru.Cache // Bad block cache
|
||||
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
|
||||
}
|
||||
|
||||
// NewBlockChain returns a fully initialised block chain using information
|
||||
// available in the database. It initialises the default Ethereum Validator and
|
||||
// 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, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) {
|
||||
if cacheConfig == nil {
|
||||
cacheConfig = &CacheConfig{
|
||||
TrieNodeLimit: 256 * 1024 * 1024,
|
||||
|
|
@ -151,9 +152,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
|||
chainConfig: chainConfig,
|
||||
cacheConfig: cacheConfig,
|
||||
db: db,
|
||||
triegc: prque.New(),
|
||||
triegc: prque.New(nil),
|
||||
stateCache: state.NewDatabase(db),
|
||||
quit: make(chan struct{}),
|
||||
shouldPreserve: shouldPreserve,
|
||||
bodyCache: bodyCache,
|
||||
bodyRLPCache: bodyRLPCache,
|
||||
blockCache: blockCache,
|
||||
|
|
@ -251,9 +253,9 @@ func (bc *BlockChain) loadLastState() error {
|
|||
blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.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 full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd)
|
||||
log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd)
|
||||
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, "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, "age", common.PrettyAge(time.Unix(currentFastBlock.Time().Int64(), 0)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -850,13 +852,16 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
}
|
||||
bc.mu.Unlock()
|
||||
|
||||
log.Info("Imported new block receipts",
|
||||
"count", stats.processed,
|
||||
"elapsed", common.PrettyDuration(time.Since(start)),
|
||||
"number", head.Number(),
|
||||
"hash", head.Hash(),
|
||||
context := []interface{}{
|
||||
"count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
|
||||
"number", head.Number(), "hash", head.Hash(), "age", common.PrettyAge(time.Unix(head.Time().Int64(), 0)),
|
||||
"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
|
||||
}
|
||||
|
||||
|
|
@ -915,7 +920,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
|
|||
} else {
|
||||
// Full but not archive node, do proper garbage collection
|
||||
triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive
|
||||
bc.triegc.Push(root, -float32(block.NumberU64()))
|
||||
bc.triegc.Push(root, -int64(block.NumberU64()))
|
||||
|
||||
if current := block.NumberU64(); current > triesInMemory {
|
||||
// If we exceeded our memory allowance, flush matured singleton nodes to disk
|
||||
|
|
@ -964,8 +969,17 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
|
|||
reorg := externTd.Cmp(localTd) > 0
|
||||
currentBlock = bc.CurrentBlock()
|
||||
if !reorg && externTd.Cmp(localTd) == 0 {
|
||||
// Split same-difficulty blocks by number, then at random
|
||||
reorg = block.NumberU64() < currentBlock.NumberU64() || (block.NumberU64() == currentBlock.NumberU64() && mrand.Float64() < 0.5)
|
||||
// Split same-difficulty blocks by number, then preferentially select
|
||||
// the block generated by the local miner as the canonical block.
|
||||
if block.NumberU64() < currentBlock.NumberU64() {
|
||||
reorg = true
|
||||
} else if block.NumberU64() == currentBlock.NumberU64() {
|
||||
var currentPreserve, blockPreserve bool
|
||||
if bc.shouldPreserve != nil {
|
||||
currentPreserve, blockPreserve = bc.shouldPreserve(currentBlock), bc.shouldPreserve(block)
|
||||
}
|
||||
reorg = !currentPreserve && (blockPreserve || mrand.Float64() < 0.5)
|
||||
}
|
||||
}
|
||||
if reorg {
|
||||
// Reorganise the chain if the parent is not the head block
|
||||
|
|
@ -1229,8 +1243,13 @@ func (st *insertStats) report(chain []*types.Block, index int, cache common.Stor
|
|||
context := []interface{}{
|
||||
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
||||
"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 {
|
||||
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
|
||||
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
|
||||
if n == 0 {
|
||||
return db, blockchain, nil
|
||||
|
|
@ -523,7 +523,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
|||
blockchain.Stop()
|
||||
|
||||
// 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 {
|
||||
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
|
||||
archiveDb := ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
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
|
||||
fastDb := ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
headers := make([]*types.Header, len(blocks))
|
||||
|
|
@ -722,7 +722,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
|||
archiveDb := ethdb.NewMemDatabase()
|
||||
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 {
|
||||
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
|
||||
fastDb := ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
headers := make([]*types.Header, len(blocks))
|
||||
|
|
@ -756,7 +756,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
|||
lightDb := ethdb.NewMemDatabase()
|
||||
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 {
|
||||
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.
|
||||
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 {
|
||||
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)
|
||||
)
|
||||
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
rmLogsCh := make(chan RemovedLogsEvent)
|
||||
|
|
@ -943,7 +943,7 @@ func TestReorgSideEvent(t *testing.T) {
|
|||
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()
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
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)
|
||||
)
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
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()
|
||||
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 {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -1298,7 +1298,7 @@ func TestTrieForkGC(t *testing.T) {
|
|||
diskdb := ethdb.NewMemDatabase()
|
||||
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 {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -1337,7 +1337,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
|
|||
diskdb := ethdb.NewMemDatabase()
|
||||
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 {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -1419,7 +1419,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
|||
diskdb := ethdb.NewMemDatabase()
|
||||
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 {
|
||||
b.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ func (c *ChainIndexer) AddChildIndexer(indexer *ChainIndexer) {
|
|||
func (c *ChainIndexer) loadValidSections() {
|
||||
data, _ := c.indexDb.Get([]byte("count"))
|
||||
if len(data) == 8 {
|
||||
c.storedSections = binary.BigEndian.Uint64(data[:])
|
||||
c.storedSections = binary.BigEndian.Uint64(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ func (b *BlockGen) SetExtra(data []byte) {
|
|||
b.header.Extra = data
|
||||
}
|
||||
|
||||
// SetNonce sets the nonce field of the generated block.
|
||||
func (b *BlockGen) SetNonce(nonce types.BlockNonce) {
|
||||
b.header.Nonce = nonce
|
||||
}
|
||||
|
||||
// AddTx adds a transaction to the generated block. If no coinbase has
|
||||
// been set, the block's coinbase is set to the zero address.
|
||||
//
|
||||
|
|
@ -172,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) {
|
||||
// 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.
|
||||
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{})
|
||||
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine}
|
||||
|
|
@ -190,13 +195,14 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
|
||||
misc.ApplyDAOHardFork(statedb)
|
||||
}
|
||||
// Execute any user modifications to the block and finalize it
|
||||
// Execute any user modifications to the block
|
||||
if gen != nil {
|
||||
gen(i, b)
|
||||
}
|
||||
|
||||
if b.engine != nil {
|
||||
// Finalize and seal the block
|
||||
block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts)
|
||||
|
||||
// Write state changes to db
|
||||
root, err := statedb.Commit(config.IsEIP158(b.header.Number))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func ExampleGenerateChain() {
|
|||
})
|
||||
|
||||
// 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()
|
||||
|
||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
proConf.DAOForkBlock = forkBlock
|
||||
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()
|
||||
|
||||
conDb := ethdb.NewMemDatabase()
|
||||
|
|
@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
conConf.DAOForkBlock = forkBlock
|
||||
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()
|
||||
|
||||
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
|
||||
db = ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
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
|
||||
db = ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
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
|
||||
db = ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
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
|
||||
db = ethdb.NewMemDatabase()
|
||||
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()
|
||||
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ func TestSetupGenesis(t *testing.T) {
|
|||
// Advance to block #4, past the homestead transition block of customg.
|
||||
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()
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ type stateObject struct {
|
|||
trie Trie // storage trie, which becomes non-nil on first access
|
||||
code Code // contract bytecode, which gets set when code is loaded
|
||||
|
||||
cachedStorage Storage // Storage entry cache to avoid duplicate reads
|
||||
originStorage Storage // Storage cache of original entries to dedup rewrites
|
||||
dirtyStorage Storage // Storage entries that need to be flushed to disk
|
||||
|
||||
// Cache flags.
|
||||
|
|
@ -115,7 +115,7 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject {
|
|||
address: address,
|
||||
addrHash: crypto.Keccak256Hash(address[:]),
|
||||
data: data,
|
||||
cachedStorage: make(Storage),
|
||||
originStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
}
|
||||
}
|
||||
|
|
@ -159,13 +159,25 @@ func (c *stateObject) getTrie(db Database) Trie {
|
|||
return c.trie
|
||||
}
|
||||
|
||||
// GetState returns a value in account storage.
|
||||
// GetState retrieves a value from the account storage trie.
|
||||
func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
||||
value, exists := self.cachedStorage[key]
|
||||
if exists {
|
||||
// If we have a dirty value for this state entry, return it
|
||||
value, dirty := self.dirtyStorage[key]
|
||||
if dirty {
|
||||
return value
|
||||
}
|
||||
// Load from DB in case it is missing.
|
||||
// Otherwise return the entry's original value
|
||||
return self.GetCommittedState(db, key)
|
||||
}
|
||||
|
||||
// GetCommittedState retrieves a value from the committed account storage trie.
|
||||
func (self *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash {
|
||||
// If we have the original value cached, return that
|
||||
value, cached := self.originStorage[key]
|
||||
if cached {
|
||||
return value
|
||||
}
|
||||
// Otherwise load the value from the database
|
||||
enc, err := self.getTrie(db).TryGet(key[:])
|
||||
if err != nil {
|
||||
self.setError(err)
|
||||
|
|
@ -178,22 +190,27 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
|||
}
|
||||
value.SetBytes(content)
|
||||
}
|
||||
self.cachedStorage[key] = value
|
||||
self.originStorage[key] = value
|
||||
return value
|
||||
}
|
||||
|
||||
// SetState updates a value in account storage.
|
||||
func (self *stateObject) SetState(db Database, key, value common.Hash) {
|
||||
// If the new value is the same as old, don't set
|
||||
prev := self.GetState(db, key)
|
||||
if prev == value {
|
||||
return
|
||||
}
|
||||
// New value is different, update and journal the change
|
||||
self.db.journal.append(storageChange{
|
||||
account: &self.address,
|
||||
key: key,
|
||||
prevalue: self.GetState(db, key),
|
||||
prevalue: prev,
|
||||
})
|
||||
self.setState(key, value)
|
||||
}
|
||||
|
||||
func (self *stateObject) setState(key, value common.Hash) {
|
||||
self.cachedStorage[key] = value
|
||||
self.dirtyStorage[key] = value
|
||||
}
|
||||
|
||||
|
|
@ -202,6 +219,13 @@ func (self *stateObject) updateTrie(db Database) Trie {
|
|||
tr := self.getTrie(db)
|
||||
for key, value := range self.dirtyStorage {
|
||||
delete(self.dirtyStorage, key)
|
||||
|
||||
// Skip noop changes, persist actual changes
|
||||
if value == self.originStorage[key] {
|
||||
continue
|
||||
}
|
||||
self.originStorage[key] = value
|
||||
|
||||
if (value == common.Hash{}) {
|
||||
self.setError(tr.TryDelete(key[:]))
|
||||
continue
|
||||
|
|
@ -279,7 +303,7 @@ func (self *stateObject) deepCopy(db *StateDB) *stateObject {
|
|||
}
|
||||
stateObject.code = self.code
|
||||
stateObject.dirtyStorage = self.dirtyStorage.Copy()
|
||||
stateObject.cachedStorage = self.dirtyStorage.Copy()
|
||||
stateObject.originStorage = self.originStorage.Copy()
|
||||
stateObject.suicided = self.suicided
|
||||
stateObject.dirtyCode = self.dirtyCode
|
||||
stateObject.deleted = self.deleted
|
||||
|
|
|
|||
|
|
@ -96,11 +96,15 @@ func (s *StateSuite) TestNull(c *checker.C) {
|
|||
s.state.CreateAccount(address)
|
||||
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
||||
var value common.Hash
|
||||
|
||||
s.state.SetState(address, common.Hash{}, value)
|
||||
s.state.Commit(false)
|
||||
value = s.state.GetState(address, common.Hash{})
|
||||
if value != (common.Hash{}) {
|
||||
c.Errorf("expected empty hash. got %x", value)
|
||||
|
||||
if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) {
|
||||
c.Errorf("expected empty current value, got %x", value)
|
||||
}
|
||||
if value := s.state.GetCommittedState(address, common.Hash{}); value != (common.Hash{}) {
|
||||
c.Errorf("expected empty committed value, got %x", value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,20 +114,24 @@ func (s *StateSuite) TestSnapshot(c *checker.C) {
|
|||
data1 := common.BytesToHash([]byte{42})
|
||||
data2 := common.BytesToHash([]byte{43})
|
||||
|
||||
// snapshot the genesis state
|
||||
genesis := s.state.Snapshot()
|
||||
|
||||
// set initial state object value
|
||||
s.state.SetState(stateobjaddr, storageaddr, data1)
|
||||
// get snapshot of current state
|
||||
snapshot := s.state.Snapshot()
|
||||
|
||||
// set new state object value
|
||||
// set a new state object value, revert it and ensure correct content
|
||||
s.state.SetState(stateobjaddr, storageaddr, data2)
|
||||
// restore snapshot
|
||||
s.state.RevertToSnapshot(snapshot)
|
||||
|
||||
// get state storage value
|
||||
res := s.state.GetState(stateobjaddr, storageaddr)
|
||||
c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, data1)
|
||||
c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{})
|
||||
|
||||
c.Assert(data1, checker.DeepEquals, res)
|
||||
// revert up to the genesis state and ensure correct content
|
||||
s.state.RevertToSnapshot(genesis)
|
||||
c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{})
|
||||
c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{})
|
||||
}
|
||||
|
||||
func (s *StateSuite) TestSnapshotEmpty(c *checker.C) {
|
||||
|
|
@ -208,24 +216,30 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
|
|||
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)
|
||||
}
|
||||
|
||||
if len(so1.cachedStorage) != len(so0.cachedStorage) {
|
||||
t.Errorf("Storage size mismatch: have %d, want %d", len(so1.cachedStorage), len(so0.cachedStorage))
|
||||
if len(so1.dirtyStorage) != len(so0.dirtyStorage) {
|
||||
t.Errorf("Dirty storage size mismatch: have %d, want %d", len(so1.dirtyStorage), len(so0.dirtyStorage))
|
||||
}
|
||||
for k, v := range so1.cachedStorage {
|
||||
if so0.cachedStorage[k] != v {
|
||||
t.Errorf("Storage key %x mismatch: have %v, want %v", k, so0.cachedStorage[k], v)
|
||||
for k, v := range so1.dirtyStorage {
|
||||
if so0.dirtyStorage[k] != v {
|
||||
t.Errorf("Dirty storage key %x mismatch: have %v, want %v", k, so0.dirtyStorage[k], v)
|
||||
}
|
||||
}
|
||||
for k, v := range so0.cachedStorage {
|
||||
if so1.cachedStorage[k] != v {
|
||||
t.Errorf("Storage key %x mismatch: have %v, want none.", k, v)
|
||||
for k, v := range so0.dirtyStorage {
|
||||
if so1.dirtyStorage[k] != v {
|
||||
t.Errorf("Dirty storage key %x mismatch: have %v, want none.", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
if so0.suicided != so1.suicided {
|
||||
t.Fatalf("suicided mismatch: have %v, want %v", so0.suicided, so1.suicided)
|
||||
if len(so1.originStorage) != len(so0.originStorage) {
|
||||
t.Errorf("Origin storage size mismatch: have %d, want %d", len(so1.originStorage), len(so0.originStorage))
|
||||
}
|
||||
for k, v := range so1.originStorage {
|
||||
if so0.originStorage[k] != v {
|
||||
t.Errorf("Origin storage key %x mismatch: have %v, want %v", k, so0.originStorage[k], v)
|
||||
}
|
||||
}
|
||||
for k, v := range so0.originStorage {
|
||||
if so1.originStorage[k] != v {
|
||||
t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v)
|
||||
}
|
||||
if so0.deleted != so1.deleted {
|
||||
t.Fatalf("Deleted mismatch: have %v, want %v", so0.deleted, so1.deleted)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,11 +169,22 @@ func (self *StateDB) Preimages() map[common.Hash][]byte {
|
|||
return self.preimages
|
||||
}
|
||||
|
||||
// AddRefund adds gas to the refund counter
|
||||
func (self *StateDB) AddRefund(gas uint64) {
|
||||
self.journal.append(refundChange{prev: self.refund})
|
||||
self.refund += gas
|
||||
}
|
||||
|
||||
// SubRefund removes gas from the refund counter.
|
||||
// This method will panic if the refund counter goes below zero
|
||||
func (self *StateDB) SubRefund(gas uint64) {
|
||||
self.journal.append(refundChange{prev: self.refund})
|
||||
if gas > self.refund {
|
||||
panic("Refund counter below zero")
|
||||
}
|
||||
self.refund -= gas
|
||||
}
|
||||
|
||||
// Exist reports whether the given account address exists in the state.
|
||||
// Notably this also returns true for suicided accounts.
|
||||
func (self *StateDB) Exist(addr common.Address) bool {
|
||||
|
|
@ -236,10 +247,20 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
|||
return common.BytesToHash(stateObject.CodeHash())
|
||||
}
|
||||
|
||||
func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash {
|
||||
// GetState retrieves a value from the given account's storage trie.
|
||||
func (self *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
|
||||
stateObject := self.getStateObject(addr)
|
||||
if stateObject != nil {
|
||||
return stateObject.GetState(self.db, bhash)
|
||||
return stateObject.GetState(self.db, hash)
|
||||
}
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
// GetCommittedState retrieves a value from the given account's committed storage trie.
|
||||
func (self *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
|
||||
stateObject := self.getStateObject(addr)
|
||||
if stateObject != nil {
|
||||
return stateObject.GetCommittedState(self.db, hash)
|
||||
}
|
||||
return common.Hash{}
|
||||
}
|
||||
|
|
@ -435,19 +456,14 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
|
|||
if so == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// When iterating over the storage check the cache first
|
||||
for h, value := range so.cachedStorage {
|
||||
cb(h, value)
|
||||
}
|
||||
|
||||
it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil))
|
||||
for it.Next() {
|
||||
// ignore cached values
|
||||
key := common.BytesToHash(db.trie.GetKey(it.Key))
|
||||
if _, ok := so.cachedStorage[key]; !ok {
|
||||
cb(key, common.BytesToHash(it.Value))
|
||||
if value, dirty := so.dirtyStorage[key]; dirty {
|
||||
cb(key, value)
|
||||
continue
|
||||
}
|
||||
cb(key, common.BytesToHash(it.Value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -381,11 +381,11 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
|
|||
checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
|
||||
// Check storage.
|
||||
if obj := state.getStateObject(addr); obj != nil {
|
||||
state.ForEachStorage(addr, func(key, val common.Hash) bool {
|
||||
return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
|
||||
state.ForEachStorage(addr, func(key, value common.Hash) bool {
|
||||
return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value)
|
||||
})
|
||||
checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
|
||||
return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
|
||||
checkstate.ForEachStorage(addr, func(key, value common.Hash) bool {
|
||||
return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value)
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
|||
*usedGas += gas
|
||||
|
||||
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
|
||||
// based on the eip phase, we're passing wether the root touch-delete accounts.
|
||||
// based on the eip phase, we're passing whether the root touch-delete accounts.
|
||||
receipt := types.NewReceipt(root, failed, *usedGas)
|
||||
receipt.TxHash = tx.Hash()
|
||||
receipt.GasUsed = gas
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -525,7 +525,7 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common
|
|||
return pending, queued
|
||||
}
|
||||
|
||||
// Pending retrieves all currently processable transactions, groupped by origin
|
||||
// Pending retrieves all currently processable transactions, grouped by origin
|
||||
// account and sorted by nonce. The returned transaction set is a copy and can be
|
||||
// freely modified by calling code.
|
||||
func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) {
|
||||
|
|
@ -547,7 +547,7 @@ func (pool *TxPool) Locals() []common.Address {
|
|||
return pool.locals.flatten()
|
||||
}
|
||||
|
||||
// local retrieves all currently known local transactions, groupped by origin
|
||||
// local retrieves all currently known local transactions, grouped by origin
|
||||
// account and sorted by nonce. The returned transaction set is a copy and can be
|
||||
// freely modified by calling code.
|
||||
func (pool *TxPool) local() map[common.Address]types.Transactions {
|
||||
|
|
@ -987,11 +987,11 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
|
|||
if pending > pool.config.GlobalSlots {
|
||||
pendingBeforeCap := pending
|
||||
// Assemble a spam order to penalize large transactors first
|
||||
spammers := prque.New()
|
||||
spammers := prque.New(nil)
|
||||
for addr, list := range pool.pending {
|
||||
// Only evict transactions from high rollers
|
||||
if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots {
|
||||
spammers.Push(addr, float32(list.Len()))
|
||||
spammers.Push(addr, int64(list.Len()))
|
||||
}
|
||||
}
|
||||
// Gradually drop transactions from offenders
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ func LogsBloom(logs []*Log) *big.Int {
|
|||
}
|
||||
|
||||
func bloom9(b []byte) *big.Int {
|
||||
b = crypto.Keccak256(b[:])
|
||||
b = crypto.Keccak256(b)
|
||||
|
||||
r := new(big.Int)
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ var Bloom9 = bloom9
|
|||
|
||||
func BloomLookup(bin Bloom, topic bytesBacked) bool {
|
||||
bloom := bin.Big()
|
||||
cmp := bloom9(topic.Bytes()[:])
|
||||
cmp := bloom9(topic.Bytes())
|
||||
|
||||
return bloom.And(bloom, cmp).Cmp(cmp) == 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ type (
|
|||
)
|
||||
|
||||
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
|
||||
func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
|
||||
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
|
||||
if contract.CodeAddr != nil {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
|
||||
|
|
@ -61,7 +61,7 @@ func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
|
|||
}(evm.interpreter)
|
||||
evm.interpreter = interpreter
|
||||
}
|
||||
return interpreter.Run(contract, input)
|
||||
return interpreter.Run(contract, input, readOnly)
|
||||
}
|
||||
}
|
||||
return nil, ErrNoCompatibleInterpreter
|
||||
|
|
@ -136,10 +136,28 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
|
|||
vmConfig: vmConfig,
|
||||
chainConfig: chainConfig,
|
||||
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]
|
||||
|
||||
return evm
|
||||
|
|
@ -210,7 +228,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
|
||||
}()
|
||||
}
|
||||
ret, err = run(evm, contract, input)
|
||||
ret, err = run(evm, contract, input, false)
|
||||
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
|
|
@ -255,7 +273,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
contract := NewContract(caller, to, value, gas)
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
|
||||
ret, err = run(evm, contract, input)
|
||||
ret, err = run(evm, contract, input, false)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != errExecutionReverted {
|
||||
|
|
@ -288,7 +306,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
contract := NewContract(caller, to, nil, gas).AsDelegate()
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
|
||||
ret, err = run(evm, contract, input)
|
||||
ret, err = run(evm, contract, input, false)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != errExecutionReverted {
|
||||
|
|
@ -310,13 +328,6 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
}
|
||||
// Make sure the readonly is only set if we aren't in readonly yet
|
||||
// this makes also sure that the readonly flag isn't removed for
|
||||
// child calls.
|
||||
if !evm.interpreter.IsReadOnly() {
|
||||
evm.interpreter.SetReadOnly(true)
|
||||
defer func() { evm.interpreter.SetReadOnly(false) }()
|
||||
}
|
||||
|
||||
var (
|
||||
to = AccountRef(addr)
|
||||
|
|
@ -331,7 +342,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in Homestead this also counts for code storage gas errors.
|
||||
ret, err = run(evm, contract, input)
|
||||
ret, err = run(evm, contract, input, true)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != errExecutionReverted {
|
||||
|
|
@ -382,7 +393,7 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||
}
|
||||
start := time.Now()
|
||||
|
||||
ret, err := run(evm, contract, nil)
|
||||
ret, err := run(evm, contract, nil, false)
|
||||
|
||||
// check whether the max code size has been exceeded
|
||||
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
|
||||
|
|
|
|||
|
|
@ -118,24 +118,69 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *
|
|||
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var (
|
||||
y, x = stack.Back(1), stack.Back(0)
|
||||
val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||
)
|
||||
// This checks for 3 scenario's and calculates gas accordingly
|
||||
// The legacy gas metering only takes into consideration the current state
|
||||
if !evm.chainRules.IsConstantinople {
|
||||
// This checks for 3 scenario's and calculates gas accordingly:
|
||||
//
|
||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||
// 2. From a non-zero value address to a zero-value address (DELETE)
|
||||
// 3. From a non-zero to a non-zero (CHANGE)
|
||||
if val == (common.Hash{}) && y.Sign() != 0 {
|
||||
// 0 => non 0
|
||||
switch {
|
||||
case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0
|
||||
return params.SstoreSetGas, nil
|
||||
} else if val != (common.Hash{}) && y.Sign() == 0 {
|
||||
// non 0 => 0
|
||||
case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0
|
||||
evm.StateDB.AddRefund(params.SstoreRefundGas)
|
||||
return params.SstoreClearGas, nil
|
||||
} else {
|
||||
// non 0 => non 0 (or 0 => 0)
|
||||
default: // non 0 => non 0 (or 0 => 0)
|
||||
return params.SstoreResetGas, nil
|
||||
}
|
||||
}
|
||||
// The new gas metering is based on net gas costs (EIP-1283):
|
||||
//
|
||||
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
|
||||
// 2. If current value does not equal new value
|
||||
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
|
||||
// 2.1.1. If original value is 0, 20000 gas is deducted.
|
||||
// 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter.
|
||||
// 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
|
||||
// 2.2.1. If original value is not 0
|
||||
// 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
|
||||
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
|
||||
// 2.2.2. If original value equals new value (this storage slot is reset)
|
||||
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
|
||||
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
|
||||
value := common.BigToHash(y)
|
||||
if current == value { // noop (1)
|
||||
return params.NetSstoreNoopGas, nil
|
||||
}
|
||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
||||
if original == current {
|
||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||
return params.NetSstoreInitGas, nil
|
||||
}
|
||||
if value == (common.Hash{}) { // delete slot (2.1.2b)
|
||||
evm.StateDB.AddRefund(params.NetSstoreClearRefund)
|
||||
}
|
||||
return params.NetSstoreCleanGas, nil // write existing slot (2.1.2)
|
||||
}
|
||||
if original != (common.Hash{}) {
|
||||
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
|
||||
evm.StateDB.SubRefund(params.NetSstoreClearRefund)
|
||||
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
|
||||
evm.StateDB.AddRefund(params.NetSstoreClearRefund)
|
||||
}
|
||||
}
|
||||
if original == value {
|
||||
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
||||
evm.StateDB.AddRefund(params.NetSstoreResetClearRefund)
|
||||
} else { // reset to original existing slot (2.2.2.2)
|
||||
evm.StateDB.AddRefund(params.NetSstoreResetRefund)
|
||||
}
|
||||
}
|
||||
return params.NetSstoreDirtyGas, nil
|
||||
}
|
||||
|
||||
func makeGasLog(n uint64) gasFunc {
|
||||
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
|
|||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
||||
|
||||
if shift.Cmp(common.Big256) >= 0 {
|
||||
if value.Sign() > 0 {
|
||||
if value.Sign() >= 0 {
|
||||
value.SetUint64(0)
|
||||
} else {
|
||||
value.SetInt64(-1)
|
||||
|
|
@ -727,7 +727,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
|||
}
|
||||
|
||||
func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas in in interpreter.evm.callGasTemp.
|
||||
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
|
||||
interpreter.intPool.put(stack.pop())
|
||||
gas := interpreter.evm.callGasTemp
|
||||
// Pop other call parameters.
|
||||
|
|
|
|||
|
|
@ -40,8 +40,10 @@ type StateDB interface {
|
|||
GetCodeSize(common.Address) int
|
||||
|
||||
AddRefund(uint64)
|
||||
SubRefund(uint64)
|
||||
GetRefund() uint64
|
||||
|
||||
GetCommittedState(common.Address, common.Hash) common.Hash
|
||||
GetState(common.Address, common.Hash) common.Hash
|
||||
SetState(common.Address, common.Hash, common.Hash)
|
||||
|
||||
|
|
@ -64,7 +66,7 @@ type StateDB interface {
|
|||
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool)
|
||||
}
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
// depends on this context being implemented for doing subcalls and initialising new EVM contracts.
|
||||
type CallContext interface {
|
||||
// Call another contract
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ type Config struct {
|
|||
// may be left uninitialised and will be set to the default
|
||||
// table.
|
||||
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
|
||||
|
|
@ -48,7 +53,7 @@ type Config struct {
|
|||
type Interpreter interface {
|
||||
// Run loops and evaluates the contract's code with the given input data and returns
|
||||
// the return byte-slice and an error if one occurred.
|
||||
Run(contract *Contract, input []byte) ([]byte, error)
|
||||
Run(contract *Contract, input []byte, static bool) ([]byte, error)
|
||||
// CanRun tells if the contract, passed as an argument, can be
|
||||
// run by the current interpreter. This is meant so that the
|
||||
// caller can do something like:
|
||||
|
|
@ -61,10 +66,6 @@ type Interpreter interface {
|
|||
// }
|
||||
// ```
|
||||
CanRun([]byte) bool
|
||||
// IsReadOnly reports if the interpreter is in read only mode.
|
||||
IsReadOnly() bool
|
||||
// SetReadOnly sets (or unsets) read only mode in the interpreter.
|
||||
SetReadOnly(bool)
|
||||
}
|
||||
|
||||
// EVMInterpreter represents an EVM interpreter
|
||||
|
|
@ -125,7 +126,7 @@ func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, st
|
|||
// It's important to note that any errors returned by the interpreter should be
|
||||
// considered a revert-and-consume-all-gas operation except for
|
||||
// errExecutionReverted which means revert-and-keep-gas-left.
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
|
||||
if in.intPool == nil {
|
||||
in.intPool = poolOfIntPools.get()
|
||||
defer func() {
|
||||
|
|
@ -138,6 +139,13 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err
|
|||
in.evm.depth++
|
||||
defer func() { in.evm.depth-- }()
|
||||
|
||||
// Make sure the readOnly is only set if we aren't in readOnly yet.
|
||||
// This makes also sure that the readOnly flag isn't removed for child calls.
|
||||
if readOnly && !in.readOnly {
|
||||
in.readOnly = true
|
||||
defer func() { in.readOnly = false }()
|
||||
}
|
||||
|
||||
// Reset the previous call's return data. It's unimportant to preserve the old buffer
|
||||
// as every returning call will return new data anyway.
|
||||
in.returnData = nil
|
||||
|
|
@ -263,13 +271,3 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err
|
|||
func (in *EVMInterpreter) CanRun(code []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsReadOnly reports if the interpreter is in read only mode.
|
||||
func (in *EVMInterpreter) IsReadOnly() bool {
|
||||
return in.readOnly
|
||||
}
|
||||
|
||||
// SetReadOnly sets (or unsets) read only mode in the interpreter.
|
||||
func (in *EVMInterpreter) SetReadOnly(ro bool) {
|
||||
in.readOnly = ro
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,11 +41,6 @@ func (d *dummyContractRef) SetBalance(*big.Int) {}
|
|||
func (d *dummyContractRef) SetNonce(uint64) {}
|
||||
func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) }
|
||||
|
||||
type dummyStateDB struct {
|
||||
NoopStateDB
|
||||
ref *dummyContractRef
|
||||
}
|
||||
|
||||
func TestStoreCapture(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ type Memory struct {
|
|||
lastGasCost uint64
|
||||
}
|
||||
|
||||
// NewMemory returns a new memory memory model.
|
||||
// NewMemory returns a new memory model.
|
||||
func NewMemory() *Memory {
|
||||
return &Memory{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
// 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 vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func NoopCanTransfer(db StateDB, from common.Address, balance *big.Int) bool {
|
||||
return true
|
||||
}
|
||||
func NoopTransfer(db StateDB, from, to common.Address, amount *big.Int) {}
|
||||
|
||||
type NoopEVMCallContext struct{}
|
||||
|
||||
func (NoopEVMCallContext) Call(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (NoopEVMCallContext) CallCode(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (NoopEVMCallContext) Create(caller ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) {
|
||||
return nil, common.Address{}, nil
|
||||
}
|
||||
func (NoopEVMCallContext) DelegateCall(me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type NoopStateDB struct{}
|
||||
|
||||
func (NoopStateDB) CreateAccount(common.Address) {}
|
||||
func (NoopStateDB) SubBalance(common.Address, *big.Int) {}
|
||||
func (NoopStateDB) AddBalance(common.Address, *big.Int) {}
|
||||
func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil }
|
||||
func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 }
|
||||
func (NoopStateDB) SetNonce(common.Address, uint64) {}
|
||||
func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} }
|
||||
func (NoopStateDB) GetCode(common.Address) []byte { return nil }
|
||||
func (NoopStateDB) SetCode(common.Address, []byte) {}
|
||||
func (NoopStateDB) GetCodeSize(common.Address) int { return 0 }
|
||||
func (NoopStateDB) AddRefund(uint64) {}
|
||||
func (NoopStateDB) GetRefund() uint64 { return 0 }
|
||||
func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} }
|
||||
func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {}
|
||||
func (NoopStateDB) Suicide(common.Address) bool { return false }
|
||||
func (NoopStateDB) HasSuicided(common.Address) bool { return false }
|
||||
func (NoopStateDB) Exist(common.Address) bool { return false }
|
||||
func (NoopStateDB) Empty(common.Address) bool { return false }
|
||||
func (NoopStateDB) RevertToSnapshot(int) {}
|
||||
func (NoopStateDB) Snapshot() int { return 0 }
|
||||
func (NoopStateDB) AddLog(*types.Log) {}
|
||||
func (NoopStateDB) AddPreimage(common.Hash, []byte) {}
|
||||
func (NoopStateDB) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) {}
|
||||
|
|
@ -54,7 +54,7 @@ static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const se
|
|||
even if r was negative. */
|
||||
static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m);
|
||||
|
||||
/** Right-shift the passed number by bits bits. */
|
||||
/** Right-shift the passed number by bits. */
|
||||
static void secp256k1_num_shift(secp256k1_num *r, int bits);
|
||||
|
||||
/** Check whether a number is zero. */
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
} while(0)
|
||||
|
||||
static void default_illegal_callback_fn(const char* str, void* data) {
|
||||
(void)data;
|
||||
fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
|
||||
abort();
|
||||
}
|
||||
|
|
@ -37,7 +36,6 @@ static const secp256k1_callback default_illegal_callback = {
|
|||
};
|
||||
|
||||
static void default_error_callback_fn(const char* str, void* data) {
|
||||
(void)data;
|
||||
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
|
||||
abort();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// 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) {
|
||||
// Tracing a chain is a **long** operation, only do with subscriptions
|
||||
notifier, supported := rpc.NotifierFromContext(ctx)
|
||||
|
|
|
|||
|
|
@ -149,10 +149,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion)
|
||||
}
|
||||
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}
|
||||
)
|
||||
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.shouldPreserve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -173,7 +177,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil)
|
||||
eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil, eth.isLocalBlock)
|
||||
eth.miner.SetExtra(makeExtraData(config.MinerExtraData))
|
||||
|
||||
eth.APIBackend = &EthAPIBackend{eth, nil}
|
||||
|
|
@ -330,6 +334,60 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
|||
return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
|
||||
}
|
||||
|
||||
// isLocalBlock checks whether the specified block is mined
|
||||
// by local miner accounts.
|
||||
//
|
||||
// We regard two types of accounts as local miner account: etherbase
|
||||
// and accounts specified via `txpool.locals` flag.
|
||||
func (s *Ethereum) isLocalBlock(block *types.Block) bool {
|
||||
author, err := s.engine.Author(block.Header())
|
||||
if err != nil {
|
||||
log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err)
|
||||
return false
|
||||
}
|
||||
// Check whether the given address is etherbase.
|
||||
s.lock.RLock()
|
||||
etherbase := s.etherbase
|
||||
s.lock.RUnlock()
|
||||
if author == etherbase {
|
||||
return true
|
||||
}
|
||||
// Check whether the given address is specified by `txpool.local`
|
||||
// CLI flag.
|
||||
for _, account := range s.config.TxPool.Locals {
|
||||
if account == author {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// shouldPreserve checks whether we should preserve the given block
|
||||
// during the chain reorg depending on whether the author of block
|
||||
// is a local account.
|
||||
func (s *Ethereum) shouldPreserve(block *types.Block) bool {
|
||||
// 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.
|
||||
if _, ok := s.engine.(*clique.Clique); ok {
|
||||
return false
|
||||
}
|
||||
return s.isLocalBlock(block)
|
||||
}
|
||||
|
||||
// SetEtherbase sets the mining reward address.
|
||||
func (s *Ethereum) SetEtherbase(etherbase common.Address) {
|
||||
s.lock.Lock()
|
||||
|
|
@ -362,7 +420,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
s.lock.RUnlock()
|
||||
s.txPool.SetGasPrice(price)
|
||||
|
||||
// Configure the local mining addess
|
||||
// Configure the local mining address
|
||||
eb, err := s.Etherbase()
|
||||
if err != nil {
|
||||
log.Error("Cannot start mining without etherbase", "err", err)
|
||||
|
|
|
|||
|
|
@ -124,6 +124,11 @@ type Config struct {
|
|||
|
||||
// specify time to exit after syncing
|
||||
ExitWhenSynced time.Duration
|
||||
|
||||
// Type of the EWASM interpreter ("" for detault)
|
||||
EWASMInterpreter string
|
||||
// Type of the EVM interpreter ("" for default)
|
||||
EVMInterpreter string
|
||||
}
|
||||
|
||||
type configMarshaling struct {
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -105,11 +105,11 @@ func newQueue() *queue {
|
|||
headerPendPool: make(map[string]*fetchRequest),
|
||||
headerContCh: make(chan bool),
|
||||
blockTaskPool: make(map[common.Hash]*types.Header),
|
||||
blockTaskQueue: prque.New(),
|
||||
blockTaskQueue: prque.New(nil),
|
||||
blockPendPool: make(map[string]*fetchRequest),
|
||||
blockDonePool: make(map[common.Hash]struct{}),
|
||||
receiptTaskPool: make(map[common.Hash]*types.Header),
|
||||
receiptTaskQueue: prque.New(),
|
||||
receiptTaskQueue: prque.New(nil),
|
||||
receiptPendPool: make(map[string]*fetchRequest),
|
||||
receiptDonePool: make(map[common.Hash]struct{}),
|
||||
resultCache: make([]*fetchResult, blockCacheItems),
|
||||
|
|
@ -277,7 +277,7 @@ func (q *queue) ScheduleSkeleton(from uint64, skeleton []*types.Header) {
|
|||
}
|
||||
// Schedule all the header retrieval tasks for the skeleton assembly
|
||||
q.headerTaskPool = make(map[uint64]*types.Header)
|
||||
q.headerTaskQueue = prque.New()
|
||||
q.headerTaskQueue = prque.New(nil)
|
||||
q.headerPeerMiss = make(map[string]map[uint64]struct{}) // Reset availability to correct invalid chains
|
||||
q.headerResults = make([]*types.Header, len(skeleton)*MaxHeaderFetch)
|
||||
q.headerProced = 0
|
||||
|
|
@ -288,7 +288,7 @@ func (q *queue) ScheduleSkeleton(from uint64, skeleton []*types.Header) {
|
|||
index := from + uint64(i*MaxHeaderFetch)
|
||||
|
||||
q.headerTaskPool[index] = header
|
||||
q.headerTaskQueue.Push(index, -float32(index))
|
||||
q.headerTaskQueue.Push(index, -int64(index))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -334,11 +334,11 @@ func (q *queue) Schedule(headers []*types.Header, from uint64) []*types.Header {
|
|||
}
|
||||
// Queue the header for content retrieval
|
||||
q.blockTaskPool[hash] = header
|
||||
q.blockTaskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
q.blockTaskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
|
||||
if q.mode == FastSync {
|
||||
q.receiptTaskPool[hash] = header
|
||||
q.receiptTaskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
q.receiptTaskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
inserts = append(inserts, header)
|
||||
q.headerHead = hash
|
||||
|
|
@ -436,7 +436,7 @@ func (q *queue) ReserveHeaders(p *peerConnection, count int) *fetchRequest {
|
|||
}
|
||||
// Merge all the skipped batches back
|
||||
for _, from := range skip {
|
||||
q.headerTaskQueue.Push(from, -float32(from))
|
||||
q.headerTaskQueue.Push(from, -int64(from))
|
||||
}
|
||||
// Assemble and return the block download request
|
||||
if send == 0 {
|
||||
|
|
@ -542,7 +542,7 @@ func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common
|
|||
}
|
||||
// Merge all the skipped headers back
|
||||
for _, header := range skip {
|
||||
taskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
taskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
if progress {
|
||||
// Wake WaitResults, resultCache was modified
|
||||
|
|
@ -585,10 +585,10 @@ func (q *queue) cancel(request *fetchRequest, taskQueue *prque.Prque, pendPool m
|
|||
defer q.lock.Unlock()
|
||||
|
||||
if request.From > 0 {
|
||||
taskQueue.Push(request.From, -float32(request.From))
|
||||
taskQueue.Push(request.From, -int64(request.From))
|
||||
}
|
||||
for _, header := range request.Headers {
|
||||
taskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
taskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
delete(pendPool, request.Peer.id)
|
||||
}
|
||||
|
|
@ -602,13 +602,13 @@ func (q *queue) Revoke(peerID string) {
|
|||
|
||||
if request, ok := q.blockPendPool[peerID]; ok {
|
||||
for _, header := range request.Headers {
|
||||
q.blockTaskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
q.blockTaskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
delete(q.blockPendPool, peerID)
|
||||
}
|
||||
if request, ok := q.receiptPendPool[peerID]; ok {
|
||||
for _, header := range request.Headers {
|
||||
q.receiptTaskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
q.receiptTaskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
delete(q.receiptPendPool, peerID)
|
||||
}
|
||||
|
|
@ -657,10 +657,10 @@ func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest,
|
|||
|
||||
// Return any non satisfied requests to the pool
|
||||
if request.From > 0 {
|
||||
taskQueue.Push(request.From, -float32(request.From))
|
||||
taskQueue.Push(request.From, -int64(request.From))
|
||||
}
|
||||
for _, header := range request.Headers {
|
||||
taskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
taskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
// Add the peer to the expiry report along the number of failed requests
|
||||
expiries[id] = len(request.Headers)
|
||||
|
|
@ -731,7 +731,7 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, headerProcCh
|
|||
}
|
||||
miss[request.From] = struct{}{}
|
||||
|
||||
q.headerTaskQueue.Push(request.From, -float32(request.From))
|
||||
q.headerTaskQueue.Push(request.From, -int64(request.From))
|
||||
return 0, errors.New("delivery not accepted")
|
||||
}
|
||||
// Clean up a successful fetch and try to deliver any sub-results
|
||||
|
|
@ -854,7 +854,7 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
|
|||
// Return all failed or missing fetches to the queue
|
||||
for _, header := range request.Headers {
|
||||
if header != nil {
|
||||
taskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
taskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||
}
|
||||
}
|
||||
// Wake up WaitResults
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -160,7 +160,7 @@ func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBloc
|
|||
fetching: make(map[common.Hash]*announce),
|
||||
fetched: make(map[common.Hash][]*announce),
|
||||
completing: make(map[common.Hash]*announce),
|
||||
queue: prque.New(),
|
||||
queue: prque.New(nil),
|
||||
queues: make(map[string]int),
|
||||
queued: make(map[common.Hash]*inject),
|
||||
getBlock: getBlock,
|
||||
|
|
@ -299,7 +299,7 @@ func (f *Fetcher) loop() {
|
|||
// If too high up the chain or phase, continue later
|
||||
number := op.block.NumberU64()
|
||||
if number > height+1 {
|
||||
f.queue.Push(op, -float32(number))
|
||||
f.queue.Push(op, -int64(number))
|
||||
if f.queueChangeHook != nil {
|
||||
f.queueChangeHook(hash, true)
|
||||
}
|
||||
|
|
@ -624,7 +624,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
|
|||
}
|
||||
f.queues[peer] = count
|
||||
f.queued[hash] = op
|
||||
f.queue.Push(op, -float32(block.NumberU64()))
|
||||
f.queue.Push(op, -int64(block.NumberU64()))
|
||||
if f.queueChangeHook != nil {
|
||||
f.queueChangeHook(op.block.Hash(), true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
|
@ -147,7 +147,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
|
|||
NodeInfo: func() interface{} {
|
||||
return manager.NodeInfo()
|
||||
},
|
||||
PeerInfo: func(id discover.NodeID) interface{} {
|
||||
PeerInfo: func(id enode.ID) interface{} {
|
||||
if p := manager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil {
|
||||
return p.Info()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
|||
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
||||
gspec = &core.Genesis{Config: config}
|
||||
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)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
|
|||
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
||||
}
|
||||
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)
|
||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||
|
|
@ -148,7 +148,7 @@ func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*te
|
|||
app, net := p2p.MsgPipe()
|
||||
|
||||
// Generate a random id and create the peer
|
||||
var id discover.NodeID
|
||||
var id enode.ID
|
||||
rand.Read(id[:])
|
||||
|
||||
peer := pm.newPeer(version, p2p.NewPeer(id, name, nil), net)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -64,7 +64,7 @@ func (pm *ProtocolManager) syncTransactions(p *peer) {
|
|||
// the transactions in small packs to one peer at a time.
|
||||
func (pm *ProtocolManager) txsyncLoop() {
|
||||
var (
|
||||
pending = make(map[discover.NodeID]*txsync)
|
||||
pending = make(map[enode.ID]*txsync)
|
||||
sending = false // whether a send is active
|
||||
pack = new(txsync) // the pack that is being sent
|
||||
done = make(chan error, 1) // result of the send
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
)
|
||||
|
||||
// Tests that fast sync gets disabled as soon as a real block is successfully
|
||||
|
|
@ -42,8 +42,8 @@ func TestFastSyncDisabling(t *testing.T) {
|
|||
// Sync up the two peers
|
||||
io1, io2 := p2p.MsgPipe()
|
||||
|
||||
go pmFull.handle(pmFull.newPeer(63, p2p.NewPeer(discover.NodeID{}, "empty", nil), io2))
|
||||
go pmEmpty.handle(pmEmpty.newPeer(63, p2p.NewPeer(discover.NodeID{}, "full", nil), io1))
|
||||
go pmFull.handle(pmFull.newPeer(63, p2p.NewPeer(enode.ID{}, "empty", nil), io2))
|
||||
go pmEmpty.handle(pmEmpty.newPeer(63, p2p.NewPeer(enode.ID{}, "full", nil), io1))
|
||||
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
pmEmpty.synchronise(pmEmpty.peers.BestPeer())
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ func (mw *memoryWrapper) pushObject(vm *duktape.Context) {
|
|||
ctx.Pop2()
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(blob))
|
||||
copy(makeSlice(ptr, uint(len(blob))), blob[:])
|
||||
copy(makeSlice(ptr, uint(len(blob))), blob)
|
||||
return 1
|
||||
})
|
||||
vm.PutPropString(obj, "slice")
|
||||
|
|
@ -204,7 +204,7 @@ func (dw *dbWrapper) pushObject(vm *duktape.Context) {
|
|||
code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx)))
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(code))
|
||||
copy(makeSlice(ptr, uint(len(code))), code[:])
|
||||
copy(makeSlice(ptr, uint(len(code))), code)
|
||||
return 1
|
||||
})
|
||||
vm.PutPropString(obj, "getCode")
|
||||
|
|
@ -268,7 +268,7 @@ func (cw *contractWrapper) pushObject(vm *duktape.Context) {
|
|||
blob := cw.contract.Input
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(blob))
|
||||
copy(makeSlice(ptr, uint(len(blob))), blob[:])
|
||||
copy(makeSlice(ptr, uint(len(blob))), blob)
|
||||
return 1
|
||||
})
|
||||
vm.PutPropString(obj, "getInput")
|
||||
|
|
@ -584,7 +584,7 @@ func (jst *Tracer) GetResult() (json.RawMessage, error) {
|
|||
|
||||
case []byte:
|
||||
ptr := jst.vm.PushFixedBuffer(len(val))
|
||||
copy(makeSlice(ptr, uint(len(val))), val[:])
|
||||
copy(makeSlice(ptr, uint(len(val))), val)
|
||||
|
||||
case common.Address:
|
||||
ptr := jst.vm.PushFixedBuffer(20)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ func runTrace(tracer *Tracer) (json.RawMessage, error) {
|
|||
contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
|
||||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
||||
|
||||
_, err := env.Interpreter().Run(contract, []byte{})
|
||||
_, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,15 +155,12 @@ func (db *LDBDatabase) LDB() *leveldb.DB {
|
|||
|
||||
// Meter configures the database metrics collectors and
|
||||
func (db *LDBDatabase) Meter(prefix string) {
|
||||
if metrics.Enabled {
|
||||
// Initialize all the metrics collector at the requested prefix
|
||||
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
||||
db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
|
||||
db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
|
||||
db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
|
||||
db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
|
||||
}
|
||||
// Initialize write delay metrics no matter we are in metric mode or not.
|
||||
db.writeDelayMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil)
|
||||
db.writeDelayNMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", 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
|
||||
// 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.
|
||||
func GoTool(tool string, args ...string) *exec.Cmd {
|
||||
args = append([]string{tool}, args...)
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c
|
|||
// addr = ecrecover(hash, signature)
|
||||
//
|
||||
// Note, the signature must conform to the secp256k1 curve R, S and V values, where
|
||||
// the V value must be be 27 or 28 for legacy reasons.
|
||||
// the V value must be 27 or 28 for legacy reasons.
|
||||
//
|
||||
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
||||
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
|
||||
|
|
|
|||
|
|
@ -1021,7 +1021,7 @@ var formatOutputInt = function (param) {
|
|||
var value = param.staticPart() || "0";
|
||||
|
||||
// check if it's negative number
|
||||
// it it is, return two's complement
|
||||
// it is, return two's complement
|
||||
if (signedIsNegative(value)) {
|
||||
return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
|
||||
}
|
||||
|
|
@ -2250,7 +2250,7 @@ var isAddress = function (address) {
|
|||
// check if it has the basic requirements of an address
|
||||
return false;
|
||||
} else if (/^(0x)?[0-9a-f]{40}$/.test(address) || /^(0x)?[0-9A-F]{40}$/.test(address)) {
|
||||
// If it's all small caps or all all caps, return true
|
||||
// If it's all small caps or all caps, return true
|
||||
return true;
|
||||
} else {
|
||||
// Otherwise check each case
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/light"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ type NodeInfo struct {
|
|||
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
||||
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
|
||||
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.
|
||||
|
|
@ -63,7 +63,7 @@ func (c *lesCommons) makeProtocols(versions []uint) []p2p.Protocol {
|
|||
Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
|
||||
return c.protocolManager.runPeer(version, p, rw)
|
||||
},
|
||||
PeerInfo: func(id discover.NodeID) interface{} {
|
||||
PeerInfo: func(id enode.ID) interface{} {
|
||||
if p := c.protocolManager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil {
|
||||
return p.Info()
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ func (c *lesCommons) makeProtocols(versions []uint) []p2p.Protocol {
|
|||
|
||||
// nodeInfo retrieves some protocol metadata about the running host node.
|
||||
func (c *lesCommons) nodeInfo() interface{} {
|
||||
var cht light.TrustedCheckpoint
|
||||
var cht params.TrustedCheckpoint
|
||||
sections, _, _ := c.chtIndexer.Sections()
|
||||
sections2, _, _ := c.bloomTrieIndexer.Sections()
|
||||
|
||||
|
|
@ -98,8 +98,8 @@ func (c *lesCommons) nodeInfo() interface{} {
|
|||
idxV2 := (sectionIndex+1)*c.iConfig.PairChtSize/c.iConfig.ChtSize - 1
|
||||
chtRoot = light.GetChtRoot(c.chainDb, idxV2, sectionHead)
|
||||
}
|
||||
cht = light.TrustedCheckpoint{
|
||||
SectionIdx: sectionIndex,
|
||||
cht = params.TrustedCheckpoint{
|
||||
SectionIndex: sectionIndex,
|
||||
SectionHead: sectionHead,
|
||||
CHTRoot: chtRoot,
|
||||
BloomRoot: light.GetBloomTrieRoot(c.chainDb, sectionIndex, sectionHead),
|
||||
|
|
|
|||
|
|
@ -114,7 +114,9 @@ func (d *requestDistributor) loop() {
|
|||
d.lock.Lock()
|
||||
elem := d.reqQueue.Front()
|
||||
for elem != nil {
|
||||
close(elem.Value.(*distReq).sentChn)
|
||||
req := elem.Value.(*distReq)
|
||||
close(req.sentChn)
|
||||
req.sentChn = nil
|
||||
elem = elem.Next()
|
||||
}
|
||||
d.lock.Unlock()
|
||||
|
|
|
|||
|
|
@ -213,8 +213,7 @@ func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWrit
|
|||
var entry *poolEntry
|
||||
peer := pm.newPeer(int(version), pm.networkId, p, rw)
|
||||
if pm.serverPool != nil {
|
||||
addr := p.RemoteAddr().(*net.TCPAddr)
|
||||
entry = pm.serverPool.connect(peer, addr.IP, uint16(addr.Port))
|
||||
entry = pm.serverPool.connect(peer, peer.Node())
|
||||
}
|
||||
peer.poolEntry = entry
|
||||
select {
|
||||
|
|
@ -382,7 +381,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
}
|
||||
|
||||
if p.requestAnnounceType == announceTypeSigned {
|
||||
if err := req.checkSignature(p.pubKey); err != nil {
|
||||
if err := req.checkSignature(p.ID()); err != nil {
|
||||
p.Log().Trace("Invalid announcement signature", "err", err)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/les/flowcontrol"
|
||||
"github.com/ethereum/go-ethereum/light"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
|||
if lightSync {
|
||||
chain, _ = light.NewLightChain(odr, gspec.Config, engine)
|
||||
} 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)
|
||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||
panic(err)
|
||||
|
|
@ -221,7 +221,7 @@ func newTestPeer(t *testing.T, name string, version int, pm *ProtocolManager, sh
|
|||
app, net := p2p.MsgPipe()
|
||||
|
||||
// Generate a random id and create the peer
|
||||
var id discover.NodeID
|
||||
var id enode.ID
|
||||
rand.Read(id[:])
|
||||
|
||||
peer := pm.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net)
|
||||
|
|
@ -258,7 +258,7 @@ func newTestPeerPair(name string, version int, pm, pm2 *ProtocolManager) (*peer,
|
|||
app, net := p2p.MsgPipe()
|
||||
|
||||
// Generate a random id and create the peer
|
||||
var id discover.NodeID
|
||||
var id enode.ID
|
||||
rand.Read(id[:])
|
||||
|
||||
peer := pm.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net)
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
|
|||
}
|
||||
|
||||
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
|
||||
|
|
@ -487,7 +487,7 @@ type BloomRequest light.BloomRequest
|
|||
// GetCost returns the cost of the given ODR request according to the serving
|
||||
// peer's cost table (implementation of LesOdrRequest)
|
||||
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
|
||||
|
|
@ -503,13 +503,13 @@ func (r *BloomRequest) CanSend(peer *peer) bool {
|
|||
|
||||
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
|
||||
func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
|
||||
peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList)
|
||||
reqs := make([]HelperTrieReq, len(r.SectionIdxList))
|
||||
peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
|
||||
reqs := make([]HelperTrieReq, len(r.SectionIndexList))
|
||||
|
||||
var encNumber [10]byte
|
||||
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)
|
||||
reqs[i] = HelperTrieReq{
|
||||
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
|
||||
// to the request (implementation of LesOdrRequest)
|
||||
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
|
||||
if msg.MsgType != MsgHelperTrieProofs {
|
||||
|
|
@ -535,13 +535,13 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
|
|||
nodeSet := proofs.NodeSet()
|
||||
reads := &readTraceDB{db: nodeSet}
|
||||
|
||||
r.BloomBits = make([][]byte, len(r.SectionIdxList))
|
||||
r.BloomBits = make([][]byte, len(r.SectionIndexList))
|
||||
|
||||
// Verify the proofs
|
||||
var encNumber [10]byte
|
||||
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)
|
||||
value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package les
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
|
@ -51,7 +50,6 @@ const (
|
|||
|
||||
type peer struct {
|
||||
*p2p.Peer
|
||||
pubKey *ecdsa.PublicKey
|
||||
|
||||
rw p2p.MsgReadWriter
|
||||
|
||||
|
|
@ -80,11 +78,9 @@ type peer struct {
|
|||
|
||||
func newPeer(version int, network uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
|
||||
id := p.ID()
|
||||
pubKey, _ := id.Pubkey()
|
||||
|
||||
return &peer{
|
||||
Peer: p,
|
||||
pubKey: pubKey,
|
||||
rw: rw,
|
||||
version: version,
|
||||
network: network,
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@
|
|||
package les
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -30,7 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
|
|
@ -148,21 +146,20 @@ func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
|
|||
}
|
||||
|
||||
// checkSignature verifies if the block announcement has a valid signature by the given pubKey
|
||||
func (a *announceData) checkSignature(pubKey *ecdsa.PublicKey) error {
|
||||
func (a *announceData) checkSignature(id enode.ID) error {
|
||||
var sig []byte
|
||||
if err := a.Update.decode().get("sign", &sig); err != nil {
|
||||
return err
|
||||
}
|
||||
rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
|
||||
recPubkey, err := secp256k1.RecoverPubkey(crypto.Keccak256(rlp), sig)
|
||||
recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
|
||||
if bytes.Equal(pbytes, recPubkey) {
|
||||
if id == enode.PubkeyToIDV4(recPubkey) {
|
||||
return nil
|
||||
}
|
||||
return errors.New("Wrong signature")
|
||||
return errors.New("wrong signature")
|
||||
}
|
||||
|
||||
type blockInfo struct {
|
||||
|
|
|
|||
|
|
@ -217,6 +217,13 @@ func (r *sentReq) stateRequesting() reqStateFn {
|
|||
go r.tryRequest()
|
||||
r.lastReqQueued = true
|
||||
return r.stateRequesting
|
||||
case rpDeliveredInvalid:
|
||||
// if it was the last sent request (set to nil by update) then start a new one
|
||||
if !r.lastReqQueued && r.lastReqSentTo == nil {
|
||||
go r.tryRequest()
|
||||
r.lastReqQueued = true
|
||||
}
|
||||
return r.stateRequesting
|
||||
case rpDeliveredValid:
|
||||
r.stop(nil)
|
||||
return r.stateStopped
|
||||
|
|
@ -242,7 +249,11 @@ func (r *sentReq) stateNoMorePeers() reqStateFn {
|
|||
r.stop(nil)
|
||||
return r.stateStopped
|
||||
}
|
||||
if r.waiting() {
|
||||
return r.stateNoMorePeers
|
||||
}
|
||||
r.stop(light.ErrNoPeers)
|
||||
return nil
|
||||
case <-r.stopCh:
|
||||
return r.stateStopped
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue