mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
Merge branch 'master' into rpcGolint2
This commit is contained in:
commit
79598a4600
97 changed files with 1225 additions and 823 deletions
|
|
@ -146,7 +146,7 @@ matrix:
|
|||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
before_install:
|
||||
- curl https://storage.googleapis.com/golang/go1.10.2.linux-amd64.tar.gz | tar -xz
|
||||
- curl https://storage.googleapis.com/golang/go1.10.3.linux-amd64.tar.gz | tar -xz
|
||||
- export PATH=`pwd`/go/bin:$PATH
|
||||
- export GOROOT=`pwd`/go
|
||||
- export GOPATH=$HOME/go
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1.8.11
|
||||
1.8.12
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ var (
|
|||
var KeyStoreType = reflect.TypeOf(&KeyStore{})
|
||||
|
||||
// KeyStoreScheme is the protocol scheme prefixing account and wallet URLs.
|
||||
var KeyStoreScheme = "keystore"
|
||||
const KeyStoreScheme = "keystore"
|
||||
|
||||
// Maximum time between wallet refreshes (if filesystem notifications don't work).
|
||||
const walletRefreshCycle = 3 * time.Second
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ environment:
|
|||
install:
|
||||
- git submodule update --init
|
||||
- rmdir C:\go /s /q
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.2.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.10.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- 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
|
||||
- go version
|
||||
- gcc --version
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
// 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/>.
|
||||
|
||||
// simple nonconcurrent reference implementation for hashsize segment based
|
||||
// Package bmt is a simple nonconcurrent reference implementation for hashsize segment based
|
||||
// Binary Merkle tree hash on arbitrary but fixed maximum chunksize
|
||||
//
|
||||
// This implementation does not take advantage of any paralellisms and uses
|
||||
|
|
|
|||
|
|
@ -330,6 +330,7 @@ func doLint(cmdline []string) {
|
|||
configs := []string{
|
||||
"--vendor",
|
||||
"--tests",
|
||||
"--deadline=2m",
|
||||
"--disable-all",
|
||||
"--enable=goimports",
|
||||
"--enable=varcheck",
|
||||
|
|
|
|||
72
cmd/ethkey/changepassphrase.go
Normal file
72
cmd/ethkey/changepassphrase.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
var newPassphraseFlag = cli.StringFlag{
|
||||
Name: "newpasswordfile",
|
||||
Usage: "the file that contains the new passphrase for the keyfile",
|
||||
}
|
||||
|
||||
var commandChangePassphrase = cli.Command{
|
||||
Name: "changepassphrase",
|
||||
Usage: "change the passphrase on a keyfile",
|
||||
ArgsUsage: "<keyfile>",
|
||||
Description: `
|
||||
Change the passphrase of a keyfile.`,
|
||||
Flags: []cli.Flag{
|
||||
passphraseFlag,
|
||||
newPassphraseFlag,
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
keyfilepath := ctx.Args().First()
|
||||
|
||||
// Read key from file.
|
||||
keyjson, err := ioutil.ReadFile(keyfilepath)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err)
|
||||
}
|
||||
|
||||
// Decrypt key with passphrase.
|
||||
passphrase := getPassphrase(ctx)
|
||||
key, err := keystore.DecryptKey(keyjson, passphrase)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error decrypting key: %v", err)
|
||||
}
|
||||
|
||||
// Get a new passphrase.
|
||||
fmt.Println("Please provide a new passphrase")
|
||||
var newPhrase string
|
||||
if passFile := ctx.String(newPassphraseFlag.Name); passFile != "" {
|
||||
content, err := ioutil.ReadFile(passFile)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read new passphrase file '%s': %v", passFile, err)
|
||||
}
|
||||
newPhrase = strings.TrimRight(string(content), "\r\n")
|
||||
} else {
|
||||
newPhrase = promptPassphrase(true)
|
||||
}
|
||||
|
||||
// Encrypt the key with the new passphrase.
|
||||
newJson, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error encrypting with new passphrase: %v", err)
|
||||
}
|
||||
|
||||
// Then write the new keyfile in place of the old one.
|
||||
if err := ioutil.WriteFile(keyfilepath, newJson, 600); err != nil {
|
||||
utils.Fatalf("Error writing new keyfile to disk: %v", err)
|
||||
}
|
||||
|
||||
// Don't print anything. Just return successfully,
|
||||
// producing a positive exit code.
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ If you want to encrypt an existing private key, it can be specified by setting
|
|||
}
|
||||
|
||||
// Encrypt key with passphrase.
|
||||
passphrase := getPassPhrase(ctx, true)
|
||||
passphrase := promptPassphrase(true)
|
||||
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error encrypting key: %v", err)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ make sure to use this feature with great caution!`,
|
|||
}
|
||||
|
||||
// Decrypt key with passphrase.
|
||||
passphrase := getPassPhrase(ctx, false)
|
||||
passphrase := getPassphrase(ctx)
|
||||
key, err := keystore.DecryptKey(keyjson, passphrase)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error decrypting key: %v", err)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ func init() {
|
|||
app.Commands = []cli.Command{
|
||||
commandGenerate,
|
||||
commandInspect,
|
||||
commandChangePassphrase,
|
||||
commandSignMessage,
|
||||
commandVerifyMessage,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ To sign a message contained in a file, use the --msgfile flag.
|
|||
}
|
||||
|
||||
// Decrypt key with passphrase.
|
||||
passphrase := getPassPhrase(ctx, false)
|
||||
passphrase := getPassphrase(ctx)
|
||||
key, err := keystore.DecryptKey(keyjson, passphrase)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error decrypting key: %v", err)
|
||||
|
|
|
|||
|
|
@ -28,11 +28,32 @@ import (
|
|||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// getPassPhrase obtains a passphrase given by the user. It first checks the
|
||||
// --passphrase command line flag and ultimately prompts the user for a
|
||||
// promptPassphrase prompts the user for a passphrase. Set confirmation to true
|
||||
// to require the user to confirm the passphrase.
|
||||
func promptPassphrase(confirmation bool) string {
|
||||
passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||
}
|
||||
|
||||
if confirmation {
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
|
||||
}
|
||||
if passphrase != confirm {
|
||||
utils.Fatalf("Passphrases do not match")
|
||||
}
|
||||
}
|
||||
|
||||
return passphrase
|
||||
}
|
||||
|
||||
// getPassphrase obtains a passphrase given by the user. It first checks the
|
||||
// --passfile command line flag and ultimately prompts the user for a
|
||||
// passphrase.
|
||||
func getPassPhrase(ctx *cli.Context, confirmation bool) string {
|
||||
// Look for the --passphrase flag.
|
||||
func getPassphrase(ctx *cli.Context) string {
|
||||
// Look for the --passwordfile flag.
|
||||
passphraseFile := ctx.String(passphraseFlag.Name)
|
||||
if passphraseFile != "" {
|
||||
content, err := ioutil.ReadFile(passphraseFile)
|
||||
|
|
@ -44,20 +65,7 @@ func getPassPhrase(ctx *cli.Context, confirmation bool) string {
|
|||
}
|
||||
|
||||
// Otherwise prompt the user for the passphrase.
|
||||
passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||
}
|
||||
if confirmation {
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
|
||||
}
|
||||
if passphrase != confirm {
|
||||
utils.Fatalf("Passphrases do not match")
|
||||
}
|
||||
}
|
||||
return passphrase
|
||||
return promptPassphrase(false)
|
||||
}
|
||||
|
||||
// signHash is a helper function that calculates a hash for the given message
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ func (w *wizard) deployNode(boot bool) {
|
|||
// Ethash based miners only need an etherbase to mine against
|
||||
fmt.Println()
|
||||
if infos.etherbase == "" {
|
||||
fmt.Printf("What address should the miner user?\n")
|
||||
fmt.Printf("What address should the miner use?\n")
|
||||
for {
|
||||
if address := w.readAddress(); address != nil {
|
||||
infos.etherbase = address.Hex()
|
||||
|
|
@ -115,7 +115,7 @@ func (w *wizard) deployNode(boot bool) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("What address should the miner user? (default = %s)\n", infos.etherbase)
|
||||
fmt.Printf("What address should the miner use? (default = %s)\n", infos.etherbase)
|
||||
infos.etherbase = w.readDefaultAddress(common.HexToAddress(infos.etherbase)).Hex()
|
||||
}
|
||||
} else if w.conf.Genesis.Config.Clique != nil {
|
||||
|
|
|
|||
|
|
@ -1084,6 +1084,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
|
|||
}
|
||||
cfg.Genesis = core.DefaultRinkebyGenesisBlock()
|
||||
case ctx.GlobalBool(DeveloperFlag.Name):
|
||||
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 1337
|
||||
}
|
||||
// Create new developer account or reuse existing one
|
||||
var (
|
||||
developer accounts.Account
|
||||
|
|
|
|||
|
|
@ -140,8 +140,8 @@ func processArgs() {
|
|||
}
|
||||
|
||||
if *asymmetricMode && len(*argPub) > 0 {
|
||||
pub = crypto.ToECDSAPub(common.FromHex(*argPub))
|
||||
if !isKeyValid(pub) {
|
||||
var err error
|
||||
if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil {
|
||||
utils.Fatalf("invalid public key")
|
||||
}
|
||||
}
|
||||
|
|
@ -321,10 +321,6 @@ func startServer() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func isKeyValid(k *ecdsa.PublicKey) bool {
|
||||
return k.X != nil && k.Y != nil
|
||||
}
|
||||
|
||||
func configureNode() {
|
||||
var err error
|
||||
var p2pAccept bool
|
||||
|
|
@ -340,9 +336,8 @@ func configureNode() {
|
|||
if b == nil {
|
||||
utils.Fatalf("Error: can not convert hexadecimal string")
|
||||
}
|
||||
pub = crypto.ToECDSAPub(b)
|
||||
if !isKeyValid(pub) {
|
||||
utils.Fatalf("Error: invalid public key")
|
||||
if pub, err = crypto.UnmarshalPubkey(b); err != nil {
|
||||
utils.Fatalf("Error: invalid peer public key")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import (
|
|||
|
||||
const uintBits = 32 << (uint64(^uint(0)) >> 63)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrEmptyString = &decError{"empty hex string"}
|
||||
ErrSyntax = &decError{"invalid hex string"}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,13 @@ import (
|
|||
"math/big"
|
||||
)
|
||||
|
||||
// Various big integer limit values.
|
||||
var (
|
||||
tt255 = BigPow(2, 255)
|
||||
tt256 = BigPow(2, 256)
|
||||
tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
|
||||
MaxBig256 = new(big.Int).Set(tt256m1)
|
||||
tt63 = BigPow(2, 63)
|
||||
MaxBig256 = new(big.Int).Set(tt256m1)
|
||||
MaxBig63 = new(big.Int).Sub(tt63, big.NewInt(1))
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
// Integer limit values.
|
||||
const (
|
||||
// Integer limit values.
|
||||
MaxInt8 = 1<<7 - 1
|
||||
MinInt8 = -1 << 7
|
||||
MaxInt16 = 1<<15 - 1
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
// 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 mclock is a wrapper for a monotonic clock source
|
||||
// Package mclock is a wrapper for a monotonic clock source
|
||||
package mclock
|
||||
|
||||
import (
|
||||
|
|
@ -23,8 +23,10 @@ import (
|
|||
"github.com/aristanetworks/goarista/monotime"
|
||||
)
|
||||
|
||||
type AbsTime time.Duration // absolute monotonic time
|
||||
// AbsTime represents absolute monotonic time.
|
||||
type AbsTime time.Duration
|
||||
|
||||
// Now returns the current absolute monotonic time.
|
||||
func Now() AbsTime {
|
||||
return AbsTime(monotime.Now())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,196 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package number
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
|
||||
var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
|
||||
var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
|
||||
|
||||
func limitUnsigned256(x *Number) *Number {
|
||||
x.num.And(x.num, tt256m1)
|
||||
return x
|
||||
}
|
||||
|
||||
func limitSigned256(x *Number) *Number {
|
||||
if x.num.Cmp(tt255) < 0 {
|
||||
return x
|
||||
}
|
||||
x.num.Sub(x.num, tt256)
|
||||
return x
|
||||
}
|
||||
|
||||
// Initialiser is a Number function
|
||||
type Initialiser func(n int64) *Number
|
||||
|
||||
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
|
||||
// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda
|
||||
// with the new Initialiser.
|
||||
type Number struct {
|
||||
num *big.Int
|
||||
limit func(n *Number) *Number
|
||||
}
|
||||
|
||||
// NewInitialiser returns a new initialiser for a new *Number without having to expose certain fields
|
||||
func NewInitialiser(limiter func(*Number) *Number) Initialiser {
|
||||
return func(n int64) *Number {
|
||||
return &Number{big.NewInt(n), limiter}
|
||||
}
|
||||
}
|
||||
|
||||
// Uint256 returns a Number with a UNSIGNED limiter up to 256 bits
|
||||
func Uint256(n int64) *Number {
|
||||
return &Number{big.NewInt(n), limitUnsigned256}
|
||||
}
|
||||
|
||||
// Int256 returns Number with a SIGNED limiter up to 256 bits
|
||||
func Int256(n int64) *Number {
|
||||
return &Number{big.NewInt(n), limitSigned256}
|
||||
}
|
||||
|
||||
// Big returns a Number with a SIGNED unlimited size
|
||||
func Big(n int64) *Number {
|
||||
return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
|
||||
}
|
||||
|
||||
// Add sets i to sum of x+y
|
||||
func (i *Number) Add(x, y *Number) *Number {
|
||||
i.num.Add(x.num, y.num)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Sub sets i to difference of x-y
|
||||
func (i *Number) Sub(x, y *Number) *Number {
|
||||
i.num.Sub(x.num, y.num)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Mul sets i to product of x*y
|
||||
func (i *Number) Mul(x, y *Number) *Number {
|
||||
i.num.Mul(x.num, y.num)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Div sets i to the quotient prodject of x/y
|
||||
func (i *Number) Div(x, y *Number) *Number {
|
||||
i.num.Div(x.num, y.num)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Mod sets i to x % y
|
||||
func (i *Number) Mod(x, y *Number) *Number {
|
||||
i.num.Mod(x.num, y.num)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Lsh sets i to x << s
|
||||
func (i *Number) Lsh(x *Number, s uint) *Number {
|
||||
i.num.Lsh(x.num, s)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Pow sets i to x^y
|
||||
func (i *Number) Pow(x, y *Number) *Number {
|
||||
i.num.Exp(x.num, y.num, big.NewInt(0))
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
// Set sets x to i
|
||||
func (i *Number) Set(x *Number) *Number {
|
||||
i.num.Set(x.num)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// SetBytes sets x bytes to i
|
||||
func (i *Number) SetBytes(x []byte) *Number {
|
||||
i.num.SetBytes(x)
|
||||
return i.limit(i)
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
func (i *Number) Cmp(x *Number) int {
|
||||
return i.num.Cmp(x.num)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
// String returns the string representation of i
|
||||
func (i *Number) String() string {
|
||||
return i.num.String()
|
||||
}
|
||||
|
||||
// Bytes returns the byte representation of i
|
||||
func (i *Number) Bytes() []byte {
|
||||
return i.num.Bytes()
|
||||
}
|
||||
|
||||
// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined.
|
||||
func (i *Number) Uint64() uint64 {
|
||||
return i.num.Uint64()
|
||||
}
|
||||
|
||||
// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined.
|
||||
func (i *Number) Int64() int64 {
|
||||
return i.num.Int64()
|
||||
}
|
||||
|
||||
// Int256 returns the signed version of i
|
||||
func (i *Number) Int256() *Number {
|
||||
return Int(0).Set(i)
|
||||
}
|
||||
|
||||
// Uint256 returns the unsigned version of i
|
||||
func (i *Number) Uint256() *Number {
|
||||
return Uint(0).Set(i)
|
||||
}
|
||||
|
||||
// FirstBitSet returns the index of the first bit that's set to 1
|
||||
func (i *Number) FirstBitSet() int {
|
||||
for j := 0; j < i.num.BitLen(); j++ {
|
||||
if i.num.Bit(j) > 0 {
|
||||
return j
|
||||
}
|
||||
}
|
||||
|
||||
return i.num.BitLen()
|
||||
}
|
||||
|
||||
// Variables
|
||||
|
||||
var (
|
||||
Zero = Uint(0)
|
||||
One = Uint(1)
|
||||
Two = Uint(2)
|
||||
MaxUint256 = Uint(0).SetBytes(common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
||||
|
||||
MinOne = Int(-1)
|
||||
|
||||
// "typedefs"
|
||||
Uint = Uint256
|
||||
Int = Int256
|
||||
)
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package number
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
a := Uint(0)
|
||||
b := Uint(10)
|
||||
a.Set(b)
|
||||
if a.num.Cmp(b.num) != 0 {
|
||||
t.Error("didn't compare", a, b)
|
||||
}
|
||||
|
||||
c := Uint(0).SetBytes(common.Hex2Bytes("0a"))
|
||||
if c.num.Cmp(big.NewInt(10)) != 0 {
|
||||
t.Error("c set bytes failed.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitialiser(t *testing.T) {
|
||||
check := false
|
||||
init := NewInitialiser(func(x *Number) *Number {
|
||||
check = true
|
||||
return x
|
||||
})
|
||||
a := init(0).Add(init(1), init(2))
|
||||
if a.Cmp(init(3)) != 0 {
|
||||
t.Error("expected 3. got", a)
|
||||
}
|
||||
if !check {
|
||||
t.Error("expected limiter to be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
a := Uint(10)
|
||||
if a.Uint64() != 10 {
|
||||
t.Error("expected to get 10. got", a.Uint64())
|
||||
}
|
||||
|
||||
a = Uint(10)
|
||||
if a.Int64() != 10 {
|
||||
t.Error("expected to get 10. got", a.Int64())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmp(t *testing.T) {
|
||||
a := Uint(10)
|
||||
b := Uint(10)
|
||||
c := Uint(11)
|
||||
|
||||
if a.Cmp(b) != 0 {
|
||||
t.Error("a b == 0 failed", a, b)
|
||||
}
|
||||
|
||||
if a.Cmp(c) >= 0 {
|
||||
t.Error("a c < 0 failed", a, c)
|
||||
}
|
||||
|
||||
if c.Cmp(b) <= 0 {
|
||||
t.Error("c b > 0 failed", c, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxArith(t *testing.T) {
|
||||
a := Uint(0).Add(MaxUint256, One)
|
||||
if a.Cmp(Zero) != 0 {
|
||||
t.Error("expected max256 + 1 = 0 got", a)
|
||||
}
|
||||
|
||||
a = Uint(0).Sub(Uint(0), One)
|
||||
if a.Cmp(MaxUint256) != 0 {
|
||||
t.Error("expected 0 - 1 = max256 got", a)
|
||||
}
|
||||
|
||||
a = Int(0).Sub(Int(0), One)
|
||||
if a.Cmp(MinOne) != 0 {
|
||||
t.Error("expected 0 - 1 = -1 got", a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConversion(t *testing.T) {
|
||||
a := Int(-1)
|
||||
b := a.Uint256()
|
||||
if b.Cmp(MaxUint256) != 0 {
|
||||
t.Error("expected -1 => unsigned to return max. got", b)
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
)
|
||||
|
||||
// Lengths of hashes and addresses in bytes.
|
||||
const (
|
||||
HashLength = 32
|
||||
AddressLength = 20
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ type Config struct {
|
|||
Preload []string // Absolute paths to JavaScript files to preload
|
||||
}
|
||||
|
||||
// Console is a JavaScript interpreted runtime environment. It is a fully fleged
|
||||
// Console is a JavaScript interpreted runtime environment. It is a fully fledged
|
||||
// JavaScript console attached to a running node via an external or in-process RPC
|
||||
// client.
|
||||
type Console struct {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func ensParentNode(name string) (common.Hash, common.Hash) {
|
|||
}
|
||||
}
|
||||
|
||||
func ensNode(name string) common.Hash {
|
||||
func EnsNode(name string) common.Hash {
|
||||
parentNode, parentLabel := ensParentNode(name)
|
||||
return crypto.Keccak256Hash(parentNode[:], parentLabel[:])
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ func (self *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, er
|
|||
|
||||
// Resolve is a non-transactional call that returns the content hash associated with a name.
|
||||
func (self *ENS) Resolve(name string) (common.Hash, error) {
|
||||
node := ensNode(name)
|
||||
node := EnsNode(name)
|
||||
|
||||
resolver, err := self.getResolver(node)
|
||||
if err != nil {
|
||||
|
|
@ -165,7 +165,7 @@ func (self *ENS) Register(name string) (*types.Transaction, error) {
|
|||
// SetContentHash sets the content hash associated with a name. Only works if the caller
|
||||
// owns the name, and the associated resolver implements a `setContent` function.
|
||||
func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
|
||||
node := ensNode(name)
|
||||
node := EnsNode(name)
|
||||
|
||||
resolver, err := self.getResolver(node)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func TestENS(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("can't deploy resolver: %v", err)
|
||||
}
|
||||
if _, err := ens.SetResolver(ensNode(name), resolverAddr); err != nil {
|
||||
if _, err := ens.SetResolver(EnsNode(name), resolverAddr); err != nil {
|
||||
t.Fatalf("can't set resolver: %v", err)
|
||||
}
|
||||
contractBackend.Commit()
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func NewCompiler(debug bool) *Compiler {
|
|||
// the compiler.
|
||||
//
|
||||
// feed is the first pass in the compile stage as it
|
||||
// collect the used labels in the program and keeps a
|
||||
// collects the used labels in the program and keeps a
|
||||
// program counter which is used to determine the locations
|
||||
// of the jump dests. The labels can than be used in the
|
||||
// second stage to push labels and determine the right
|
||||
|
|
@ -120,7 +120,7 @@ func (c *Compiler) next() token {
|
|||
return token
|
||||
}
|
||||
|
||||
// compile line compiles a single line instruction e.g.
|
||||
// compileLine compiles a single line instruction e.g.
|
||||
// "push 1", "jump @label".
|
||||
func (c *Compiler) compileLine() error {
|
||||
n := c.next()
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ func lexLabel(l *lexer) stateFn {
|
|||
}
|
||||
|
||||
// lexInsideString lexes the inside of a string until
|
||||
// until the state function finds the closing quote.
|
||||
// the state function finds the closing quote.
|
||||
// It returns the lex text state function.
|
||||
func lexInsideString(l *lexer) stateFn {
|
||||
if l.acceptRunUntil('"') {
|
||||
|
|
|
|||
|
|
@ -1392,27 +1392,21 @@ func (bc *BlockChain) update() {
|
|||
}
|
||||
}
|
||||
|
||||
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
|
||||
type BadBlockArgs struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
Header *types.Header `json:"header"`
|
||||
}
|
||||
|
||||
// BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
||||
func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) {
|
||||
headers := make([]BadBlockArgs, 0, bc.badBlocks.Len())
|
||||
func (bc *BlockChain) BadBlocks() []*types.Block {
|
||||
blocks := make([]*types.Block, 0, bc.badBlocks.Len())
|
||||
for _, hash := range bc.badBlocks.Keys() {
|
||||
if hdr, exist := bc.badBlocks.Peek(hash); exist {
|
||||
header := hdr.(*types.Header)
|
||||
headers = append(headers, BadBlockArgs{header.Hash(), header})
|
||||
if blk, exist := bc.badBlocks.Peek(hash); exist {
|
||||
block := blk.(*types.Block)
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
}
|
||||
return headers, nil
|
||||
return blocks
|
||||
}
|
||||
|
||||
// addBadBlock adds a bad block to the bad-block LRU cache
|
||||
func (bc *BlockChain) addBadBlock(block *types.Block) {
|
||||
bc.badBlocks.Add(block.Header().Hash(), block.Header())
|
||||
bc.badBlocks.Add(block.Hash(), block)
|
||||
}
|
||||
|
||||
// reportBlock logs a bad block error.
|
||||
|
|
@ -1530,6 +1524,18 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com
|
|||
return bc.hc.GetBlockHashesFromHash(hash, max)
|
||||
}
|
||||
|
||||
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
|
||||
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
|
||||
// number of blocks to be individually checked before we reach the canonical chain.
|
||||
//
|
||||
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
||||
func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
|
||||
bc.chainmu.Lock()
|
||||
defer bc.chainmu.Unlock()
|
||||
|
||||
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
|
||||
}
|
||||
|
||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||
// caching it (associated with its hash) if found.
|
||||
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||
|
|
|
|||
|
|
@ -307,6 +307,43 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
|
|||
return chain
|
||||
}
|
||||
|
||||
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
|
||||
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
|
||||
// number of blocks to be individually checked before we reach the canonical chain.
|
||||
//
|
||||
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
||||
func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
|
||||
if ancestor > number {
|
||||
return common.Hash{}, 0
|
||||
}
|
||||
if ancestor == 1 {
|
||||
// in this case it is cheaper to just read the header
|
||||
if header := hc.GetHeader(hash, number); header != nil {
|
||||
return header.ParentHash, number - 1
|
||||
} else {
|
||||
return common.Hash{}, 0
|
||||
}
|
||||
}
|
||||
for ancestor != 0 {
|
||||
if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash {
|
||||
number -= ancestor
|
||||
return rawdb.ReadCanonicalHash(hc.chainDb, number), number
|
||||
}
|
||||
if *maxNonCanonical == 0 {
|
||||
return common.Hash{}, 0
|
||||
}
|
||||
*maxNonCanonical--
|
||||
ancestor--
|
||||
header := hc.GetHeader(hash, number)
|
||||
if header == nil {
|
||||
return common.Hash{}, 0
|
||||
}
|
||||
hash = header.ParentHash
|
||||
number--
|
||||
}
|
||||
return hash, number
|
||||
}
|
||||
|
||||
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||
// database by hash and number, caching it if found.
|
||||
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import (
|
|||
|
||||
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
|
||||
func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
|
||||
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...))
|
||||
data, _ := db.Get(headerHashKey(number))
|
||||
if len(data) == 0 {
|
||||
return common.Hash{}
|
||||
}
|
||||
|
|
@ -38,22 +38,21 @@ func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
|
|||
|
||||
// WriteCanonicalHash stores the hash assigned to a canonical block number.
|
||||
func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
|
||||
key := append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
|
||||
if err := db.Put(key, hash.Bytes()); err != nil {
|
||||
if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {
|
||||
log.Crit("Failed to store number to hash mapping", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteCanonicalHash removes the number to hash canonical mapping.
|
||||
func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
|
||||
if err := db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)); err != nil {
|
||||
if err := db.Delete(headerHashKey(number)); err != nil {
|
||||
log.Crit("Failed to delete number to hash mapping", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadHeaderNumber returns the header number assigned to a hash.
|
||||
func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
|
||||
data, _ := db.Get(append(headerNumberPrefix, hash.Bytes()...))
|
||||
data, _ := db.Get(headerNumberKey(hash))
|
||||
if len(data) != 8 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -129,14 +128,13 @@ func WriteFastTrieProgress(db DatabaseWriter, count uint64) {
|
|||
|
||||
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
|
||||
func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||
data, _ := db.Get(headerKey(number, hash))
|
||||
return data
|
||||
}
|
||||
|
||||
// HasHeader verifies the existence of a block header corresponding to the hash.
|
||||
func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
|
||||
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||
if has, err := db.Has(key); !has || err != nil {
|
||||
if has, err := db.Has(headerKey(number, hash)); !has || err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
@ -161,11 +159,11 @@ func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Heade
|
|||
func WriteHeader(db DatabaseWriter, header *types.Header) {
|
||||
// Write the hash -> number mapping
|
||||
var (
|
||||
hash = header.Hash().Bytes()
|
||||
hash = header.Hash()
|
||||
number = header.Number.Uint64()
|
||||
encoded = encodeBlockNumber(number)
|
||||
)
|
||||
key := append(headerNumberPrefix, hash...)
|
||||
key := headerNumberKey(hash)
|
||||
if err := db.Put(key, encoded); err != nil {
|
||||
log.Crit("Failed to store hash to number mapping", "err", err)
|
||||
}
|
||||
|
|
@ -174,7 +172,7 @@ func WriteHeader(db DatabaseWriter, header *types.Header) {
|
|||
if err != nil {
|
||||
log.Crit("Failed to RLP encode header", "err", err)
|
||||
}
|
||||
key = append(append(headerPrefix, encoded...), hash...)
|
||||
key = headerKey(number, hash)
|
||||
if err := db.Put(key, data); err != nil {
|
||||
log.Crit("Failed to store header", "err", err)
|
||||
}
|
||||
|
|
@ -182,32 +180,30 @@ func WriteHeader(db DatabaseWriter, header *types.Header) {
|
|||
|
||||
// DeleteHeader removes all block header data associated with a hash.
|
||||
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||
if err := db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil {
|
||||
if err := db.Delete(headerKey(number, hash)); err != nil {
|
||||
log.Crit("Failed to delete header", "err", err)
|
||||
}
|
||||
if err := db.Delete(append(headerNumberPrefix, hash.Bytes()...)); err != nil {
|
||||
if err := db.Delete(headerNumberKey(hash)); err != nil {
|
||||
log.Crit("Failed to delete hash to number mapping", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
|
||||
func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||
data, _ := db.Get(append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||
data, _ := db.Get(blockBodyKey(number, hash))
|
||||
return data
|
||||
}
|
||||
|
||||
// WriteBodyRLP stores an RLP encoded block body into the database.
|
||||
func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
|
||||
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
if err := db.Put(key, rlp); err != nil {
|
||||
if err := db.Put(blockBodyKey(number, hash), rlp); err != nil {
|
||||
log.Crit("Failed to store block body", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// HasBody verifies the existence of a block body corresponding to the hash.
|
||||
func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
|
||||
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
if has, err := db.Has(key); !has || err != nil {
|
||||
if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
@ -238,14 +234,14 @@ func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.B
|
|||
|
||||
// DeleteBody removes all block body data associated with a hash.
|
||||
func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||
if err := db.Delete(append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil {
|
||||
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
|
||||
log.Crit("Failed to delete block body", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadTd retrieves a block's total difficulty corresponding to the hash.
|
||||
func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
|
||||
data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), headerTDSuffix...))
|
||||
data, _ := db.Get(headerTDKey(number, hash))
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -263,15 +259,14 @@ func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) {
|
|||
if err != nil {
|
||||
log.Crit("Failed to RLP encode block total difficulty", "err", err)
|
||||
}
|
||||
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), headerTDSuffix...)
|
||||
if err := db.Put(key, data); err != nil {
|
||||
if err := db.Put(headerTDKey(number, hash), data); err != nil {
|
||||
log.Crit("Failed to store block total difficulty", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteTd removes all block total difficulty data associated with a hash.
|
||||
func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||
if err := db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), headerTDSuffix...)); err != nil {
|
||||
if err := db.Delete(headerTDKey(number, hash)); err != nil {
|
||||
log.Crit("Failed to delete block total difficulty", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -279,7 +274,7 @@ func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
|
|||
// ReadReceipts retrieves all the transaction receipts belonging to a block.
|
||||
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
|
||||
// Retrieve the flattened receipt slice
|
||||
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...))
|
||||
data, _ := db.Get(blockReceiptsKey(number, hash))
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -308,15 +303,14 @@ func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts
|
|||
log.Crit("Failed to encode block receipts", "err", err)
|
||||
}
|
||||
// Store the flattened receipt slice
|
||||
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
if err := db.Put(key, bytes); err != nil {
|
||||
if err := db.Put(blockReceiptsKey(number, hash), bytes); err != nil {
|
||||
log.Crit("Failed to store block receipts", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteReceipts removes all receipt data associated with a block hash.
|
||||
func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||
if err := db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil {
|
||||
if err := db.Delete(blockReceiptsKey(number, hash)); err != nil {
|
||||
log.Crit("Failed to delete block receipts", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
package rawdb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
|
@ -28,7 +26,7 @@ import (
|
|||
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
|
||||
// hash to allow retrieving the transaction or receipt by hash.
|
||||
func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
|
||||
data, _ := db.Get(append(txLookupPrefix, hash.Bytes()...))
|
||||
data, _ := db.Get(txLookupKey(hash))
|
||||
if len(data) == 0 {
|
||||
return common.Hash{}, 0, 0
|
||||
}
|
||||
|
|
@ -53,7 +51,7 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
|
|||
if err != nil {
|
||||
log.Crit("Failed to encode transaction lookup entry", "err", err)
|
||||
}
|
||||
if err := db.Put(append(txLookupPrefix, tx.Hash().Bytes()...), data); err != nil {
|
||||
if err := db.Put(txLookupKey(tx.Hash()), data); err != nil {
|
||||
log.Crit("Failed to store transaction lookup entry", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -61,7 +59,7 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
|
|||
|
||||
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
||||
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
|
||||
db.Delete(append(txLookupPrefix, hash.Bytes()...))
|
||||
db.Delete(txLookupKey(hash))
|
||||
}
|
||||
|
||||
// ReadTransaction retrieves a specific transaction from the database, along with
|
||||
|
|
@ -97,23 +95,13 @@ func ReadReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Ha
|
|||
// ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
|
||||
// section and bit index from the.
|
||||
func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
|
||||
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
|
||||
|
||||
binary.BigEndian.PutUint16(key[1:], uint16(bit))
|
||||
binary.BigEndian.PutUint64(key[3:], section)
|
||||
|
||||
return db.Get(key)
|
||||
return db.Get(bloomBitsKey(bit, section, head))
|
||||
}
|
||||
|
||||
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
|
||||
// section and bit index.
|
||||
func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) {
|
||||
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
|
||||
|
||||
binary.BigEndian.PutUint16(key[1:], uint16(bit))
|
||||
binary.BigEndian.PutUint64(key[3:], section)
|
||||
|
||||
if err := db.Put(key, bits); err != nil {
|
||||
if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
|
||||
log.Crit("Failed to store bloom bits", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func WriteDatabaseVersion(db DatabaseWriter, version int) {
|
|||
|
||||
// ReadChainConfig retrieves the consensus settings based on the given genesis hash.
|
||||
func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
|
||||
data, _ := db.Get(append(configPrefix, hash[:]...))
|
||||
data, _ := db.Get(configKey(hash))
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -66,14 +66,14 @@ func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConf
|
|||
if err != nil {
|
||||
log.Crit("Failed to JSON encode chain config", "err", err)
|
||||
}
|
||||
if err := db.Put(append(configPrefix, hash[:]...), data); err != nil {
|
||||
if err := db.Put(configKey(hash), data); err != nil {
|
||||
log.Crit("Failed to store chain config", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadPreimage retrieves a single preimage of the provided hash.
|
||||
func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
|
||||
data, _ := db.Get(append(preimagePrefix, hash.Bytes()...))
|
||||
data, _ := db.Get(preimageKey(hash))
|
||||
return data
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
|
|||
// current block number, and is used for debug messages only.
|
||||
func WritePreimages(db DatabaseWriter, number uint64, preimages map[common.Hash][]byte) {
|
||||
for hash, preimage := range preimages {
|
||||
if err := db.Put(append(preimagePrefix, hash.Bytes()...), preimage); err != nil {
|
||||
if err := db.Put(preimageKey(hash), preimage); err != nil {
|
||||
log.Crit("Failed to store trie preimage", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,3 +77,58 @@ func encodeBlockNumber(number uint64) []byte {
|
|||
binary.BigEndian.PutUint64(enc, number)
|
||||
return enc
|
||||
}
|
||||
|
||||
// headerKey = headerPrefix + num (uint64 big endian) + hash
|
||||
func headerKey(number uint64, hash common.Hash) []byte {
|
||||
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
}
|
||||
|
||||
// headerTDKey = headerPrefix + num (uint64 big endian) + hash + headerTDSuffix
|
||||
func headerTDKey(number uint64, hash common.Hash) []byte {
|
||||
return append(headerKey(number, hash), headerTDSuffix...)
|
||||
}
|
||||
|
||||
// headerHashKey = headerPrefix + num (uint64 big endian) + headerHashSuffix
|
||||
func headerHashKey(number uint64) []byte {
|
||||
return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
|
||||
}
|
||||
|
||||
// headerNumberKey = headerNumberPrefix + hash
|
||||
func headerNumberKey(hash common.Hash) []byte {
|
||||
return append(headerNumberPrefix, hash.Bytes()...)
|
||||
}
|
||||
|
||||
// blockBodyKey = blockBodyPrefix + num (uint64 big endian) + hash
|
||||
func blockBodyKey(number uint64, hash common.Hash) []byte {
|
||||
return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
}
|
||||
|
||||
// blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash
|
||||
func blockReceiptsKey(number uint64, hash common.Hash) []byte {
|
||||
return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
}
|
||||
|
||||
// txLookupKey = txLookupPrefix + hash
|
||||
func txLookupKey(hash common.Hash) []byte {
|
||||
return append(txLookupPrefix, hash.Bytes()...)
|
||||
}
|
||||
|
||||
// bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash
|
||||
func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte {
|
||||
key := append(append(bloomBitsPrefix, make([]byte, 10)...), hash.Bytes()...)
|
||||
|
||||
binary.BigEndian.PutUint16(key[1:], uint16(bit))
|
||||
binary.BigEndian.PutUint64(key[3:], section)
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
// preimageKey = preimagePrefix + hash
|
||||
func preimageKey(hash common.Hash) []byte {
|
||||
return append(preimagePrefix, hash.Bytes()...)
|
||||
}
|
||||
|
||||
// configKey = configPrefix + hash
|
||||
func configKey(hash common.Hash) []byte {
|
||||
return append(configPrefix, hash.Bytes()...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) {
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
|
|
|||
|
|
@ -815,11 +815,9 @@ func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error {
|
|||
|
||||
for i, tx := range txs {
|
||||
var replace bool
|
||||
if replace, errs[i] = pool.add(tx, local); errs[i] == nil {
|
||||
if !replace {
|
||||
from, _ := types.Sender(pool.signer, tx) // already validated
|
||||
dirty[from] = struct{}{}
|
||||
}
|
||||
if replace, errs[i] = pool.add(tx, local); errs[i] == nil && !replace {
|
||||
from, _ := types.Sender(pool.signer, tx) // already validated
|
||||
dirty[from] = struct{}{}
|
||||
}
|
||||
}
|
||||
// Only reprocess the internal state if something was actually added
|
||||
|
|
@ -1107,7 +1105,7 @@ func (pool *TxPool) demoteUnexecutables() {
|
|||
log.Trace("Demoting pending transaction", "hash", hash)
|
||||
pool.enqueueTx(hash, tx)
|
||||
}
|
||||
// If there's a gap in front, warn (should never happen) and postpone all transactions
|
||||
// If there's a gap in front, alert (should never happen) and postpone all transactions
|
||||
if list.Len() > 0 && list.txs.Get(nonce) == nil {
|
||||
for _, tx := range list.Cap(0) {
|
||||
hash := tx.Hash()
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St
|
|||
func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// pop value of the stack
|
||||
mStart, val := stack.pop(), stack.pop()
|
||||
memory.Set(mStart.Uint64(), 32, math.PaddedBigBytes(val, 32))
|
||||
memory.Set32(mStart.Uint64(), val)
|
||||
|
||||
evm.interpreter.intPool.put(mStart, val)
|
||||
return nil, nil
|
||||
|
|
@ -570,9 +570,9 @@ func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
|
|||
}
|
||||
|
||||
func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
loc := common.BigToHash(stack.pop())
|
||||
val := evm.StateDB.GetState(contract.Address(), loc).Big()
|
||||
stack.push(val)
|
||||
loc := stack.peek()
|
||||
val := evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
||||
loc.SetBytes(val.Bytes())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -425,3 +425,42 @@ func BenchmarkOpIsZero(b *testing.B) {
|
|||
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||
opBenchmark(b, opIszero, x)
|
||||
}
|
||||
|
||||
func TestOpMstore(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
)
|
||||
mem.Resize(64)
|
||||
pc := uint64(0)
|
||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
||||
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
|
||||
opMstore(&pc, env, nil, mem, stack)
|
||||
if got := common.Bytes2Hex(mem.Get(0, 32)); got != v {
|
||||
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
||||
}
|
||||
stack.pushN(big.NewInt(0x1), big.NewInt(0))
|
||||
opMstore(&pc, env, nil, mem, stack)
|
||||
if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||
t.Fatalf("Mstore failed to overwrite previous value")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOpMstore(bench *testing.B) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
)
|
||||
mem.Resize(64)
|
||||
pc := uint64(0)
|
||||
memStart := big.NewInt(0)
|
||||
value := big.NewInt(0x1337)
|
||||
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
stack.pushN(value, memStart)
|
||||
opMstore(&pc, env, nil, mem, stack)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,12 @@
|
|||
|
||||
package vm
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
// Memory implements a simple memory model for the ethereum virtual machine.
|
||||
type Memory struct {
|
||||
|
|
@ -30,19 +35,32 @@ func NewMemory() *Memory {
|
|||
|
||||
// Set sets offset + size to value
|
||||
func (m *Memory) Set(offset, size uint64, value []byte) {
|
||||
// length of store may never be less than offset + size.
|
||||
// The store should be resized PRIOR to setting the memory
|
||||
if size > uint64(len(m.store)) {
|
||||
panic("INVALID memory: store empty")
|
||||
}
|
||||
|
||||
// It's possible the offset is greater than 0 and size equals 0. This is because
|
||||
// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
|
||||
if size > 0 {
|
||||
// length of store may never be less than offset + size.
|
||||
// The store should be resized PRIOR to setting the memory
|
||||
if offset+size > uint64(len(m.store)) {
|
||||
panic("invalid memory: store empty")
|
||||
}
|
||||
copy(m.store[offset:offset+size], value)
|
||||
}
|
||||
}
|
||||
|
||||
// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to
|
||||
// 32 bytes.
|
||||
func (m *Memory) Set32(offset uint64, val *big.Int) {
|
||||
// length of store may never be less than offset + size.
|
||||
// The store should be resized PRIOR to setting the memory
|
||||
if offset+32 > uint64(len(m.store)) {
|
||||
panic("invalid memory: store empty")
|
||||
}
|
||||
// Zero the memory area
|
||||
copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
// Fill in relevant bits
|
||||
math.ReadBits(val, m.store[offset:offset+32])
|
||||
}
|
||||
|
||||
// Resize resizes the memory to size
|
||||
func (m *Memory) Resize(size uint64) {
|
||||
if uint64(m.Len()) < size {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ var (
|
|||
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
|
||||
)
|
||||
|
||||
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
|
||||
|
||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||
func Keccak256(data ...[]byte) []byte {
|
||||
d := sha3.NewKeccak256()
|
||||
|
|
@ -122,12 +124,13 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {
|
|||
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
||||
}
|
||||
|
||||
func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
|
||||
if len(pub) == 0 {
|
||||
return nil
|
||||
}
|
||||
// UnmarshalPubkey converts bytes to a secp256k1 public key.
|
||||
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
||||
x, y := elliptic.Unmarshal(S256(), pub)
|
||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}
|
||||
if x == nil {
|
||||
return nil, errInvalidPubkey
|
||||
}
|
||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
|
||||
}
|
||||
|
||||
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ import (
|
|||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
|
||||
|
|
@ -56,6 +58,33 @@ func BenchmarkSha3(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalPubkey(t *testing.T) {
|
||||
key, err := UnmarshalPubkey(nil)
|
||||
if err != errInvalidPubkey || key != nil {
|
||||
t.Fatalf("expected error, got %v, %v", err, key)
|
||||
}
|
||||
key, err = UnmarshalPubkey([]byte{1, 2, 3})
|
||||
if err != errInvalidPubkey || key != nil {
|
||||
t.Fatalf("expected error, got %v, %v", err, key)
|
||||
}
|
||||
|
||||
var (
|
||||
enc, _ = hex.DecodeString("04760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d")
|
||||
dec = &ecdsa.PublicKey{
|
||||
Curve: S256(),
|
||||
X: hexutil.MustDecodeBig("0x760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1"),
|
||||
Y: hexutil.MustDecodeBig("0xb01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d"),
|
||||
}
|
||||
)
|
||||
key, err = UnmarshalPubkey(enc)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(key, dec) {
|
||||
t.Fatal("wrong result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
key, _ := HexToECDSA(testPrivHex)
|
||||
addr := common.HexToAddress(testAddrHex)
|
||||
|
|
@ -69,7 +98,7 @@ func TestSign(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("ECRecover error: %s", err)
|
||||
}
|
||||
pubKey := ToECDSAPub(recoveredPub)
|
||||
pubKey, _ := UnmarshalPubkey(recoveredPub)
|
||||
recoveredAddr := PubkeyToAddress(*pubKey)
|
||||
if addr != recoveredAddr {
|
||||
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
|
||||
|
|
|
|||
33
eth/api.go
33
eth/api.go
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/miner"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -351,10 +352,34 @@ func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hex
|
|||
return nil, errors.New("unknown preimage")
|
||||
}
|
||||
|
||||
// GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network
|
||||
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
|
||||
type BadBlockArgs struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
Block map[string]interface{} `json:"block"`
|
||||
RLP string `json:"rlp"`
|
||||
}
|
||||
|
||||
// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
||||
// and returns them as a JSON list of block-hashes
|
||||
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) {
|
||||
return api.eth.BlockChain().BadBlocks()
|
||||
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
|
||||
blocks := api.eth.BlockChain().BadBlocks()
|
||||
results := make([]*BadBlockArgs, len(blocks))
|
||||
|
||||
var err error
|
||||
for i, block := range blocks {
|
||||
results[i] = &BadBlockArgs{
|
||||
Hash: block.Hash(),
|
||||
}
|
||||
if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
|
||||
results[i].RLP = err.Error() // Hacky, but hey, it works
|
||||
} else {
|
||||
results[i].RLP = fmt.Sprintf("0x%x", rlpBytes)
|
||||
}
|
||||
if results[i].Block, err = ethapi.RPCMarshalBlock(block, true, true); err != nil {
|
||||
results[i].Block = map[string]interface{}{"error": err.Error()}
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// StorageRangeResult is the result of a debug_storageRangeAt API call.
|
||||
|
|
@ -406,7 +431,7 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeRes
|
|||
return result, nil
|
||||
}
|
||||
|
||||
// GetModifiedAccountsByumber returns all accounts that have changed between the
|
||||
// GetModifiedAccountsByNumber returns all accounts that have changed between the
|
||||
// two blocks specified. A change is defined as a difference in nonce, balance,
|
||||
// code hash, or storage hash.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ type EthAPIBackend struct {
|
|||
gpo *gasprice.Oracle
|
||||
}
|
||||
|
||||
// ChainConfig returns the active chain configuration.
|
||||
func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
|
||||
return b.eth.chainConfig
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ type Ethereum struct {
|
|||
gasPrice *big.Int
|
||||
etherbase common.Address
|
||||
|
||||
networkId uint64
|
||||
networkID uint64
|
||||
netRPCService *ethapi.PublicNetAPI
|
||||
|
||||
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
|
||||
|
|
@ -126,7 +126,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
accountManager: ctx.AccountManager,
|
||||
engine: CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb),
|
||||
shutdownChan: make(chan bool),
|
||||
networkId: config.NetworkId,
|
||||
networkID: config.NetworkId,
|
||||
gasPrice: config.GasPrice,
|
||||
etherbase: config.Etherbase,
|
||||
bloomRequests: make(chan chan *bloombits.Retrieval),
|
||||
|
|
@ -369,7 +369,7 @@ func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
|||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
||||
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
||||
func (s *Ethereum) NetVersion() uint64 { return s.networkId }
|
||||
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
||||
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
||||
|
||||
// Protocols implements node.Service, returning all the currently configured
|
||||
|
|
|
|||
|
|
@ -900,7 +900,7 @@ func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) (
|
|||
var (
|
||||
deliver = func(packet dataPack) (int, error) {
|
||||
pack := packet.(*headerPack)
|
||||
return d.queue.DeliverHeaders(pack.peerId, pack.headers, d.headerProcCh)
|
||||
return d.queue.DeliverHeaders(pack.peerID, pack.headers, d.headerProcCh)
|
||||
}
|
||||
expire = func() map[string]int { return d.queue.ExpireHeaders(d.requestTTL()) }
|
||||
throttle = func() bool { return false }
|
||||
|
|
@ -930,7 +930,7 @@ func (d *Downloader) fetchBodies(from uint64) error {
|
|||
var (
|
||||
deliver = func(packet dataPack) (int, error) {
|
||||
pack := packet.(*bodyPack)
|
||||
return d.queue.DeliverBodies(pack.peerId, pack.transactions, pack.uncles)
|
||||
return d.queue.DeliverBodies(pack.peerID, pack.transactions, pack.uncles)
|
||||
}
|
||||
expire = func() map[string]int { return d.queue.ExpireBodies(d.requestTTL()) }
|
||||
fetch = func(p *peerConnection, req *fetchRequest) error { return p.FetchBodies(req) }
|
||||
|
|
@ -954,7 +954,7 @@ func (d *Downloader) fetchReceipts(from uint64) error {
|
|||
var (
|
||||
deliver = func(packet dataPack) (int, error) {
|
||||
pack := packet.(*receiptPack)
|
||||
return d.queue.DeliverReceipts(pack.peerId, pack.receipts)
|
||||
return d.queue.DeliverReceipts(pack.peerID, pack.receipts)
|
||||
}
|
||||
expire = func() map[string]int { return d.queue.ExpireReceipts(d.requestTTL()) }
|
||||
fetch = func(p *peerConnection, req *fetchRequest) error { return p.FetchReceipts(req) }
|
||||
|
|
|
|||
|
|
@ -596,21 +596,21 @@ func (q *queue) cancel(request *fetchRequest, taskQueue *prque.Prque, pendPool m
|
|||
// Revoke cancels all pending requests belonging to a given peer. This method is
|
||||
// meant to be called during a peer drop to quickly reassign owned data fetches
|
||||
// to remaining nodes.
|
||||
func (q *queue) Revoke(peerId string) {
|
||||
func (q *queue) Revoke(peerID string) {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
|
||||
if request, ok := q.blockPendPool[peerId]; ok {
|
||||
if request, ok := q.blockPendPool[peerID]; ok {
|
||||
for _, header := range request.Headers {
|
||||
q.blockTaskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
}
|
||||
delete(q.blockPendPool, peerId)
|
||||
delete(q.blockPendPool, peerID)
|
||||
}
|
||||
if request, ok := q.receiptPendPool[peerId]; ok {
|
||||
if request, ok := q.receiptPendPool[peerID]; ok {
|
||||
for _, header := range request.Headers {
|
||||
q.receiptTaskQueue.Push(header, -float32(header.Number.Uint64()))
|
||||
}
|
||||
delete(q.receiptPendPool, peerId)
|
||||
delete(q.receiptPendPool, peerID)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,22 +34,22 @@ type dataPack interface {
|
|||
|
||||
// headerPack is a batch of block headers returned by a peer.
|
||||
type headerPack struct {
|
||||
peerId string
|
||||
peerID string
|
||||
headers []*types.Header
|
||||
}
|
||||
|
||||
func (p *headerPack) PeerId() string { return p.peerId }
|
||||
func (p *headerPack) PeerId() string { return p.peerID }
|
||||
func (p *headerPack) Items() int { return len(p.headers) }
|
||||
func (p *headerPack) Stats() string { return fmt.Sprintf("%d", len(p.headers)) }
|
||||
|
||||
// bodyPack is a batch of block bodies returned by a peer.
|
||||
type bodyPack struct {
|
||||
peerId string
|
||||
peerID string
|
||||
transactions [][]*types.Transaction
|
||||
uncles [][]*types.Header
|
||||
}
|
||||
|
||||
func (p *bodyPack) PeerId() string { return p.peerId }
|
||||
func (p *bodyPack) PeerId() string { return p.peerID }
|
||||
func (p *bodyPack) Items() int {
|
||||
if len(p.transactions) <= len(p.uncles) {
|
||||
return len(p.transactions)
|
||||
|
|
@ -60,20 +60,20 @@ func (p *bodyPack) Stats() string { return fmt.Sprintf("%d:%d", len(p.transactio
|
|||
|
||||
// receiptPack is a batch of receipts returned by a peer.
|
||||
type receiptPack struct {
|
||||
peerId string
|
||||
peerID string
|
||||
receipts [][]*types.Receipt
|
||||
}
|
||||
|
||||
func (p *receiptPack) PeerId() string { return p.peerId }
|
||||
func (p *receiptPack) PeerId() string { return p.peerID }
|
||||
func (p *receiptPack) Items() int { return len(p.receipts) }
|
||||
func (p *receiptPack) Stats() string { return fmt.Sprintf("%d", len(p.receipts)) }
|
||||
|
||||
// statePack is a batch of states returned by a peer.
|
||||
type statePack struct {
|
||||
peerId string
|
||||
peerID string
|
||||
states [][]byte
|
||||
}
|
||||
|
||||
func (p *statePack) PeerId() string { return p.peerId }
|
||||
func (p *statePack) PeerId() string { return p.peerID }
|
||||
func (p *statePack) Items() int { return len(p.states) }
|
||||
func (p *statePack) Stats() string { return fmt.Sprintf("%d", len(p.states)) }
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ type headerFilterTask struct {
|
|||
time time.Time // Arrival time of the headers
|
||||
}
|
||||
|
||||
// headerFilterTask represents a batch of block bodies (transactions and uncles)
|
||||
// bodyFilterTask represents a batch of block bodies (transactions and uncles)
|
||||
// needing fetcher filtering.
|
||||
type bodyFilterTask struct {
|
||||
peer string // The source peer of block bodies
|
||||
|
|
|
|||
|
|
@ -258,9 +258,9 @@ Logs:
|
|||
if len(topics) > len(log.Topics) {
|
||||
continue Logs
|
||||
}
|
||||
for i, topics := range topics {
|
||||
match := len(topics) == 0 // empty rule set == wildcard
|
||||
for _, topic := range topics {
|
||||
for i, sub := range topics {
|
||||
match := len(sub) == 0 // empty rule set == wildcard
|
||||
for _, topic := range sub {
|
||||
if log.Topics[i] == topic {
|
||||
match = true
|
||||
break
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func errResp(code errCode, format string, v ...interface{}) error {
|
|||
}
|
||||
|
||||
type ProtocolManager struct {
|
||||
networkId uint64
|
||||
networkID uint64
|
||||
|
||||
fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks)
|
||||
acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing)
|
||||
|
|
@ -98,10 +98,10 @@ type ProtocolManager struct {
|
|||
|
||||
// NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||
// with the Ethereum network.
|
||||
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkId uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
|
||||
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
|
||||
// Create the protocol manager with the base fields
|
||||
manager := &ProtocolManager{
|
||||
networkId: networkId,
|
||||
networkID: networkID,
|
||||
eventMux: mux,
|
||||
txpool: txpool,
|
||||
blockchain: blockchain,
|
||||
|
|
@ -263,7 +263,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
|
|||
number = head.Number.Uint64()
|
||||
td = pm.blockchain.GetTd(hash, number)
|
||||
)
|
||||
if err := p.Handshake(pm.networkId, td, hash, genesis.Hash()); err != nil {
|
||||
if err := p.Handshake(pm.networkID, td, hash, genesis.Hash()); err != nil {
|
||||
p.Log().Debug("Ethereum handshake failed", "err", err)
|
||||
return err
|
||||
}
|
||||
|
|
@ -340,6 +340,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
return errResp(ErrDecode, "%v: %v", msg, err)
|
||||
}
|
||||
hashMode := query.Origin.Hash != (common.Hash{})
|
||||
first := true
|
||||
maxNonCanonical := uint64(100)
|
||||
|
||||
// Gather headers until the fetch or network limits is reached
|
||||
var (
|
||||
|
|
@ -351,31 +353,36 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
// Retrieve the next header satisfying the query
|
||||
var origin *types.Header
|
||||
if hashMode {
|
||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
||||
if first {
|
||||
first = false
|
||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
||||
if origin != nil {
|
||||
query.Origin.Number = origin.Number.Uint64()
|
||||
}
|
||||
} else {
|
||||
origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
|
||||
}
|
||||
} else {
|
||||
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
||||
}
|
||||
if origin == nil {
|
||||
break
|
||||
}
|
||||
number := origin.Number.Uint64()
|
||||
headers = append(headers, origin)
|
||||
bytes += estHeaderRlpSize
|
||||
|
||||
// Advance to the next header of the query
|
||||
switch {
|
||||
case query.Origin.Hash != (common.Hash{}) && query.Reverse:
|
||||
case hashMode && query.Reverse:
|
||||
// Hash based traversal towards the genesis block
|
||||
for i := 0; i < int(query.Skip)+1; i++ {
|
||||
if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil {
|
||||
query.Origin.Hash = header.ParentHash
|
||||
number--
|
||||
} else {
|
||||
unknown = true
|
||||
break
|
||||
}
|
||||
ancestor := query.Skip + 1
|
||||
if ancestor == 0 {
|
||||
unknown = true
|
||||
} else {
|
||||
query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
|
||||
unknown = (query.Origin.Hash == common.Hash{})
|
||||
}
|
||||
case query.Origin.Hash != (common.Hash{}) && !query.Reverse:
|
||||
case hashMode && !query.Reverse:
|
||||
// Hash based traversal towards the leaf block
|
||||
var (
|
||||
current = origin.Number.Uint64()
|
||||
|
|
@ -387,8 +394,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
unknown = true
|
||||
} else {
|
||||
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
|
||||
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash {
|
||||
query.Origin.Hash = header.Hash()
|
||||
nextHash := header.Hash()
|
||||
expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
|
||||
if expOldHash == query.Origin.Hash {
|
||||
query.Origin.Hash, query.Origin.Number = nextHash, next
|
||||
} else {
|
||||
unknown = true
|
||||
}
|
||||
|
|
@ -770,7 +779,7 @@ type NodeInfo struct {
|
|||
func (pm *ProtocolManager) NodeInfo() *NodeInfo {
|
||||
currentBlock := pm.blockchain.CurrentBlock()
|
||||
return &NodeInfo{
|
||||
Network: pm.networkId,
|
||||
Network: pm.networkID,
|
||||
Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
|
||||
Genesis: pm.blockchain.Genesis().Hash(),
|
||||
Config: pm.blockchain.Config(),
|
||||
|
|
|
|||
|
|
@ -141,7 +141,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
|
|||
// Fill the sender cache of transactions in the block.
|
||||
txs := make([]*types.Transaction, len(body.Transactions))
|
||||
for i, tx := range body.Transactions {
|
||||
setSenderFromServer(tx.tx, tx.From, body.Hash)
|
||||
if tx.From != nil {
|
||||
setSenderFromServer(tx.tx, *tx.From, body.Hash)
|
||||
}
|
||||
txs[i] = tx.tx
|
||||
}
|
||||
return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil
|
||||
|
|
@ -174,9 +176,9 @@ type rpcTransaction struct {
|
|||
}
|
||||
|
||||
type txExtraInfo struct {
|
||||
BlockNumber *string
|
||||
BlockHash common.Hash
|
||||
From common.Address
|
||||
BlockNumber *string `json:"blockNumber,omitempty"`
|
||||
BlockHash *common.Hash `json:"blockHash,omitempty"`
|
||||
From *common.Address `json:"from,omitempty"`
|
||||
}
|
||||
|
||||
func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
|
||||
|
|
@ -197,7 +199,9 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *
|
|||
} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
|
||||
return nil, false, fmt.Errorf("server returned transaction without signature")
|
||||
}
|
||||
setSenderFromServer(json.tx, json.From, json.BlockHash)
|
||||
if json.From != nil && json.BlockHash != nil {
|
||||
setSenderFromServer(json.tx, *json.From, *json.BlockHash)
|
||||
}
|
||||
return json.tx, json.BlockNumber == nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +248,9 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
|
|||
return nil, fmt.Errorf("server returned transaction without signature")
|
||||
}
|
||||
}
|
||||
setSenderFromServer(json.tx, json.From, json.BlockHash)
|
||||
if json.From != nil && json.BlockHash != nil {
|
||||
setSenderFromServer(json.tx, *json.From, *json.BlockHash)
|
||||
}
|
||||
return json.tx, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ func (db *LDBDatabase) Close() {
|
|||
if err := <-errc; err != nil {
|
||||
db.log.Error("Metrics collection failed", "err", err)
|
||||
}
|
||||
db.quitChan = nil
|
||||
}
|
||||
err := db.db.Close()
|
||||
if err == nil {
|
||||
|
|
@ -189,7 +190,7 @@ func (db *LDBDatabase) Meter(prefix string) {
|
|||
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
||||
//
|
||||
// This is how the write delay look like (currently):
|
||||
// DelayN:5 Delay:406.604657ms
|
||||
// DelayN:5 Delay:406.604657ms Paused: false
|
||||
//
|
||||
// This is how the iostats look like (currently):
|
||||
// Read(MB):3895.04860 Write(MB):3654.64712
|
||||
|
|
@ -210,13 +211,19 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
lastWritePaused time.Time
|
||||
)
|
||||
|
||||
var (
|
||||
errc chan error
|
||||
merr error
|
||||
)
|
||||
|
||||
// Iterate ad infinitum and collect the stats
|
||||
for i := 1; ; i++ {
|
||||
for i := 1; errc == nil && merr == nil; i++ {
|
||||
// Retrieve the database stats
|
||||
stats, err := db.db.GetProperty("leveldb.stats")
|
||||
if err != nil {
|
||||
db.log.Error("Failed to read database stats", "err", err)
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
// Find the compaction table, skip the header
|
||||
lines := strings.Split(stats, "\n")
|
||||
|
|
@ -225,7 +232,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
}
|
||||
if len(lines) <= 3 {
|
||||
db.log.Error("Compaction table not found")
|
||||
return
|
||||
merr = errors.New("compaction table not found")
|
||||
continue
|
||||
}
|
||||
lines = lines[3:]
|
||||
|
||||
|
|
@ -242,7 +250,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
|
||||
if err != nil {
|
||||
db.log.Error("Compaction entry parsing failed", "err", err)
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
compactions[i%2][idx] += value
|
||||
}
|
||||
|
|
@ -262,7 +271,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
writedelay, err := db.db.GetProperty("leveldb.writedelay")
|
||||
if err != nil {
|
||||
db.log.Error("Failed to read database write delay statistic", "err", err)
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
var (
|
||||
delayN int64
|
||||
|
|
@ -272,12 +282,14 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
)
|
||||
if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil {
|
||||
db.log.Error("Write delay statistic not found")
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
duration, err = time.ParseDuration(delayDuration)
|
||||
if err != nil {
|
||||
db.log.Error("Failed to parse delay duration", "err", err)
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
if db.writeDelayNMeter != nil {
|
||||
db.writeDelayNMeter.Mark(delayN - delaystats[0])
|
||||
|
|
@ -317,53 +329,47 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
ioStats, err := db.db.GetProperty("leveldb.iostats")
|
||||
if err != nil {
|
||||
db.log.Error("Failed to read database iostats", "err", err)
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
var nRead, nWrite float64
|
||||
parts := strings.Split(ioStats, " ")
|
||||
if len(parts) < 2 {
|
||||
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
|
||||
return
|
||||
merr = fmt.Errorf("bad syntax of ioStats %s", ioStats)
|
||||
continue
|
||||
}
|
||||
r := strings.Split(parts[0], ":")
|
||||
if len(r) < 2 {
|
||||
if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil {
|
||||
db.log.Error("Bad syntax of read entry", "entry", parts[0])
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
read, err := strconv.ParseFloat(r[1], 64)
|
||||
if err != nil {
|
||||
db.log.Error("Read entry parsing failed", "err", err)
|
||||
return
|
||||
}
|
||||
w := strings.Split(parts[1], ":")
|
||||
if len(w) < 2 {
|
||||
if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil {
|
||||
db.log.Error("Bad syntax of write entry", "entry", parts[1])
|
||||
return
|
||||
}
|
||||
write, err := strconv.ParseFloat(w[1], 64)
|
||||
if err != nil {
|
||||
db.log.Error("Write entry parsing failed", "err", err)
|
||||
return
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
if db.diskReadMeter != nil {
|
||||
db.diskReadMeter.Mark(int64((read - iostats[0]) * 1024 * 1024))
|
||||
db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024))
|
||||
}
|
||||
if db.diskWriteMeter != nil {
|
||||
db.diskWriteMeter.Mark(int64((write - iostats[1]) * 1024 * 1024))
|
||||
db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024))
|
||||
}
|
||||
iostats[0] = read
|
||||
iostats[1] = write
|
||||
iostats[0], iostats[1] = nRead, nWrite
|
||||
|
||||
// Sleep a bit, then repeat the stats collection
|
||||
select {
|
||||
case errc := <-db.quitChan:
|
||||
case errc = <-db.quitChan:
|
||||
// Quit requesting, stop hammering the database
|
||||
errc <- nil
|
||||
return
|
||||
|
||||
case <-time.After(refresh):
|
||||
// Timeout, gather a new set of stats
|
||||
}
|
||||
}
|
||||
|
||||
if errc == nil {
|
||||
errc = <-db.quitChan
|
||||
}
|
||||
errc <- merr
|
||||
}
|
||||
|
||||
func (db *LDBDatabase) NewBatch() Batch {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
package debug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
|
@ -190,9 +191,9 @@ func (*HandlerT) WriteMemProfile(file string) error {
|
|||
|
||||
// Stacks returns a printed representation of the stacks of all goroutines.
|
||||
func (*HandlerT) Stacks() string {
|
||||
buf := make([]byte, 1024*1024)
|
||||
buf = buf[:runtime.Stack(buf, true)]
|
||||
return string(buf)
|
||||
buf := new(bytes.Buffer)
|
||||
pprof.Lookup("goroutine").WriteTo(buf, 2)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// FreeOSMemory returns unused memory to the OS.
|
||||
|
|
|
|||
|
|
@ -62,8 +62,9 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
|
|||
}
|
||||
|
||||
// GasPrice returns a suggestion for a gas price.
|
||||
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return s.b.SuggestPrice(ctx)
|
||||
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
|
||||
price, err := s.b.SuggestPrice(ctx)
|
||||
return (*hexutil.Big)(price), err
|
||||
}
|
||||
|
||||
// ProtocolVersion returns the current Ethereum protocol version this node supports
|
||||
|
|
@ -460,13 +461,11 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt
|
|||
}
|
||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||
|
||||
rpk, err := crypto.Ecrecover(signHash(data), sig)
|
||||
rpk, err := crypto.SigToPub(signHash(data), sig)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
pubKey := crypto.ToECDSAPub(rpk)
|
||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
||||
return recoveredAddr, nil
|
||||
return crypto.PubkeyToAddress(*rpk), nil
|
||||
}
|
||||
|
||||
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
|
||||
|
|
@ -487,21 +486,20 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
|
|||
}
|
||||
|
||||
// BlockNumber returns the block number of the chain head.
|
||||
func (s *PublicBlockChainAPI) BlockNumber() *big.Int {
|
||||
func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
|
||||
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
|
||||
return header.Number
|
||||
return hexutil.Uint64(header.Number.Uint64())
|
||||
}
|
||||
|
||||
// GetBalance returns the amount of wei for the given address in the state of the
|
||||
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||
// block numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) {
|
||||
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Big, error) {
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
if state == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := state.GetBalance(address)
|
||||
return b, state.Error()
|
||||
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
||||
}
|
||||
|
||||
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
|
||||
|
|
@ -792,10 +790,10 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
|||
return formatted
|
||||
}
|
||||
|
||||
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
||||
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
||||
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
|
||||
// transaction hashes.
|
||||
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
||||
func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
||||
head := b.Header() // copies the header once
|
||||
fields := map[string]interface{}{
|
||||
"number": (*hexutil.Big)(head.Number),
|
||||
|
|
@ -808,7 +806,6 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
"stateRoot": head.Root,
|
||||
"miner": head.Coinbase,
|
||||
"difficulty": (*hexutil.Big)(head.Difficulty),
|
||||
"totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())),
|
||||
"extraData": hexutil.Bytes(head.Extra),
|
||||
"size": hexutil.Uint64(b.Size()),
|
||||
"gasLimit": hexutil.Uint64(head.GasLimit),
|
||||
|
|
@ -822,17 +819,15 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
formatTx := func(tx *types.Transaction) (interface{}, error) {
|
||||
return tx.Hash(), nil
|
||||
}
|
||||
|
||||
if fullTx {
|
||||
formatTx = func(tx *types.Transaction) (interface{}, error) {
|
||||
return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
|
||||
}
|
||||
}
|
||||
|
||||
txs := b.Transactions()
|
||||
transactions := make([]interface{}, len(txs))
|
||||
var err error
|
||||
for i, tx := range b.Transactions() {
|
||||
for i, tx := range txs {
|
||||
if transactions[i], err = formatTx(tx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -850,6 +845,17 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
return fields, nil
|
||||
}
|
||||
|
||||
// rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires
|
||||
// a `PublicBlockchainAPI`.
|
||||
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
||||
fields, err := RPCMarshalBlock(b, inclTx, fullTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash()))
|
||||
return fields, err
|
||||
}
|
||||
|
||||
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
||||
type RPCTransaction struct {
|
||||
BlockHash common.Hash `json:"blockHash"`
|
||||
|
|
@ -1293,14 +1299,19 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
|
|||
return &SignTransactionResult{data, tx}, nil
|
||||
}
|
||||
|
||||
// PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of
|
||||
// the accounts this node manages.
|
||||
// PendingTransactions returns the transactions that are in the transaction pool
|
||||
// and have a from address that is one of the accounts this node manages.
|
||||
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
|
||||
pending, err := s.b.GetPoolTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accounts := make(map[common.Address]struct{})
|
||||
for _, wallet := range s.b.AccountManager().Wallets() {
|
||||
for _, account := range wallet.Accounts() {
|
||||
accounts[account.Address] = struct{}{}
|
||||
}
|
||||
}
|
||||
transactions := make([]*RPCTransaction, 0, len(pending))
|
||||
for _, tx := range pending {
|
||||
var signer types.Signer = types.HomesteadSigner{}
|
||||
|
|
@ -1308,7 +1319,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
|
|||
signer = types.NewEIP155Signer(tx.ChainId())
|
||||
}
|
||||
from, _ := types.Sender(signer, tx)
|
||||
if _, err := s.b.AccountManager().Find(accounts.Account{Address: from}); err == nil {
|
||||
if _, exists := accounts[from]; exists {
|
||||
transactions = append(transactions, newRPCPendingTransaction(tx))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,8 +313,8 @@ web3._extend({
|
|||
params: 2
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'setMutexProfileRate',
|
||||
call: 'debug_setMutexProfileRate',
|
||||
name: 'setMutexProfileFraction',
|
||||
call: 'debug_setMutexProfileFraction',
|
||||
params: 1
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
|||
}
|
||||
|
||||
leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)
|
||||
if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, quitSync, &leth.wg); err != nil {
|
||||
if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, leth.serverPool, quitSync, &leth.wg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leth.ApiBackend = &LesApiBackend{leth, nil}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ type BlockChain interface {
|
|||
InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
|
||||
Rollback(chain []common.Hash)
|
||||
GetHeaderByNumber(number uint64) *types.Header
|
||||
GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash
|
||||
GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64)
|
||||
Genesis() *types.Block
|
||||
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ type ProtocolManager struct {
|
|||
|
||||
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||
// with the ethereum network.
|
||||
func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protocolVersions []uint, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, quitSync chan struct{}, wg *sync.WaitGroup) (*ProtocolManager, error) {
|
||||
func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protocolVersions []uint, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, serverPool *serverPool, quitSync chan struct{}, wg *sync.WaitGroup) (*ProtocolManager, error) {
|
||||
// Create the protocol manager with the base fields
|
||||
manager := &ProtocolManager{
|
||||
lightSync: lightSync,
|
||||
|
|
@ -141,6 +141,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protoco
|
|||
networkId: networkId,
|
||||
txpool: txpool,
|
||||
txrelay: txrelay,
|
||||
serverPool: serverPool,
|
||||
peers: peers,
|
||||
newPeerCh: make(chan *peer),
|
||||
quitSync: quitSync,
|
||||
|
|
@ -418,6 +419,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
}
|
||||
|
||||
hashMode := query.Origin.Hash != (common.Hash{})
|
||||
first := true
|
||||
maxNonCanonical := uint64(100)
|
||||
|
||||
// Gather headers until the fetch or network limits is reached
|
||||
var (
|
||||
|
|
@ -429,14 +432,21 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
// Retrieve the next header satisfying the query
|
||||
var origin *types.Header
|
||||
if hashMode {
|
||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
||||
if first {
|
||||
first = false
|
||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
||||
if origin != nil {
|
||||
query.Origin.Number = origin.Number.Uint64()
|
||||
}
|
||||
} else {
|
||||
origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
|
||||
}
|
||||
} else {
|
||||
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
||||
}
|
||||
if origin == nil {
|
||||
break
|
||||
}
|
||||
number := origin.Number.Uint64()
|
||||
headers = append(headers, origin)
|
||||
bytes += estHeaderRlpSize
|
||||
|
||||
|
|
@ -444,14 +454,12 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
switch {
|
||||
case hashMode && query.Reverse:
|
||||
// Hash based traversal towards the genesis block
|
||||
for i := 0; i < int(query.Skip)+1; i++ {
|
||||
if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil {
|
||||
query.Origin.Hash = header.ParentHash
|
||||
number--
|
||||
} else {
|
||||
unknown = true
|
||||
break
|
||||
}
|
||||
ancestor := query.Skip + 1
|
||||
if ancestor == 0 {
|
||||
unknown = true
|
||||
} else {
|
||||
query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
|
||||
unknown = (query.Origin.Hash == common.Hash{})
|
||||
}
|
||||
case hashMode && !query.Reverse:
|
||||
// Hash based traversal towards the leaf block
|
||||
|
|
@ -465,8 +473,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
unknown = true
|
||||
} else {
|
||||
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
|
||||
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash {
|
||||
query.Origin.Hash = header.Hash()
|
||||
nextHash := header.Hash()
|
||||
expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
|
||||
if expOldHash == query.Origin.Hash {
|
||||
query.Origin.Hash, query.Origin.Number = nextHash, next
|
||||
} else {
|
||||
unknown = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
|||
} else {
|
||||
protocolVersions = ServerProtocolVersions
|
||||
}
|
||||
pm, err := NewProtocolManager(gspec.Config, lightSync, protocolVersions, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, make(chan struct{}), new(sync.WaitGroup))
|
||||
pm, err := NewProtocolManager(gspec.Config, lightSync, protocolVersions, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,9 @@ type sentReq struct {
|
|||
lock sync.RWMutex // protect access to sentTo map
|
||||
sentTo map[distPeer]sentReqToPeer
|
||||
|
||||
reqQueued bool // a request has been queued but not sent
|
||||
reqSent bool // a request has been sent but not timed out
|
||||
reqSrtoCount int // number of requests that reached soft (but not hard) timeout
|
||||
lastReqQueued bool // last request has been queued but not sent
|
||||
lastReqSentTo distPeer // if not nil then last request has been sent to given peer but not timed out
|
||||
reqSrtoCount int // number of requests that reached soft (but not hard) timeout
|
||||
}
|
||||
|
||||
// sentReqToPeer notifies the request-from-peer goroutine (tryRequest) about a response
|
||||
|
|
@ -180,7 +180,7 @@ type reqStateFn func() reqStateFn
|
|||
// retrieveLoop is the retrieval state machine event loop
|
||||
func (r *sentReq) retrieveLoop() {
|
||||
go r.tryRequest()
|
||||
r.reqQueued = true
|
||||
r.lastReqQueued = true
|
||||
state := r.stateRequesting
|
||||
|
||||
for state != nil {
|
||||
|
|
@ -214,7 +214,7 @@ func (r *sentReq) stateRequesting() reqStateFn {
|
|||
case rpSoftTimeout:
|
||||
// last request timed out, try asking a new peer
|
||||
go r.tryRequest()
|
||||
r.reqQueued = true
|
||||
r.lastReqQueued = true
|
||||
return r.stateRequesting
|
||||
case rpDeliveredValid:
|
||||
r.stop(nil)
|
||||
|
|
@ -233,7 +233,7 @@ func (r *sentReq) stateNoMorePeers() reqStateFn {
|
|||
select {
|
||||
case <-time.After(retryQueue):
|
||||
go r.tryRequest()
|
||||
r.reqQueued = true
|
||||
r.lastReqQueued = true
|
||||
return r.stateRequesting
|
||||
case ev := <-r.eventsCh:
|
||||
r.update(ev)
|
||||
|
|
@ -260,22 +260,26 @@ func (r *sentReq) stateStopped() reqStateFn {
|
|||
func (r *sentReq) update(ev reqPeerEvent) {
|
||||
switch ev.event {
|
||||
case rpSent:
|
||||
r.reqQueued = false
|
||||
if ev.peer != nil {
|
||||
r.reqSent = true
|
||||
}
|
||||
r.lastReqQueued = false
|
||||
r.lastReqSentTo = ev.peer
|
||||
case rpSoftTimeout:
|
||||
r.reqSent = false
|
||||
r.lastReqSentTo = nil
|
||||
r.reqSrtoCount++
|
||||
case rpHardTimeout, rpDeliveredValid, rpDeliveredInvalid:
|
||||
case rpHardTimeout:
|
||||
r.reqSrtoCount--
|
||||
case rpDeliveredValid, rpDeliveredInvalid:
|
||||
if ev.peer == r.lastReqSentTo {
|
||||
r.lastReqSentTo = nil
|
||||
} else {
|
||||
r.reqSrtoCount--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waiting returns true if the retrieval mechanism is waiting for an answer from
|
||||
// any peer
|
||||
func (r *sentReq) waiting() bool {
|
||||
return r.reqQueued || r.reqSent || r.reqSrtoCount > 0
|
||||
return r.lastReqQueued || r.lastReqSentTo != nil || r.reqSrtoCount > 0
|
||||
}
|
||||
|
||||
// tryRequest tries to send the request to a new peer and waits for it to either
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ type LesServer struct {
|
|||
|
||||
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
||||
quitSync := make(chan struct{})
|
||||
pm, err := NewProtocolManager(eth.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, quitSync, new(sync.WaitGroup))
|
||||
pm, err := NewProtocolManager(eth.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -433,6 +433,18 @@ func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []c
|
|||
return self.hc.GetBlockHashesFromHash(hash, max)
|
||||
}
|
||||
|
||||
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
|
||||
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
|
||||
// number of blocks to be individually checked before we reach the canonical chain.
|
||||
//
|
||||
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
||||
func (bc *LightChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
|
||||
bc.chainmu.Lock()
|
||||
defer bc.chainmu.Unlock()
|
||||
|
||||
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
|
||||
}
|
||||
|
||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||
// caching it (associated with its hash) if found.
|
||||
func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||
|
|
|
|||
|
|
@ -59,18 +59,18 @@ type trustedCheckpoint struct {
|
|||
var (
|
||||
mainnetCheckpoint = trustedCheckpoint{
|
||||
name: "mainnet",
|
||||
sectionIdx: 170,
|
||||
sectionHead: common.HexToHash("3bb2c28bcce463d57968f14f56cdb3fbf35349ab7a701f44c1afb57349c9a356"),
|
||||
chtRoot: common.HexToHash("d92b6d0853455f8439086292338e87f69781921680dd7aa072fb71547b87415e"),
|
||||
bloomTrieRoot: common.HexToHash("e4e8250a2fefddead7ae42daecd848cbf9b66d748a8270f8bbd4370b764bb9e9"),
|
||||
sectionIdx: 174,
|
||||
sectionHead: common.HexToHash("a3ef48cd8f1c3a08419f0237fc7763491fe89497b3144b17adf87c1c43664613"),
|
||||
chtRoot: common.HexToHash("dcbeed9f4dea1b3cb75601bb27c51b9960c28e5850275402ac49a150a667296e"),
|
||||
bloomTrieRoot: common.HexToHash("6b7497a4a03e33870a2383cb6f5e70570f12b1bf5699063baf8c71d02ca90b02"),
|
||||
}
|
||||
|
||||
ropstenCheckpoint = trustedCheckpoint{
|
||||
name: "ropsten",
|
||||
sectionIdx: 97,
|
||||
sectionHead: common.HexToHash("719448c67c01eb5b9f27833a36a4e34612f66801316d7ff37daf9e77fb4cd095"),
|
||||
chtRoot: common.HexToHash("a7857afc15930ca6e583b6c3d563a025144011655843d52d28e2fdaadd417bea"),
|
||||
bloomTrieRoot: common.HexToHash("9c71d4b50cbec86dfeaa8e08992de8a4667b81d13c54d6522b17ce2fc5d36416"),
|
||||
sectionIdx: 102,
|
||||
sectionHead: common.HexToHash("9017ab08465cb2b2dee035ee5b817bbd7fa28e2c8d2cd903e0aed1cccb249e89"),
|
||||
chtRoot: common.HexToHash("f61c10a7a787a5ef15f0ae1ae6c13c64331e57e79d0466d2bd9b0c06833fe956"),
|
||||
bloomTrieRoot: common.HexToHash("69f2ad19aa46d5213a90137b3d2c9bff8a7c9483f7170f0125096ff450c9a873"),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
const (
|
||||
timeFormat = "2006-01-02T15:04:05-0700"
|
||||
termTimeFormat = "01-02|15:04:05"
|
||||
termTimeFormat = "01-02|15:04:05.999999"
|
||||
floatFormat = 'f'
|
||||
termMsgJust = 40
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const timeKey = "t"
|
|||
const lvlKey = "lvl"
|
||||
const msgKey = "msg"
|
||||
const errorKey = "LOG15_ERROR"
|
||||
const skipLevel = 2
|
||||
|
||||
type Lvl int
|
||||
|
||||
|
|
@ -127,13 +128,13 @@ type logger struct {
|
|||
h *swapHandler
|
||||
}
|
||||
|
||||
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
|
||||
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) {
|
||||
l.h.Log(&Record{
|
||||
Time: time.Now(),
|
||||
Lvl: lvl,
|
||||
Msg: msg,
|
||||
Ctx: newContext(l.ctx, ctx),
|
||||
Call: stack.Caller(2),
|
||||
Call: stack.Caller(skip),
|
||||
KeyNames: RecordKeyNames{
|
||||
Time: timeKey,
|
||||
Msg: msgKey,
|
||||
|
|
@ -157,27 +158,27 @@ func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
|
|||
}
|
||||
|
||||
func (l *logger) Trace(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlTrace, ctx)
|
||||
l.write(msg, LvlTrace, ctx, skipLevel)
|
||||
}
|
||||
|
||||
func (l *logger) Debug(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlDebug, ctx)
|
||||
l.write(msg, LvlDebug, ctx, skipLevel)
|
||||
}
|
||||
|
||||
func (l *logger) Info(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlInfo, ctx)
|
||||
l.write(msg, LvlInfo, ctx, skipLevel)
|
||||
}
|
||||
|
||||
func (l *logger) Warn(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlWarn, ctx)
|
||||
l.write(msg, LvlWarn, ctx, skipLevel)
|
||||
}
|
||||
|
||||
func (l *logger) Error(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlError, ctx)
|
||||
l.write(msg, LvlError, ctx, skipLevel)
|
||||
}
|
||||
|
||||
func (l *logger) Crit(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlCrit, ctx)
|
||||
l.write(msg, LvlCrit, ctx, skipLevel)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
|
|||
21
log/root.go
21
log/root.go
|
|
@ -31,31 +31,40 @@ func Root() Logger {
|
|||
|
||||
// Trace is a convenient alias for Root().Trace
|
||||
func Trace(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlTrace, ctx)
|
||||
root.write(msg, LvlTrace, ctx, skipLevel)
|
||||
}
|
||||
|
||||
// Debug is a convenient alias for Root().Debug
|
||||
func Debug(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlDebug, ctx)
|
||||
root.write(msg, LvlDebug, ctx, skipLevel)
|
||||
}
|
||||
|
||||
// Info is a convenient alias for Root().Info
|
||||
func Info(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlInfo, ctx)
|
||||
root.write(msg, LvlInfo, ctx, skipLevel)
|
||||
}
|
||||
|
||||
// Warn is a convenient alias for Root().Warn
|
||||
func Warn(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlWarn, ctx)
|
||||
root.write(msg, LvlWarn, ctx, skipLevel)
|
||||
}
|
||||
|
||||
// Error is a convenient alias for Root().Error
|
||||
func Error(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlError, ctx)
|
||||
root.write(msg, LvlError, ctx, skipLevel)
|
||||
}
|
||||
|
||||
// Crit is a convenient alias for Root().Crit
|
||||
func Crit(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlCrit, ctx)
|
||||
root.write(msg, LvlCrit, ctx, skipLevel)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Output is a convenient alias for write, allowing for the modification of
|
||||
// the calldepth (number of stack frames to skip).
|
||||
// calldepth influences the reported line number of the log message.
|
||||
// A calldepth of zero reports the immediate caller of Output.
|
||||
// Non-zero calldepth skips as many stack frames.
|
||||
func Output(msg string, lvl Lvl, calldepth int, ctx ...interface{}) {
|
||||
root.write(msg, lvl, ctx, calldepth+skipLevel)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,17 +68,20 @@ func CollectProcessMetrics(refresh time.Duration) {
|
|||
}
|
||||
// Iterate loading the different stats and updating the meters
|
||||
for i := 1; ; i++ {
|
||||
runtime.ReadMemStats(memstats[i%2])
|
||||
memAllocs.Mark(int64(memstats[i%2].Mallocs - memstats[(i-1)%2].Mallocs))
|
||||
memFrees.Mark(int64(memstats[i%2].Frees - memstats[(i-1)%2].Frees))
|
||||
memInuse.Mark(int64(memstats[i%2].Alloc - memstats[(i-1)%2].Alloc))
|
||||
memPauses.Mark(int64(memstats[i%2].PauseTotalNs - memstats[(i-1)%2].PauseTotalNs))
|
||||
location1 := i % 2
|
||||
location2 := (i - 1) % 2
|
||||
|
||||
if ReadDiskStats(diskstats[i%2]) == nil {
|
||||
diskReads.Mark(diskstats[i%2].ReadCount - diskstats[(i-1)%2].ReadCount)
|
||||
diskReadBytes.Mark(diskstats[i%2].ReadBytes - diskstats[(i-1)%2].ReadBytes)
|
||||
diskWrites.Mark(diskstats[i%2].WriteCount - diskstats[(i-1)%2].WriteCount)
|
||||
diskWriteBytes.Mark(diskstats[i%2].WriteBytes - diskstats[(i-1)%2].WriteBytes)
|
||||
runtime.ReadMemStats(memstats[location1])
|
||||
memAllocs.Mark(int64(memstats[location1].Mallocs - memstats[location2].Mallocs))
|
||||
memFrees.Mark(int64(memstats[location1].Frees - memstats[location2].Frees))
|
||||
memInuse.Mark(int64(memstats[location1].Alloc - memstats[location2].Alloc))
|
||||
memPauses.Mark(int64(memstats[location1].PauseTotalNs - memstats[location2].PauseTotalNs))
|
||||
|
||||
if ReadDiskStats(diskstats[location1]) == nil {
|
||||
diskReads.Mark(diskstats[location1].ReadCount - diskstats[location2].ReadCount)
|
||||
diskReadBytes.Mark(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes)
|
||||
diskWrites.Mark(diskstats[location1].WriteCount - diskstats[location2].WriteCount)
|
||||
diskWriteBytes.Mark(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes)
|
||||
}
|
||||
time.Sleep(refresh)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,11 @@ type NilResettingTimer struct {
|
|||
func (NilResettingTimer) Values() []int64 { return nil }
|
||||
|
||||
// Snapshot is a no-op.
|
||||
func (NilResettingTimer) Snapshot() ResettingTimer { return NilResettingTimer{} }
|
||||
func (NilResettingTimer) Snapshot() ResettingTimer {
|
||||
return &ResettingTimerSnapshot{
|
||||
values: []int64{},
|
||||
}
|
||||
}
|
||||
|
||||
// Time is a no-op.
|
||||
func (NilResettingTimer) Time(func()) {}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ func TestTimerStop(t *testing.T) {
|
|||
func TestTimerFunc(t *testing.T) {
|
||||
tm := NewTimer()
|
||||
tm.Time(func() { time.Sleep(50e6) })
|
||||
if max := tm.Max(); 35e6 > max || max > 95e6 {
|
||||
t.Errorf("tm.Max(): 35e6 > %v || %v > 95e6\n", max, max)
|
||||
if max := tm.Max(); 35e6 > max || max > 145e6 {
|
||||
t.Errorf("tm.Max(): 35e6 > %v || %v > 145e6\n", max, max)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -480,16 +480,16 @@ func (tab *Table) doRevalidate(done chan<- struct{}) {
|
|||
b := tab.buckets[bi]
|
||||
if err == nil {
|
||||
// The node responded, move it to the front.
|
||||
log.Debug("Revalidated node", "b", bi, "id", last.ID)
|
||||
log.Trace("Revalidated node", "b", bi, "id", last.ID)
|
||||
b.bump(last)
|
||||
return
|
||||
}
|
||||
// No reply received, pick a replacement or delete the node if there aren't
|
||||
// any replacements.
|
||||
if r := tab.replace(b, last); r != nil {
|
||||
log.Debug("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP)
|
||||
log.Trace("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP)
|
||||
} else {
|
||||
log.Debug("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP)
|
||||
log.Trace("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
)
|
||||
|
||||
|
|
@ -217,6 +219,8 @@ func (p *Peer) Drop(err error) {
|
|||
// this low level call will be wrapped by libraries providing routed or broadcast sends
|
||||
// but often just used to forward and push messages to directly connected peers
|
||||
func (p *Peer) Send(msg interface{}) error {
|
||||
defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now())
|
||||
metrics.GetOrRegisterCounter("peer.send", nil).Inc(1)
|
||||
code, found := p.spec.GetCode(msg)
|
||||
if !found {
|
||||
return errorf(ErrInvalidMsgType, "%v", code)
|
||||
|
|
|
|||
|
|
@ -373,15 +373,14 @@ WAIT:
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMultiplePeersDropSelf(t *testing.T) {
|
||||
func XTestMultiplePeersDropSelf(t *testing.T) {
|
||||
runMultiplePeers(t, 0,
|
||||
fmt.Errorf("subprotocol error"),
|
||||
fmt.Errorf("Message handler error: (msg code 3): dropped"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestMultiplePeersDropOther(t *testing.T) {
|
||||
func XTestMultiplePeersDropOther(t *testing.T) {
|
||||
runMultiplePeers(t, 1,
|
||||
fmt.Errorf("Message handler error: (msg code 3): dropped"),
|
||||
fmt.Errorf("subprotocol error"),
|
||||
|
|
|
|||
|
|
@ -528,9 +528,9 @@ func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) {
|
|||
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
|
||||
}
|
||||
// TODO: fewer pointless conversions
|
||||
pub := crypto.ToECDSAPub(pubKey65)
|
||||
if pub.X == nil {
|
||||
return nil, fmt.Errorf("invalid public key")
|
||||
pub, err := crypto.UnmarshalPubkey(pubKey65)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ecies.ImportECDSAPublic(pub), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations/pipes"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
|
|
@ -159,7 +160,7 @@ func TestProtocolHandshake(t *testing.T) {
|
|||
wg sync.WaitGroup
|
||||
)
|
||||
|
||||
fd0, fd1, err := tcpPipe()
|
||||
fd0, fd1, err := pipes.TCPPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -601,31 +602,3 @@ func TestHandshakeForwardCompatibility(t *testing.T) {
|
|||
t.Errorf("ingress-mac('foo') mismatch:\ngot %x\nwant %x", fooIngressHash, wantFooIngressHash)
|
||||
}
|
||||
}
|
||||
|
||||
// tcpPipe creates an in process full duplex pipe based on a localhost TCP socket
|
||||
func tcpPipe() (net.Conn, net.Conn, error) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
var aconn net.Conn
|
||||
aerr := make(chan error, 1)
|
||||
go func() {
|
||||
var err error
|
||||
aconn, err = l.Accept()
|
||||
aerr <- err
|
||||
}()
|
||||
|
||||
dconn, err := net.Dial("tcp", l.Addr().String())
|
||||
if err != nil {
|
||||
<-aerr
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := <-aerr; err != nil {
|
||||
dconn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return aconn, dconn, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -594,13 +594,13 @@ running:
|
|||
// This channel is used by AddPeer to add to the
|
||||
// ephemeral static peer list. Add it to the dialer,
|
||||
// it will keep the node connected.
|
||||
srv.log.Debug("Adding static node", "node", n)
|
||||
srv.log.Trace("Adding static node", "node", n)
|
||||
dialstate.addStatic(n)
|
||||
case n := <-srv.removestatic:
|
||||
// This channel is used by RemovePeer to send a
|
||||
// disconnect request to a peer and begin the
|
||||
// stop keeping the node connected
|
||||
srv.log.Debug("Removing static node", "node", n)
|
||||
srv.log.Trace("Removing static node", "node", n)
|
||||
dialstate.removeStatic(n)
|
||||
if p, ok := peers[n.ID]; ok {
|
||||
p.Disconnect(DiscRequested)
|
||||
|
|
|
|||
|
|
@ -28,11 +28,14 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLinuxOnly = errors.New("DockerAdapter can only be used on Linux as it uses the current binary (which must be a Linux binary)")
|
||||
)
|
||||
|
||||
// DockerAdapter is a NodeAdapter which runs simulation nodes inside Docker
|
||||
// containers.
|
||||
//
|
||||
|
|
@ -52,7 +55,7 @@ func NewDockerAdapter() (*DockerAdapter, error) {
|
|||
// It is reasonable to require this because the caller can just
|
||||
// compile the current binary in a Docker container.
|
||||
if runtime.GOOS != "linux" {
|
||||
return nil, errors.New("DockerAdapter can only be used on Linux as it uses the current binary (which must be a Linux binary)")
|
||||
return nil, ErrLinuxOnly
|
||||
}
|
||||
|
||||
if err := buildDockerImage(); err != nil {
|
||||
|
|
@ -95,7 +98,10 @@ func (d *DockerAdapter) NewNode(config *NodeConfig) (Node, error) {
|
|||
conf.Stack.P2P.NoDiscovery = true
|
||||
conf.Stack.P2P.NAT = nil
|
||||
conf.Stack.NoUSB = true
|
||||
conf.Stack.Logger = log.New("node.id", config.ID.String())
|
||||
|
||||
// listen on all interfaces on a given port, which we set when we
|
||||
// initialise NodeConfig (usually a random port)
|
||||
conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port)
|
||||
|
||||
node := &DockerNode{
|
||||
ExecNode: ExecNode{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package adapters
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/json"
|
||||
|
|
@ -103,9 +104,9 @@ func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) {
|
|||
conf.Stack.P2P.NAT = nil
|
||||
conf.Stack.NoUSB = true
|
||||
|
||||
// listen on a random localhost port (we'll get the actual port after
|
||||
// starting the node through the RPC admin.nodeInfo method)
|
||||
conf.Stack.P2P.ListenAddr = "127.0.0.1:0"
|
||||
// listen on a localhost port, which we set when we
|
||||
// initialise NodeConfig (usually a random port)
|
||||
conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port)
|
||||
|
||||
node := &ExecNode{
|
||||
ID: config.ID,
|
||||
|
|
@ -190,9 +191,23 @@ func (n *ExecNode) Start(snapshots map[string][]byte) (err error) {
|
|||
n.Cmd = cmd
|
||||
|
||||
// read the WebSocket address from the stderr logs
|
||||
wsAddr, err := findWSAddr(stderrR, 10*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting WebSocket address: %s", err)
|
||||
var wsAddr string
|
||||
wsAddrC := make(chan string)
|
||||
go func() {
|
||||
s := bufio.NewScanner(stderrR)
|
||||
for s.Scan() {
|
||||
if strings.Contains(s.Text(), "WebSocket endpoint opened") {
|
||||
wsAddrC <- wsAddrPattern.FindString(s.Text())
|
||||
}
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case wsAddr = <-wsAddrC:
|
||||
if wsAddr == "" {
|
||||
return errors.New("failed to read WebSocket address from stderr")
|
||||
}
|
||||
case <-time.After(10 * time.Second):
|
||||
return errors.New("timed out waiting for WebSocket address on stderr")
|
||||
}
|
||||
|
||||
// create the RPC client and load the node info
|
||||
|
|
@ -318,6 +333,21 @@ type execNodeConfig struct {
|
|||
PeerAddrs map[string]string `json:"peer_addrs,omitempty"`
|
||||
}
|
||||
|
||||
// ExternalIP gets an external IP address so that Enode URL is usable
|
||||
func ExternalIP() net.IP {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
log.Crit("error getting IP address", "err", err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() && !ip.IP.IsLinkLocalUnicast() {
|
||||
return ip.IP
|
||||
}
|
||||
}
|
||||
log.Warn("unable to determine explicit IP address, falling back to loopback")
|
||||
return net.IP{127, 0, 0, 1}
|
||||
}
|
||||
|
||||
// execP2PNode starts a devp2p node when the current binary is executed with
|
||||
// argv[0] being "p2p-node", reading the service / ID from argv[1] / argv[2]
|
||||
// and the node config from the _P2P_NODE_CONFIG environment variable
|
||||
|
|
@ -341,25 +371,11 @@ func execP2PNode() {
|
|||
conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey
|
||||
conf.Stack.Logger = log.New("node.id", conf.Node.ID.String())
|
||||
|
||||
// use explicit IP address in ListenAddr so that Enode URL is usable
|
||||
externalIP := func() string {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
log.Crit("error getting IP address", "err", err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() {
|
||||
return ip.IP.String()
|
||||
}
|
||||
}
|
||||
log.Crit("unable to determine explicit IP address")
|
||||
return ""
|
||||
}
|
||||
if strings.HasPrefix(conf.Stack.P2P.ListenAddr, ":") {
|
||||
conf.Stack.P2P.ListenAddr = externalIP() + conf.Stack.P2P.ListenAddr
|
||||
conf.Stack.P2P.ListenAddr = ExternalIP().String() + conf.Stack.P2P.ListenAddr
|
||||
}
|
||||
if conf.Stack.WSHost == "0.0.0.0" {
|
||||
conf.Stack.WSHost = externalIP()
|
||||
conf.Stack.WSHost = ExternalIP().String()
|
||||
}
|
||||
|
||||
// initialize the devp2p stack
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@ import (
|
|||
"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/simulations/pipes"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
// SimAdapter is a NodeAdapter which creates in-memory simulation nodes and
|
||||
// connects them using in-memory net.Pipe connections
|
||||
// connects them using net.Pipe
|
||||
type SimAdapter struct {
|
||||
pipe func() (net.Conn, net.Conn, error)
|
||||
mtx sync.RWMutex
|
||||
nodes map[discover.NodeID]*SimNode
|
||||
services map[string]ServiceFunc
|
||||
|
|
@ -42,8 +44,18 @@ type SimAdapter struct {
|
|||
// NewSimAdapter creates a SimAdapter which is capable of running in-memory
|
||||
// simulation nodes running any of the given services (the services to run on a
|
||||
// particular node are passed to the NewNode function in the NodeConfig)
|
||||
// the adapter uses a net.Pipe for in-memory simulated network connections
|
||||
func NewSimAdapter(services map[string]ServiceFunc) *SimAdapter {
|
||||
return &SimAdapter{
|
||||
pipe: pipes.NetPipe,
|
||||
nodes: make(map[discover.NodeID]*SimNode),
|
||||
services: services,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTCPAdapter(services map[string]ServiceFunc) *SimAdapter {
|
||||
return &SimAdapter{
|
||||
pipe: pipes.TCPPipe,
|
||||
nodes: make(map[discover.NodeID]*SimNode),
|
||||
services: services,
|
||||
}
|
||||
|
|
@ -81,7 +93,7 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
|
|||
MaxPeers: math.MaxInt32,
|
||||
NoDiscovery: true,
|
||||
Dialer: s,
|
||||
EnableMsgEvents: true,
|
||||
EnableMsgEvents: config.EnableMsgEvents,
|
||||
},
|
||||
NoUSB: true,
|
||||
Logger: log.New("node.id", id.String()),
|
||||
|
|
@ -102,7 +114,7 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
|
|||
}
|
||||
|
||||
// Dial implements the p2p.NodeDialer interface by connecting to the node using
|
||||
// an in-memory net.Pipe connection
|
||||
// an in-memory net.Pipe
|
||||
func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) {
|
||||
node, ok := s.GetNode(dest.ID)
|
||||
if !ok {
|
||||
|
|
@ -112,7 +124,14 @@ func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) {
|
|||
if srv == nil {
|
||||
return nil, fmt.Errorf("node not running: %s", dest.ID)
|
||||
}
|
||||
pipe1, pipe2 := net.Pipe()
|
||||
// SimAdapter.pipe is net.Pipe (NewSimAdapter)
|
||||
pipe1, pipe2, err := s.pipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// this is simulated 'listening'
|
||||
// asynchronously call the dialed destintion node's p2p server
|
||||
// to set up connection on the 'listening' side
|
||||
go srv.SetupConn(pipe1, 0, nil)
|
||||
return pipe2, nil
|
||||
}
|
||||
|
|
@ -140,8 +159,8 @@ func (s *SimAdapter) GetNode(id discover.NodeID) (*SimNode, bool) {
|
|||
}
|
||||
|
||||
// SimNode is an in-memory simulation node which connects to other nodes using
|
||||
// an in-memory net.Pipe connection (see SimAdapter.Dial), running devp2p
|
||||
// protocols directly over that pipe
|
||||
// net.Pipe (see SimAdapter.Dial), running devp2p protocols directly over that
|
||||
// pipe
|
||||
type SimNode struct {
|
||||
lock sync.RWMutex
|
||||
ID discover.NodeID
|
||||
|
|
@ -241,7 +260,7 @@ func (sn *SimNode) Start(snapshots map[string][]byte) error {
|
|||
for _, name := range sn.config.Services {
|
||||
if err := sn.node.Register(newService(name)); err != nil {
|
||||
regErr = err
|
||||
return
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -314,3 +333,18 @@ func (sn *SimNode) NodeInfo() *p2p.NodeInfo {
|
|||
}
|
||||
return server.NodeInfo()
|
||||
}
|
||||
|
||||
func setSocketBuffer(conn net.Conn, socketReadBuffer int, socketWriteBuffer int) error {
|
||||
switch v := conn.(type) {
|
||||
case *net.UnixConn:
|
||||
err := v.SetReadBuffer(socketReadBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = v.SetWriteBuffer(socketWriteBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
259
p2p/simulations/adapters/inproc_test.go
Normal file
259
p2p/simulations/adapters/inproc_test.go
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
// Copyright 2017 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 adapters
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations/pipes"
|
||||
)
|
||||
|
||||
func TestTCPPipe(t *testing.T) {
|
||||
c1, c2, err := pipes.TCPPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
msgs := 50
|
||||
size := 1024
|
||||
for i := 0; i < msgs; i++ {
|
||||
msg := make([]byte, size)
|
||||
_ = binary.PutUvarint(msg, uint64(i))
|
||||
|
||||
_, err := c1.Write(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < msgs; i++ {
|
||||
msg := make([]byte, size)
|
||||
_ = binary.PutUvarint(msg, uint64(i))
|
||||
|
||||
out := make([]byte, size)
|
||||
_, err := c2.Read(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(msg, out) {
|
||||
t.Fatalf("expected %#v, got %#v", msg, out)
|
||||
}
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("test timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPPipeBidirections(t *testing.T) {
|
||||
c1, c2, err := pipes.TCPPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
msgs := 50
|
||||
size := 7
|
||||
for i := 0; i < msgs; i++ {
|
||||
msg := []byte(fmt.Sprintf("ping %02d", i))
|
||||
|
||||
_, err := c1.Write(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < msgs; i++ {
|
||||
expected := []byte(fmt.Sprintf("ping %02d", i))
|
||||
|
||||
out := make([]byte, size)
|
||||
_, err := c2.Read(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, out) {
|
||||
t.Fatalf("expected %#v, got %#v", out, expected)
|
||||
} else {
|
||||
msg := []byte(fmt.Sprintf("pong %02d", i))
|
||||
_, err := c2.Write(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < msgs; i++ {
|
||||
expected := []byte(fmt.Sprintf("pong %02d", i))
|
||||
|
||||
out := make([]byte, size)
|
||||
_, err := c1.Read(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, out) {
|
||||
t.Fatalf("expected %#v, got %#v", out, expected)
|
||||
}
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("test timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetPipe(t *testing.T) {
|
||||
c1, c2, err := pipes.NetPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
msgs := 50
|
||||
size := 1024
|
||||
// netPipe is blocking, so writes are emitted asynchronously
|
||||
go func() {
|
||||
for i := 0; i < msgs; i++ {
|
||||
msg := make([]byte, size)
|
||||
_ = binary.PutUvarint(msg, uint64(i))
|
||||
|
||||
_, err := c1.Write(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < msgs; i++ {
|
||||
msg := make([]byte, size)
|
||||
_ = binary.PutUvarint(msg, uint64(i))
|
||||
|
||||
out := make([]byte, size)
|
||||
_, err := c2.Read(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(msg, out) {
|
||||
t.Fatalf("expected %#v, got %#v", msg, out)
|
||||
}
|
||||
}
|
||||
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("test timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetPipeBidirections(t *testing.T) {
|
||||
c1, c2, err := pipes.NetPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
msgs := 1000
|
||||
size := 8
|
||||
pingTemplate := "ping %03d"
|
||||
pongTemplate := "pong %03d"
|
||||
|
||||
// netPipe is blocking, so writes are emitted asynchronously
|
||||
go func() {
|
||||
for i := 0; i < msgs; i++ {
|
||||
msg := []byte(fmt.Sprintf(pingTemplate, i))
|
||||
|
||||
_, err := c1.Write(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// netPipe is blocking, so reads for pong are emitted asynchronously
|
||||
go func() {
|
||||
for i := 0; i < msgs; i++ {
|
||||
expected := []byte(fmt.Sprintf(pongTemplate, i))
|
||||
|
||||
out := make([]byte, size)
|
||||
_, err := c1.Read(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, out) {
|
||||
t.Fatalf("expected %#v, got %#v", expected, out)
|
||||
}
|
||||
}
|
||||
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
// expect to read pings, and respond with pongs to the alternate connection
|
||||
for i := 0; i < msgs; i++ {
|
||||
expected := []byte(fmt.Sprintf(pingTemplate, i))
|
||||
|
||||
out := make([]byte, size)
|
||||
_, err := c2.Read(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, out) {
|
||||
t.Fatalf("expected %#v, got %#v", expected, out)
|
||||
} else {
|
||||
msg := []byte(fmt.Sprintf(pongTemplate, i))
|
||||
|
||||
_, err := c2.Write(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("test timeout")
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -97,24 +98,30 @@ type NodeConfig struct {
|
|||
|
||||
// function to sanction or prevent suggesting a peer
|
||||
Reachable func(id discover.NodeID) bool
|
||||
|
||||
Port uint16
|
||||
}
|
||||
|
||||
// nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding
|
||||
// all fields as strings
|
||||
type nodeConfigJSON struct {
|
||||
ID string `json:"id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
Name string `json:"name"`
|
||||
Services []string `json:"services"`
|
||||
ID string `json:"id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
Name string `json:"name"`
|
||||
Services []string `json:"services"`
|
||||
EnableMsgEvents bool `json:"enable_msg_events"`
|
||||
Port uint16 `json:"port"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface by encoding the config
|
||||
// fields as strings
|
||||
func (n *NodeConfig) MarshalJSON() ([]byte, error) {
|
||||
confJSON := nodeConfigJSON{
|
||||
ID: n.ID.String(),
|
||||
Name: n.Name,
|
||||
Services: n.Services,
|
||||
ID: n.ID.String(),
|
||||
Name: n.Name,
|
||||
Services: n.Services,
|
||||
Port: n.Port,
|
||||
EnableMsgEvents: n.EnableMsgEvents,
|
||||
}
|
||||
if n.PrivateKey != nil {
|
||||
confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey))
|
||||
|
|
@ -152,6 +159,8 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error {
|
|||
|
||||
n.Name = confJSON.Name
|
||||
n.Services = confJSON.Services
|
||||
n.Port = confJSON.Port
|
||||
n.EnableMsgEvents = confJSON.EnableMsgEvents
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -163,13 +172,36 @@ func RandomNodeConfig() *NodeConfig {
|
|||
if err != nil {
|
||||
panic("unable to generate key")
|
||||
}
|
||||
var id discover.NodeID
|
||||
pubkey := crypto.FromECDSAPub(&key.PublicKey)
|
||||
copy(id[:], pubkey[1:])
|
||||
return &NodeConfig{
|
||||
ID: id,
|
||||
PrivateKey: key,
|
||||
|
||||
id := discover.PubkeyID(&key.PublicKey)
|
||||
port, err := assignTCPPort()
|
||||
if err != nil {
|
||||
panic("unable to assign tcp port")
|
||||
}
|
||||
return &NodeConfig{
|
||||
ID: id,
|
||||
Name: fmt.Sprintf("node_%s", id.String()),
|
||||
PrivateKey: key,
|
||||
Port: port,
|
||||
EnableMsgEvents: true,
|
||||
}
|
||||
}
|
||||
|
||||
func assignTCPPort() (uint16, error) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
l.Close()
|
||||
_, port, err := net.SplitHostPort(l.Addr().String())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
p, err := strconv.ParseInt(port, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(p), nil
|
||||
}
|
||||
|
||||
// ServiceContext is a collection of options and methods which can be utilised
|
||||
|
|
|
|||
|
|
@ -561,7 +561,8 @@ func (s *Server) LoadSnapshot(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
// CreateNode creates a node in the network using the given configuration
|
||||
func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) {
|
||||
config := adapters.RandomNodeConfig()
|
||||
config := &adapters.NodeConfig{}
|
||||
|
||||
err := json.NewDecoder(req.Body).Decode(config)
|
||||
if err != nil && err != io.EOF {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
|
|
|
|||
|
|
@ -348,7 +348,8 @@ func startTestNetwork(t *testing.T, client *Client) []string {
|
|||
nodeCount := 2
|
||||
nodeIDs := make([]string, nodeCount)
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
node, err := client.CreateNode(nil)
|
||||
config := adapters.RandomNodeConfig()
|
||||
node, err := client.CreateNode(config)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating node: %s", err)
|
||||
}
|
||||
|
|
@ -527,7 +528,9 @@ func TestHTTPNodeRPC(t *testing.T) {
|
|||
|
||||
// start a node in the network
|
||||
client := NewClient(s.URL)
|
||||
node, err := client.CreateNode(nil)
|
||||
|
||||
config := adapters.RandomNodeConfig()
|
||||
node, err := client.CreateNode(config)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating node: %s", err)
|
||||
}
|
||||
|
|
@ -589,7 +592,8 @@ func TestHTTPSnapshot(t *testing.T) {
|
|||
nodeCount := 2
|
||||
nodes := make([]*p2p.NodeInfo, nodeCount)
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
node, err := client.CreateNode(nil)
|
||||
config := adapters.RandomNodeConfig()
|
||||
node, err := client.CreateNode(config)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating node: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
|
||||
)
|
||||
|
||||
//a map of mocker names to its function
|
||||
|
|
@ -102,7 +103,13 @@ func startStop(net *Network, quit chan struct{}, nodeCount int) {
|
|||
func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
|
||||
nodes, err := connectNodesInRing(net, nodeCount)
|
||||
if err != nil {
|
||||
panic("Could not startup node network for mocker")
|
||||
select {
|
||||
case <-quit:
|
||||
//error may be due to abortion of mocking; so the quit channel is closed
|
||||
return
|
||||
default:
|
||||
panic("Could not startup node network for mocker")
|
||||
}
|
||||
}
|
||||
for {
|
||||
select {
|
||||
|
|
@ -143,7 +150,7 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
|
|||
log.Debug(fmt.Sprintf("node %v shutting down", nodes[i]))
|
||||
err := net.Stop(nodes[i])
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Error stopping node %s", nodes[i]))
|
||||
log.Error("Error stopping node", "node", nodes[i])
|
||||
wg.Done()
|
||||
continue
|
||||
}
|
||||
|
|
@ -151,7 +158,7 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
|
|||
time.Sleep(randWait)
|
||||
err := net.Start(id)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Error starting node %s", id))
|
||||
log.Error("Error starting node", "node", id)
|
||||
}
|
||||
wg.Done()
|
||||
}(nodes[i])
|
||||
|
|
@ -165,9 +172,10 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
|
|||
func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) {
|
||||
ids := make([]discover.NodeID, nodeCount)
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
node, err := net.NewNode()
|
||||
conf := adapters.RandomNodeConfig()
|
||||
node, err := net.NewNodeWithConfig(conf)
|
||||
if err != nil {
|
||||
log.Error("Error creating a node! %s", err)
|
||||
log.Error("Error creating a node!", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
ids[i] = node.ID()
|
||||
|
|
@ -175,7 +183,7 @@ func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error)
|
|||
|
||||
for _, id := range ids {
|
||||
if err := net.Start(id); err != nil {
|
||||
log.Error("Error starting a node! %s", err)
|
||||
log.Error("Error starting a node!", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Debug(fmt.Sprintf("node %v starting up", id))
|
||||
|
|
@ -183,7 +191,7 @@ func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error)
|
|||
for i, id := range ids {
|
||||
peerID := ids[(i+1)%len(ids)]
|
||||
if err := net.Connect(id, peerID); err != nil {
|
||||
log.Error("Error connecting a node to a peer! %s", err)
|
||||
log.Error("Error connecting a node to a peer!", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,6 +382,15 @@ func (net *Network) GetNodeByName(name string) *Node {
|
|||
return net.getNodeByName(name)
|
||||
}
|
||||
|
||||
// GetNodes returns the existing nodes
|
||||
func (net *Network) GetNodes() (nodes []*Node) {
|
||||
net.lock.Lock()
|
||||
defer net.lock.Unlock()
|
||||
|
||||
nodes = append(nodes, net.Nodes...)
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (net *Network) getNode(id discover.NodeID) *Node {
|
||||
i, found := net.nodeMap[id]
|
||||
if !found {
|
||||
|
|
@ -399,15 +408,6 @@ func (net *Network) getNodeByName(name string) *Node {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetNodes returns the existing nodes
|
||||
func (net *Network) GetNodes() (nodes []*Node) {
|
||||
net.lock.Lock()
|
||||
defer net.lock.Unlock()
|
||||
|
||||
nodes = append(nodes, net.Nodes...)
|
||||
return nodes
|
||||
}
|
||||
|
||||
// GetConn returns the connection which exists between "one" and "other"
|
||||
// regardless of which node initiated the connection
|
||||
func (net *Network) GetConn(oneID, otherID discover.NodeID) *Conn {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ func TestNetworkSimulation(t *testing.T) {
|
|||
nodeCount := 20
|
||||
ids := make([]discover.NodeID, nodeCount)
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
node, err := network.NewNode()
|
||||
conf := adapters.RandomNodeConfig()
|
||||
node, err := network.NewNodeWithConfig(conf)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating node: %s", err)
|
||||
}
|
||||
|
|
|
|||
55
p2p/simulations/pipes/pipes.go
Normal file
55
p2p/simulations/pipes/pipes.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2017 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 pipes
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// NetPipe wraps net.Pipe in a signature returning an error
|
||||
func NetPipe() (net.Conn, net.Conn, error) {
|
||||
p1, p2 := net.Pipe()
|
||||
return p1, p2, nil
|
||||
}
|
||||
|
||||
// TCPPipe creates an in process full duplex pipe based on a localhost TCP socket
|
||||
func TCPPipe() (net.Conn, net.Conn, error) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
var aconn net.Conn
|
||||
aerr := make(chan error, 1)
|
||||
go func() {
|
||||
var err error
|
||||
aconn, err = l.Accept()
|
||||
aerr <- err
|
||||
}()
|
||||
|
||||
dconn, err := net.Dial("tcp", l.Addr().String())
|
||||
if err != nil {
|
||||
<-aerr
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := <-aerr; err != nil {
|
||||
dconn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return aconn, dconn, nil
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 1 // Major version component of the current release
|
||||
VersionMinor = 8 // Minor version component of the current release
|
||||
VersionPatch = 11 // Patch version component of the current release
|
||||
VersionPatch = 12 // Patch version component of the current release
|
||||
VersionMeta = "unstable" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const (
|
|||
// The approach taken here is to maintain a per-subscription linked list buffer
|
||||
// shrinks on demand. If the buffer reaches the size below, the subscription is
|
||||
// dropped.
|
||||
maxClientSubscriptionBuffer = 8000
|
||||
maxClientSubscriptionBuffer = 20000
|
||||
)
|
||||
|
||||
// BatchElem is an element in a batch request.
|
||||
|
|
|
|||
10
rpc/json.go
10
rpc/json.go
|
|
@ -320,10 +320,7 @@ func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]
|
|||
|
||||
// CreateResponse will create a JSON-RPC success response with the given id and reply as result.
|
||||
func (c *jsonCodec) CreateResponse(id interface{}, reply interface{}) interface{} {
|
||||
if isHexNum(reflect.TypeOf(reply)) {
|
||||
return &jsonSuccessResponse{Version: jsonrpcVersion, ID: id, Result: fmt.Sprintf(`%#x`, reply)}
|
||||
}
|
||||
return &jsonSuccessResponse{Version: jsonrpcVersion, ID: id, Result: reply}
|
||||
return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: reply}
|
||||
}
|
||||
|
||||
// CreateErrorResponse will create a JSON-RPC error response with the given id and error.
|
||||
|
|
@ -340,11 +337,6 @@ func (c *jsonCodec) CreateErrorResponseWithInfo(id interface{}, err Error, info
|
|||
|
||||
// CreateNotification will create a JSON-RPC notification with the given subscription id and event as params.
|
||||
func (c *jsonCodec) CreateNotification(subid, namespace string, event interface{}) interface{} {
|
||||
if isHexNum(reflect.TypeOf(event)) {
|
||||
return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix,
|
||||
Params: jsonSubscription{Subscription: subid, Result: fmt.Sprintf(`%#x`, event)}}
|
||||
}
|
||||
|
||||
return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix,
|
||||
Params: jsonSubscription{Subscription: subid, Result: event}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func (s *Server) serveRequest(ctx context.Context, codec ServerCodec, singleShot
|
|||
defer cancel()
|
||||
|
||||
// if the codec supports notification include a notifier that callbacks can use
|
||||
// to send notification to clients. It is thight to the codec/connection. If the
|
||||
// to send notification to clients. It is tied to the codec/connection. If the
|
||||
// connection is closed the notifier will stop and cancels all active subscriptions.
|
||||
if options&OptionSubscriptions == OptionSubscriptions {
|
||||
ctx = context.WithValue(ctx, notifierKey{}, newNotifier(codec))
|
||||
|
|
@ -313,7 +313,6 @@ func (s *Server) handle(ctx context.Context, codec ServerCodec, req *serverReque
|
|||
if len(reply) == 0 {
|
||||
return codec.CreateResponse(req.id, nil), nil
|
||||
}
|
||||
|
||||
if req.callb.errPos >= 0 { // test if method returned an error
|
||||
if !reply[req.callb.errPos].IsNil() {
|
||||
e := reply[req.callb.errPos].Interface().(error)
|
||||
|
|
|
|||
15
rpc/utils.go
15
rpc/utils.go
|
|
@ -22,7 +22,6 @@ import (
|
|||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
|
@ -105,20 +104,6 @@ func formatName(name string) string {
|
|||
return string(ret)
|
||||
}
|
||||
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
|
||||
|
||||
// Indication if this type should be serialized in hex
|
||||
func isHexNum(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
return t == bigIntType
|
||||
}
|
||||
|
||||
// suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria
|
||||
// for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server
|
||||
// documentation for a summary of these criteria.
|
||||
|
|
|
|||
|
|
@ -432,13 +432,11 @@ func (api *SignerAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (c
|
|||
}
|
||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||
hash, _ := SignHash(data)
|
||||
rpk, err := crypto.Ecrecover(hash, sig)
|
||||
rpk, err := crypto.SigToPub(hash, sig)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
pubKey := crypto.ToECDSAPub(rpk)
|
||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
||||
return recoveredAddr, nil
|
||||
return crypto.PubkeyToAddress(*rpk), nil
|
||||
}
|
||||
|
||||
// SignHash is a helper function that calculates a hash for the given message that can be
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package swap
|
|||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
|
|
@ -134,6 +135,11 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
|||
out *chequebook.Outbox
|
||||
)
|
||||
|
||||
remotekey, err := crypto.UnmarshalPubkey(common.FromHex(remote.PublicKey))
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid remote public key")
|
||||
}
|
||||
|
||||
// check if remote chequebook is valid
|
||||
// insolvent chequebooks suicide so will signal as invalid
|
||||
// TODO: monitoring a chequebooks events
|
||||
|
|
@ -142,7 +148,7 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
|||
log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
||||
} else {
|
||||
// remote contract valid, create inbox
|
||||
in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, crypto.ToECDSAPub(common.FromHex(remote.PublicKey)), backend)
|
||||
in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, remotekey, backend)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ func (db *Database) Cap(limit common.StorageSize) error {
|
|||
// db.nodesSize only contains the useful data in the cache, but when reporting
|
||||
// the total memory consumption, the maintenance metadata is also needed to be
|
||||
// counted. For every useful node, we track 2 extra hashes as the flushlist.
|
||||
size := db.nodesSize + common.StorageSize(len(db.nodes)*2*common.HashLength)
|
||||
size := db.nodesSize + common.StorageSize((len(db.nodes)-1)*2*common.HashLength)
|
||||
|
||||
// If the preimage cache got large enough, push to disk. If it's still small
|
||||
// leave for later to deduplicate writes.
|
||||
|
|
@ -512,6 +512,6 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) {
|
|||
// db.nodesSize only contains the useful data in the cache, but when reporting
|
||||
// the total memory consumption, the maintenance metadata is also needed to be
|
||||
// counted. For every useful node, we track 2 extra hashes as the flushlist.
|
||||
var flushlistSize = common.StorageSize(len(db.nodes) * 2 * common.HashLength)
|
||||
var flushlistSize = common.StorageSize((len(db.nodes) - 1) * 2 * common.HashLength)
|
||||
return db.nodesSize + flushlistSize, db.preimagesSize
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,10 +53,9 @@ func hexToCompact(hex []byte) []byte {
|
|||
|
||||
func compactToHex(compact []byte) []byte {
|
||||
base := keybytesToHex(compact)
|
||||
base = base[:len(base)-1]
|
||||
// apply terminator flag
|
||||
if base[0] >= 2 {
|
||||
base = append(base, 16)
|
||||
// delete terminator flag
|
||||
if base[0] < 2 {
|
||||
base = base[:len(base)-1]
|
||||
}
|
||||
// apply odd flag
|
||||
chop := 2 - base[0]&1
|
||||
|
|
|
|||
|
|
@ -252,8 +252,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
|||
|
||||
// Set asymmetric key that is used to encrypt the message
|
||||
if pubKeyGiven {
|
||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
|
||||
return false, ErrInvalidPublicKey
|
||||
}
|
||||
}
|
||||
|
|
@ -329,8 +328,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
|
|||
}
|
||||
|
||||
if len(crit.Sig) > 0 {
|
||||
filter.Src = crypto.ToECDSAPub(crit.Sig)
|
||||
if !ValidatePublicKey(filter.Src) {
|
||||
if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
|
||||
return nil, ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
@ -513,8 +511,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
|
|||
}
|
||||
|
||||
if len(req.Sig) > 0 {
|
||||
src = crypto.ToECDSAPub(req.Sig)
|
||||
if !ValidatePublicKey(src) {
|
||||
if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
|
||||
return "", ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package whisperv5
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
|
|
@ -108,8 +107,6 @@ func TestSimulation(t *testing.T) {
|
|||
|
||||
func initialize(t *testing.T) {
|
||||
var err error
|
||||
ip := net.IPv4(127, 0, 0, 1)
|
||||
port0 := 30303
|
||||
|
||||
for i := 0; i < NumNodes; i++ {
|
||||
var node TestNode
|
||||
|
|
@ -128,29 +125,15 @@ func initialize(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed convert the key: %s.", keys[i])
|
||||
}
|
||||
port := port0 + i
|
||||
addr := fmt.Sprintf(":%d", port) // e.g. ":30303"
|
||||
name := common.MakeName("whisper-go", "2.0")
|
||||
var peers []*discover.Node
|
||||
if i > 0 {
|
||||
peerNodeId := nodes[i-1].id
|
||||
peerPort := uint16(port - 1)
|
||||
peerNode := discover.PubkeyID(&peerNodeId.PublicKey)
|
||||
peer := discover.NewNode(peerNode, ip, peerPort, peerPort)
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
node.server = &p2p.Server{
|
||||
Config: p2p.Config{
|
||||
PrivateKey: node.id,
|
||||
MaxPeers: NumNodes/2 + 1,
|
||||
Name: name,
|
||||
Protocols: node.shh.Protocols(),
|
||||
ListenAddr: addr,
|
||||
NAT: nat.Any(),
|
||||
BootstrapNodes: peers,
|
||||
StaticNodes: peers,
|
||||
TrustedNodes: peers,
|
||||
PrivateKey: node.id,
|
||||
MaxPeers: NumNodes/2 + 1,
|
||||
Name: name,
|
||||
Protocols: node.shh.Protocols(),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
NAT: nat.Any(),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -159,6 +142,15 @@ func initialize(t *testing.T) {
|
|||
t.Fatalf("failed to start server %d.", i)
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
peerNodeId := nodes[j].id
|
||||
address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr)
|
||||
peerPort := uint16(address.Port)
|
||||
peerNode := discover.PubkeyID(&peerNodeId.PublicKey)
|
||||
peer := discover.NewNode(peerNode, address.IP, peerPort, peerPort)
|
||||
node.server.AddPeer(peer)
|
||||
}
|
||||
|
||||
nodes[i] = &node
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,8 +272,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.
|
|||
|
||||
// Set asymmetric key that is used to encrypt the message
|
||||
if pubKeyGiven {
|
||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
|
||||
return nil, ErrInvalidPublicKey
|
||||
}
|
||||
}
|
||||
|
|
@ -360,8 +359,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
|
|||
}
|
||||
|
||||
if len(crit.Sig) > 0 {
|
||||
filter.Src = crypto.ToECDSAPub(crit.Sig)
|
||||
if !ValidatePublicKey(filter.Src) {
|
||||
if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
|
||||
return nil, ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
@ -544,8 +542,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
|
|||
}
|
||||
|
||||
if len(req.Sig) > 0 {
|
||||
src = crypto.ToECDSAPub(req.Sig)
|
||||
if !ValidatePublicKey(src) {
|
||||
if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
|
||||
return "", ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,13 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
mrand "math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"net"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -173,8 +174,6 @@ func initialize(t *testing.T) {
|
|||
initBloom(t)
|
||||
|
||||
var err error
|
||||
ip := net.IPv4(127, 0, 0, 1)
|
||||
port0 := 30303
|
||||
|
||||
for i := 0; i < NumNodes; i++ {
|
||||
var node TestNode
|
||||
|
|
@ -199,40 +198,36 @@ func initialize(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed convert the key: %s.", keys[i])
|
||||
}
|
||||
port := port0 + i
|
||||
addr := fmt.Sprintf(":%d", port) // e.g. ":30303"
|
||||
name := common.MakeName("whisper-go", "2.0")
|
||||
var peers []*discover.Node
|
||||
if i > 0 {
|
||||
peerNodeID := nodes[i-1].id
|
||||
peerPort := uint16(port - 1)
|
||||
peerNode := discover.PubkeyID(&peerNodeID.PublicKey)
|
||||
peer := discover.NewNode(peerNode, ip, peerPort, peerPort)
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
node.server = &p2p.Server{
|
||||
Config: p2p.Config{
|
||||
PrivateKey: node.id,
|
||||
MaxPeers: NumNodes/2 + 1,
|
||||
Name: name,
|
||||
Protocols: node.shh.Protocols(),
|
||||
ListenAddr: addr,
|
||||
NAT: nat.Any(),
|
||||
BootstrapNodes: peers,
|
||||
StaticNodes: peers,
|
||||
TrustedNodes: peers,
|
||||
PrivateKey: node.id,
|
||||
MaxPeers: NumNodes/2 + 1,
|
||||
Name: name,
|
||||
Protocols: node.shh.Protocols(),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
NAT: nat.Any(),
|
||||
},
|
||||
}
|
||||
|
||||
go startServer(t, node.server)
|
||||
|
||||
nodes[i] = &node
|
||||
}
|
||||
|
||||
for i := 0; i < NumNodes; i++ {
|
||||
go startServer(t, nodes[i].server)
|
||||
}
|
||||
|
||||
waitForServersToStart(t)
|
||||
|
||||
for i := 0; i < NumNodes; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
peerNodeId := nodes[j].id
|
||||
address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr)
|
||||
peerPort := uint16(address.Port)
|
||||
peerNode := discover.PubkeyID(&peerNodeId.PublicKey)
|
||||
peer := discover.NewNode(peerNode, address.IP, peerPort, peerPort)
|
||||
nodes[i].server.AddPeer(peer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func startServer(t *testing.T, s *p2p.Server) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue