Merge branch 'master' into ethGolint

This commit is contained in:
Péter Szilágyi 2018-06-14 12:39:07 +03:00 committed by GitHub
commit 2a9cc4ca96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
167 changed files with 31844 additions and 1574 deletions

View file

@ -1 +1 @@
1.8.9
1.8.12

View file

@ -330,6 +330,7 @@ func doLint(cmdline []string) {
configs := []string{
"--vendor",
"--tests",
"--deadline=2m",
"--disable-all",
"--enable=goimports",
"--enable=varcheck",

View file

@ -29,7 +29,7 @@ import (
)
var (
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind, - for STDIN")
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
@ -75,17 +75,28 @@ func main() {
bins []string
types []string
)
if *solFlag != "" {
if *solFlag != "" || *abiFlag == "-" {
// Generate the list of types to exclude from binding
exclude := make(map[string]bool)
for _, kind := range strings.Split(*excFlag, ",") {
exclude[strings.ToLower(kind)] = true
}
contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag)
var contracts map[string]*compiler.Contract
var err error
if *solFlag != "" {
contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag)
if err != nil {
fmt.Printf("Failed to build Solidity contract: %v\n", err)
os.Exit(-1)
}
} else {
contracts, err = contractsFromStdin()
if err != nil {
fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err)
os.Exit(-1)
}
}
// Gather all non-excluded contract for binding
for name, contract := range contracts {
if exclude[strings.ToLower(name)] {
@ -138,3 +149,12 @@ func main() {
os.Exit(-1)
}
}
func contractsFromStdin() (map[string]*compiler.Contract, error) {
bytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return nil, err
}
return compiler.ParseCombinedJSON(bytes, "", "", "", "")
}

View 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
},
}

View file

@ -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)

View file

@ -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)

View file

@ -38,6 +38,7 @@ func init() {
app.Commands = []cli.Command{
commandGenerate,
commandInspect,
commandChangePassphrase,
commandSignMessage,
commandVerifyMessage,
}

View file

@ -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)

View file

@ -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

View file

@ -474,7 +474,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainId)
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
if err != nil {
f.lock.Unlock()
if err = sendError(conn, err); err != nil {

View file

@ -19,12 +19,16 @@ package main
import (
"fmt"
"math"
"os"
"runtime"
godebug "runtime/debug"
"sort"
"strconv"
"strings"
"time"
"github.com/elastic/gosigar"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
@ -188,6 +192,22 @@ func init() {
if err := debug.Setup(ctx); err != nil {
return err
}
// Cap the cache allowance and tune the garbage colelctor
var mem gosigar.Mem
if err := mem.Get(); err == nil {
allowance := int(mem.Total / 1024 / 1024 / 3)
if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance {
log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance))
}
}
// Ensure Go's GC ignores the database cache for trigger percentage
cache := ctx.GlobalInt(utils.CacheFlag.Name)
gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
godebug.SetGCPercent(int(gogc))
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)

View file

@ -103,8 +103,8 @@ func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEther
spec.Params.ByzantiumForkBlock = (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())
spec.Params.ConstantinopleForkBlock = (hexutil.Uint64)(math.MaxUint64)
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64())
spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64())
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
@ -284,7 +284,7 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64())
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.MaxCodeSize = params.MaxCodeSize
spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()
spec.Params.EIP98Transition = math.MaxUint64

View file

@ -609,7 +609,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
}
template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{
"Network": network,
"NetworkID": conf.Genesis.Config.ChainId,
"NetworkID": conf.Genesis.Config.ChainID,
"NetworkTitle": strings.Title(network),
"EthstatsPage": config.ethstats,
"ExplorerPage": config.explorer,

View file

@ -49,7 +49,7 @@ func (w *wizard) deployFaucet() {
existed := err == nil
infos.node.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ")
infos.node.network = w.conf.Genesis.Config.ChainId.Int64()
infos.node.network = w.conf.Genesis.Config.ChainID.Int64()
// Figure out which port to listen on
fmt.Println()

View file

@ -121,7 +121,7 @@ func (w *wizard) makeGenesis() {
// Query the user for some custom extras
fmt.Println()
fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)")
genesis.Config.ChainId = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
// All done, store the genesis and flush to disk
log.Info("Configured new genesis block")

View file

@ -56,7 +56,7 @@ func (w *wizard) deployNode(boot bool) {
existed := err == nil
infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ")
infos.network = w.conf.Genesis.Config.ChainId.Int64()
infos.network = w.conf.Genesis.Config.ChainID.Int64()
// Figure out where the user wants to store the persistent data
fmt.Println()
@ -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 {

View file

@ -52,7 +52,7 @@ func (w *wizard) deployWallet() {
existed := err == nil
infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ")
infos.network = w.conf.Genesis.Config.ChainId.Int64()
infos.network = w.conf.Genesis.Config.ChainID.Int64()
// Figure out which port to listen on
fmt.Println()

View file

@ -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

View file

@ -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")
}
}
}

View file

@ -19,15 +19,20 @@ package common
import "encoding/hex"
// ToHex returns the hex representation of b, prefixed with '0x'.
// For empty slices, the return value is "0x0".
//
// Deprecated: use hexutil.Encode instead.
func ToHex(b []byte) string {
hex := Bytes2Hex(b)
// Prefer output of "0x0" instead of "0x"
if len(hex) == 0 {
hex = "0"
}
return "0x" + hex
}
// FromHex returns the bytes represented by the hexadecimal string s.
// s may be prefixed with "0x".
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" {
@ -40,9 +45,7 @@ func FromHex(s string) []byte {
return Hex2Bytes(s)
}
// Copy bytes
//
// Returns an exact copy of the provided bytes
// CopyBytes returns an exact copy of the provided bytes.
func CopyBytes(b []byte) (copiedBytes []byte) {
if b == nil {
return nil
@ -53,14 +56,17 @@ func CopyBytes(b []byte) (copiedBytes []byte) {
return
}
// hasHexPrefix validates str begins with '0x' or '0X'.
func hasHexPrefix(str string) bool {
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
}
// isHexCharacter returns bool of c being a valid hexadecimal.
func isHexCharacter(c byte) bool {
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
}
// isHex validates whether each byte is valid hexadecimal string.
func isHex(str string) bool {
if len(str)%2 != 0 {
return false
@ -73,16 +79,18 @@ func isHex(str string) bool {
return true
}
// Bytes2Hex returns the hexadecimal encoding of d.
func Bytes2Hex(d []byte) string {
return hex.EncodeToString(d)
}
// Hex2Bytes returns the bytes represented by the hexadecimal string str.
func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
// Hex2BytesFixed returns bytes of a specified fixed length flen.
func Hex2BytesFixed(str string, flen int) []byte {
h, _ := hex.DecodeString(str)
if len(h) == flen {
@ -96,6 +104,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
return hh
}
// RightPadBytes zero-pads slice to the right up to length l.
func RightPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
@ -107,6 +116,7 @@ func RightPadBytes(slice []byte, l int) []byte {
return padded
}
// LeftPadBytes zero-pads slice to the left up to length l.
func LeftPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice

View file

@ -31,11 +31,17 @@ import (
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
// Contract contains information about a compiled contract, alongside its code.
type Contract struct {
Code string `json:"code"`
Info ContractInfo `json:"info"`
}
// ContractInfo contains information about a compiled contract, including access
// to the ABI definition, user and developer docs, and metadata.
//
// Depending on the source, language version, compiler version, and compiler
// options will provide information about how the contract was compiled.
type ContractInfo struct {
Source string `json:"source"`
Language string `json:"language"`
@ -142,8 +148,22 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
}
return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
}
// ParseCombinedJSON takes the direct output of a solc --combined-output run and
// parses it into a map of string contract name to Contract structs. The
// provided source, language and compiler version, and compiler options are all
// passed through into the Contract structs.
//
// The solc output is expected to contain ABI, user docs, and dev docs.
//
// Returns an error if the JSON is malformed or missing data, or if the JSON
// embedded within the JSON is malformed.
func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
var output solcOutput
if err := json.Unmarshal(stdout.Bytes(), &output); err != nil {
if err := json.Unmarshal(combinedJSON, &output); err != nil {
return nil, err
}
@ -168,9 +188,9 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
Info: ContractInfo{
Source: source,
Language: "Solidity",
LanguageVersion: s.Version,
CompilerVersion: s.Version,
CompilerOptions: strings.Join(s.makeArgs(), " "),
LanguageVersion: languageVersion,
CompilerVersion: compilerVersion,
CompilerOptions: compilerOptions,
AbiDefinition: abi,
UserDoc: userdoc,
DeveloperDoc: devdoc,

View file

@ -78,7 +78,7 @@ func ParseBig256(s string) (*big.Int, bool) {
return bigint, ok
}
// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid.
// MustParseBig256 parses s as a 256 bit big integer and panics if the string is invalid.
func MustParseBig256(s string) *big.Int {
v, ok := ParseBig256(s)
if !ok {
@ -186,9 +186,8 @@ func U256(x *big.Int) *big.Int {
func S256(x *big.Int) *big.Int {
if x.Cmp(tt255) < 0 {
return x
} else {
return new(big.Int).Sub(x, tt256)
}
return new(big.Int).Sub(x, tt256)
}
// Exp implements exponentiation by squaring.

View file

@ -34,13 +34,12 @@ func limitUnsigned256(x *Number) *Number {
func limitSigned256(x *Number) *Number {
if x.num.Cmp(tt255) < 0 {
return x
} else {
}
x.num.Sub(x.num, tt256)
return x
}
}
// Number function
// 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
@ -51,65 +50,65 @@ type Number struct {
limit func(n *Number) *Number
}
// Returns a new initialiser for a new *Number without having to expose certain fields
// 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}
}
}
// Return a Number with a UNSIGNED limiter up to 256 bits
// Uint256 returns a Number with a UNSIGNED limiter up to 256 bits
func Uint256(n int64) *Number {
return &Number{big.NewInt(n), limitUnsigned256}
}
// Return a Number with a SIGNED limiter up to 256 bits
// Int256 returns Number with a SIGNED limiter up to 256 bits
func Int256(n int64) *Number {
return &Number{big.NewInt(n), limitSigned256}
}
// Returns a Number with a SIGNED unlimited size
// 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 }}
}
// Sets i to sum of x+y
// 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)
}
// Sets i to difference of x-y
// 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)
}
// Sets i to product of x*y
// 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)
}
// Sets i to the quotient prodject of x/y
// 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)
}
// Sets i to x % y
// 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)
}
// Sets i to x << s
// 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)
}
// Sets i to x^y
// 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)
@ -117,13 +116,13 @@ func (i *Number) Pow(x, y *Number) *Number {
// Setters
// Set x to i
// Set sets x to i
func (i *Number) Set(x *Number) *Number {
i.num.Set(x.num)
return i.limit(i)
}
// Set x bytes to i
// SetBytes sets x bytes to i
func (i *Number) SetBytes(x []byte) *Number {
i.num.SetBytes(x)
return i.limit(i)
@ -140,12 +139,12 @@ func (i *Number) Cmp(x *Number) int {
// Getters
// Returns the string representation of i
// String returns the string representation of i
func (i *Number) String() string {
return i.num.String()
}
// Returns the byte representation of i
// Bytes returns the byte representation of i
func (i *Number) Bytes() []byte {
return i.num.Bytes()
}
@ -160,17 +159,17 @@ func (i *Number) Int64() int64 {
return i.num.Int64()
}
// Returns the signed version of i
// Int256 returns the signed version of i
func (i *Number) Int256() *Number {
return Int(0).Set(i)
}
// Returns the unsigned version of i
// Uint256 returns the unsigned version of i
func (i *Number) Uint256() *Number {
return Uint(0).Set(i)
}
// Returns the index of the first bit that's set to 1
// 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 {

View file

@ -30,6 +30,7 @@ func MakeName(name, version string) string {
return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
}
// FileExist checks if a file exists at filePath.
func FileExist(filePath string) bool {
_, err := os.Stat(filePath)
if err != nil && os.IsNotExist(err) {
@ -39,9 +40,10 @@ func FileExist(filePath string) bool {
return true
}
func AbsolutePath(Datadir string, filename string) string {
// AbsolutePath returns datadir + filename, or filename if it is absolute.
func AbsolutePath(datadir string, filename string) string {
if filepath.IsAbs(filename) {
return filename
}
return filepath.Join(Datadir, filename)
return filepath.Join(datadir, filename)
}

View file

@ -42,18 +42,29 @@ var (
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
type Hash [HashLength]byte
// BytesToHash sets b to hash.
// If b is larger than len(h), b will be cropped from the left.
func BytesToHash(b []byte) Hash {
var h Hash
h.SetBytes(b)
return h
}
// BigToHash sets byte representation of b to hash.
// If b is larger than len(h), b will be cropped from the left.
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
// HexToHash sets byte representation of s to hash.
// If b is larger than len(h), b will be cropped from the left.
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
// Get the string representation of the underlying hash
func (h Hash) Str() string { return string(h[:]) }
// Bytes gets the byte representation of the underlying hash.
func (h Hash) Bytes() []byte { return h[:] }
// Big converts a hash to a big integer.
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
// Hex converts a hash to a hex string.
func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
// TerminalString implements log.TerminalStringer, formatting a string for console
@ -89,7 +100,8 @@ func (h Hash) MarshalText() ([]byte, error) {
return hexutil.Bytes(h[:]).MarshalText()
}
// Sets the hash to the value of b. If b is larger than len(h), 'b' will be cropped (from the left).
// SetBytes sets the hash to the value of b.
// If b is larger than len(h), b will be cropped from the left.
func (h *Hash) SetBytes(b []byte) {
if len(b) > len(h) {
b = b[len(b)-HashLength:]
@ -98,16 +110,6 @@ func (h *Hash) SetBytes(b []byte) {
copy(h[HashLength-len(b):], b)
}
// Set string `s` to h. If s is larger than len(h) s will be cropped (from left) to fit.
func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) }
// Sets h to other
func (h *Hash) Set(other Hash) {
for i, v := range other {
h[i] = v
}
}
// Generate implements testing/quick.Generator.
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
m := rand.Intn(len(h))
@ -117,10 +119,6 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(h)
}
func EmptyHash(h Hash) bool {
return h == Hash{}
}
// UnprefixedHash allows marshaling a Hash without 0x prefix.
type UnprefixedHash Hash
@ -139,12 +137,20 @@ func (h UnprefixedHash) MarshalText() ([]byte, error) {
// Address represents the 20 byte address of an Ethereum account.
type Address [AddressLength]byte
// BytesToAddress returns Address with value b.
// If b is larger than len(h), b will be cropped from the left.
func BytesToAddress(b []byte) Address {
var a Address
a.SetBytes(b)
return a
}
// BigToAddress returns Address with byte values of b.
// If b is larger than len(h), b will be cropped from the left.
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
// HexToAddress returns Address with byte values of s.
// If s is larger than len(h), s will be cropped from the left.
func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
// IsHexAddress verifies whether a string can represent a valid hex-encoded
@ -156,10 +162,13 @@ func IsHexAddress(s string) bool {
return len(s) == 2*AddressLength && isHex(s)
}
// Get the string representation of the underlying address
func (a Address) Str() string { return string(a[:]) }
// Bytes gets the string representation of the underlying address.
func (a Address) Bytes() []byte { return a[:] }
// Big converts an address to a big integer.
func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
// Hash converts an address to a hash by left-padding it with zeros.
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
// Hex returns an EIP55-compliant hex string representation of the address.
@ -184,7 +193,7 @@ func (a Address) Hex() string {
return "0x" + string(result)
}
// String implements the stringer interface and is used also by the logger.
// String implements fmt.Stringer.
func (a Address) String() string {
return a.Hex()
}
@ -195,7 +204,8 @@ func (a Address) Format(s fmt.State, c rune) {
fmt.Fprintf(s, "%"+string(c), a[:])
}
// Sets the address to the value of b. If b is larger than len(a) it will panic
// SetBytes sets the address to the value of b.
// If b is larger than len(a) it will panic.
func (a *Address) SetBytes(b []byte) {
if len(b) > len(a) {
b = b[len(b)-AddressLength:]
@ -203,16 +213,6 @@ func (a *Address) SetBytes(b []byte) {
copy(a[AddressLength-len(b):], b)
}
// Set string `s` to a. If s is larger than len(a) it will panic
func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) }
// Sets a to other
func (a *Address) Set(other Address) {
for i, v := range other {
a[i] = v
}
}
// MarshalText returns the hex representation of a.
func (a Address) MarshalText() ([]byte, error) {
return hexutil.Bytes(a[:]).MarshalText()
@ -228,7 +228,7 @@ func (a *Address) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
}
// UnprefixedHash allows marshaling an Address without 0x prefix.
// UnprefixedAddress allows marshaling an Address without 0x prefix.
type UnprefixedAddress Address
// UnmarshalText decodes the address from hex. The 0x prefix is optional.

View file

@ -1,64 +0,0 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build none
//sed -e 's/_N_/Hash/g' -e 's/_S_/32/g' -e '1d' types_template.go | gofmt -w hash.go
package common
import "math/big"
type _N_ [_S_]byte
func BytesTo_N_(b []byte) _N_ {
var h _N_
h.SetBytes(b)
return h
}
func StringTo_N_(s string) _N_ { return BytesTo_N_([]byte(s)) }
func BigTo_N_(b *big.Int) _N_ { return BytesTo_N_(b.Bytes()) }
func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) }
// Don't use the default 'String' method in case we want to overwrite
// Get the string representation of the underlying hash
func (h _N_) Str() string { return string(h[:]) }
func (h _N_) Bytes() []byte { return h[:] }
func (h _N_) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) }
// Sets the hash to the value of b. If b is larger than len(h) it will panic
func (h *_N_) SetBytes(b []byte) {
// Use the right most bytes
if len(b) > len(h) {
b = b[len(b)-_S_:]
}
// Reverse the loop
for i := len(b) - 1; i >= 0; i-- {
h[_S_-len(b)+i] = b[i]
}
}
// Set string `s` to h. If s is larger than len(h) it will panic
func (h *_N_) SetString(s string) { h.SetBytes([]byte(s)) }
// Sets h to other
func (h *_N_) Set(other _N_) {
for i, v := range other {
h[i] = v
}
}

View file

@ -94,14 +94,25 @@ func calcDatasetSize(epoch int) uint64 {
// reused between hash runs instead of requiring new ones to be created.
type hasher func(dest []byte, data []byte)
// makeHasher creates a repetitive hasher, allowing the same hash data structures
// to be reused between hash runs instead of requiring new ones to be created.
// The returned function is not thread safe!
// makeHasher creates a repetitive hasher, allowing the same hash data structures to
// be reused between hash runs instead of requiring new ones to be created. The returned
// function is not thread safe!
func makeHasher(h hash.Hash) hasher {
// sha3.state supports Read to get the sum, use it to avoid the overhead of Sum.
// Read alters the state but we reset the hash before every operation.
type readerHash interface {
hash.Hash
Read([]byte) (int, error)
}
rh, ok := h.(readerHash)
if !ok {
panic("can't find Read method on hash")
}
outputLen := rh.Size()
return func(dest []byte, data []byte) {
h.Write(data)
h.Sum(dest[:0])
h.Reset()
rh.Reset()
rh.Write(data)
rh.Read(dest[:outputLen])
}
}

View file

@ -271,7 +271,7 @@ func (b *bridge) SleepBlocks(call otto.FunctionCall) (response otto.Value) {
}
type jsonrpcCall struct {
Id int64
ID int64
Method string
Params []interface{}
}
@ -304,7 +304,7 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
resps, _ := call.Otto.Object("new Array()")
for _, req := range reqs {
resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`)
resp.Set("id", req.Id)
resp.Set("id", req.ID)
var result json.RawMessage
err = b.client.Call(&result, req.Method, req.Params...)
switch err := err.(type) {

View file

@ -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 {
@ -73,6 +73,8 @@ type Console struct {
printer io.Writer // Output writer to serialize any display strings to
}
// New initializes a JavaScript interpreted runtime environment and sets defaults
// with the config struct.
func New(config Config) (*Console, error) {
// Handle unset config values gracefully
if config.Prompter == nil {

View file

@ -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 {

View file

@ -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()

View file

@ -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('"') {

View file

@ -674,7 +674,7 @@ func (bc *BlockChain) Stop() {
for !bc.triegc.Empty() {
triedb.Dereference(bc.triegc.PopItem().(common.Hash), common.Hash{})
}
if size := triedb.Size(); size != 0 {
if size, _ := triedb.Size(); size != 0 {
log.Error("Dangling trie nodes after full cleanup")
}
}
@ -916,34 +916,30 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
bc.triegc.Push(root, -float32(block.NumberU64()))
if current := block.NumberU64(); current > triesInMemory {
// If we exceeded our memory allowance, flush matured singleton nodes to disk
var (
nodes, imgs = triedb.Size()
limit = common.StorageSize(bc.cacheConfig.TrieNodeLimit) * 1024 * 1024
)
if nodes > limit || imgs > 4*1024*1024 {
triedb.Cap(limit - ethdb.IdealBatchSize)
}
// Find the next state trie we need to commit
header := bc.GetHeaderByNumber(current - triesInMemory)
chosen := header.Number.Uint64()
// Only write to disk if we exceeded our memory allowance *and* also have at
// least a given number of tries gapped.
var (
size = triedb.Size()
limit = common.StorageSize(bc.cacheConfig.TrieNodeLimit) * 1024 * 1024
)
if size > limit || bc.gcproc > bc.cacheConfig.TrieTimeLimit {
// If we exceeded out time allowance, flush an entire trie to disk
if bc.gcproc > bc.cacheConfig.TrieTimeLimit {
// If we're exceeding limits but haven't reached a large enough memory gap,
// warn the user that the system is becoming unstable.
if chosen < lastWrite+triesInMemory {
switch {
case size >= 2*limit:
log.Warn("State memory usage too high, committing", "size", size, "limit", limit, "optimum", float64(chosen-lastWrite)/triesInMemory)
case bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit:
if chosen < lastWrite+triesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit {
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory)
}
}
// If optimum or critical limits reached, write to disk
if chosen >= lastWrite+triesInMemory || size >= 2*limit || bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit {
// Flush an entire trie and restart the counters
triedb.Commit(header.Root, true)
lastWrite = chosen
bc.gcproc = 0
}
}
// Garbage collect anything below our required write retention
for !bc.triegc.Empty() {
root, number := bc.triegc.Pop()
@ -1009,6 +1005,10 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// only reason this method exists as a separate one is to make locking cleaner
// with deferred statements.
func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*types.Log, error) {
// Sanity check that we have something meaningful to import
if len(chain) == 0 {
return 0, nil, nil, nil
}
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ {
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
@ -1047,6 +1047,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
abort, results := bc.engine.VerifyHeaders(bc, headers, seals)
defer close(abort)
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain)
// Iterate over the blocks and insert when the verifier permits
for i, block := range chain {
// If the chain is terminating, stop processing blocks
@ -1181,7 +1184,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
}
stats.processed++
stats.usedGas += usedGas
stats.report(chain, i, bc.stateCache.TrieDB().Size())
cache, _ := bc.stateCache.TrieDB().Size()
stats.report(chain, i, cache)
}
// Append a single chain head event if we've progressed the chain
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
@ -1387,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.
@ -1525,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 {

View file

@ -578,7 +578,7 @@ func TestFastVsFullChains(t *testing.T) {
Alloc: GenesisAlloc{address: {Balance: funds}},
}
genesis = gspec.MustCommit(gendb)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.NewEIP155Signer(gspec.Config.ChainID)
)
blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
block.SetCoinbase(common.Address{0x00})
@ -753,7 +753,7 @@ func TestChainTxReorgs(t *testing.T) {
},
}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.NewEIP155Signer(gspec.Config.ChainID)
)
// Create two transactions shared between the chains:
@ -859,7 +859,7 @@ func TestLogReorgs(t *testing.T) {
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.NewEIP155Signer(gspec.Config.ChainID)
)
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
@ -906,7 +906,7 @@ func TestReorgSideEvent(t *testing.T) {
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.NewEIP155Signer(gspec.Config.ChainID)
)
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
@ -1032,7 +1032,7 @@ func TestEIP155Transition(t *testing.T) {
funds = big.NewInt(1000000000)
deleteAddr = common.Address{1}
gspec = &Genesis{
Config: &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Config: &params.ChainConfig{ChainID: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
}
genesis = gspec.MustCommit(db)
@ -1063,7 +1063,7 @@ func TestEIP155Transition(t *testing.T) {
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID))
if err != nil {
t.Fatal(err)
}
@ -1075,7 +1075,7 @@ func TestEIP155Transition(t *testing.T) {
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID))
if err != nil {
t.Fatal(err)
}
@ -1103,7 +1103,7 @@ func TestEIP155Transition(t *testing.T) {
}
// generate an invalid chain id transaction
config := &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
config := &params.ChainConfig{ChainID: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
@ -1137,7 +1137,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
theAddr = common.Address{1}
gspec = &Genesis{
Config: &params.ChainConfig{
ChainId: big.NewInt(1),
ChainID: big.NewInt(1),
HomesteadBlock: new(big.Int),
EIP155Block: new(big.Int),
EIP158Block: big.NewInt(2),
@ -1153,7 +1153,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
var (
tx *types.Transaction
err error
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.NewEIP155Signer(gspec.Config.ChainID)
)
switch i {
case 0:

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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()...)
}

View file

@ -219,7 +219,7 @@ func (self *stateObject) updateRoot(db Database) {
self.data.Root = self.trie.Hash()
}
// CommitTrie the storage trie of the object to dwb.
// CommitTrie the storage trie of the object to db.
// This updates the trie root.
func (self *stateObject) CommitTrie(db Database) error {
self.updateTrie(db)

View file

@ -99,7 +99,7 @@ func (s *StateSuite) TestNull(c *checker.C) {
s.state.SetState(address, common.Hash{}, value)
s.state.Commit(false)
value = s.state.GetState(address, common.Hash{})
if !common.EmptyHash(value) {
if value != (common.Hash{}) {
c.Errorf("expected empty hash. got %x", value)
}
}

View file

@ -25,8 +25,8 @@ import (
)
// NewStateSync create a new state trie download scheduler.
func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync {
var syncer *trie.TrieSync
func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.Sync {
var syncer *trie.Sync
callback := func(leaf []byte, parent common.Hash) error {
var obj Account
if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil {
@ -36,6 +36,6 @@ func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync
syncer.AddRawEntry(common.BytesToHash(obj.CodeHash), 64, parent)
return nil
}
syncer = trie.NewTrieSync(root, database, callback)
syncer = trie.NewSync(root, database, callback)
return syncer
}

View file

@ -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

105
core/tx_cacher.go Normal file
View file

@ -0,0 +1,105 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"runtime"
"github.com/ethereum/go-ethereum/core/types"
)
// senderCacher is a concurrent tranaction sender recoverer anc cacher.
var senderCacher = newTxSenderCacher(runtime.NumCPU())
// txSenderCacherRequest is a request for recovering transaction senders with a
// specific signature scheme and caching it into the transactions themselves.
//
// The inc field defines the number of transactions to skip after each recovery,
// which is used to feed the same underlying input array to different threads but
// ensure they process the early transactions fast.
type txSenderCacherRequest struct {
signer types.Signer
txs []*types.Transaction
inc int
}
// txSenderCacher is a helper structure to concurrently ecrecover transaction
// senders from digital signatures on background threads.
type txSenderCacher struct {
threads int
tasks chan *txSenderCacherRequest
}
// newTxSenderCacher creates a new transaction sender background cacher and starts
// as many procesing goroutines as allowed by the GOMAXPROCS on construction.
func newTxSenderCacher(threads int) *txSenderCacher {
cacher := &txSenderCacher{
tasks: make(chan *txSenderCacherRequest, threads),
threads: threads,
}
for i := 0; i < threads; i++ {
go cacher.cache()
}
return cacher
}
// cache is an infinite loop, caching transaction senders from various forms of
// data structures.
func (cacher *txSenderCacher) cache() {
for task := range cacher.tasks {
for i := 0; i < len(task.txs); i += task.inc {
types.Sender(task.signer, task.txs[i])
}
}
}
// recover recovers the senders from a batch of transactions and caches them
// back into the same data structures. There is no validation being done, nor
// any reaction to invalid signatures. That is up to calling code later.
func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transaction) {
// If there's nothing to recover, abort
if len(txs) == 0 {
return
}
// Ensure we have meaningful task sizes and schedule the recoveries
tasks := cacher.threads
if len(txs) < tasks*4 {
tasks = (len(txs) + 3) / 4
}
for i := 0; i < tasks; i++ {
cacher.tasks <- &txSenderCacherRequest{
signer: signer,
txs: txs[i:],
inc: tasks,
}
}
}
// recoverFromBlocks recovers the senders from a batch of blocks and caches them
// back into the same data structures. There is no validation being done, nor
// any reaction to invalid signatures. That is up to calling code later.
func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*types.Block) {
count := 0
for _, block := range blocks {
count += len(block.Transactions())
}
txs := make([]*types.Transaction, 0, count)
for _, block := range blocks {
txs = append(txs, block.Transactions()...)
}
cacher.recover(signer, txs)
}

View file

@ -222,7 +222,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
config: config,
chainconfig: chainconfig,
chain: chain,
signer: types.NewEIP155Signer(chainconfig.ChainId),
signer: types.NewEIP155Signer(chainconfig.ChainID),
pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList),
beats: make(map[common.Address]time.Time),
@ -411,6 +411,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
// Inject any transactions discarded due to reorgs
log.Debug("Reinjecting stale transactions", "count", len(reinject))
senderCacher.recover(pool.signer, reinject)
pool.addTxsLocked(reinject, false)
// validate the pool of pending transactions, this will remove
@ -962,7 +963,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
}
// Notify subsystem for new promoted transactions.
if len(promoted) > 0 {
pool.txFeed.Send(NewTxsEvent{promoted})
go pool.txFeed.Send(NewTxsEvent{promoted})
}
// If the pending limit is overflown, start equalizing allowances
pending := uint64(0)
@ -1106,7 +1107,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()

View file

@ -43,7 +43,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer
switch {
case config.IsEIP155(blockNumber):
signer = NewEIP155Signer(config.ChainId)
signer = NewEIP155Signer(config.ChainID)
case config.IsHomestead(blockNumber):
signer = HomesteadSigner{}
default:

View file

@ -165,28 +165,13 @@ func TestTransactionPriceNonceSort(t *testing.T) {
t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce())
}
}
// Find the previous and next nonce of this account
prev, next := i-1, i+1
for j := i - 1; j >= 0; j-- {
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
prev = j
break
}
}
for j := i + 1; j < len(txs); j++ {
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
next = j
break
}
}
// Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise
for j := prev + 1; j < next; j++ {
fromj, _ := Sender(signer, txs[j])
if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
}
if j > i && txs[j].GasPrice().Cmp(txi.GasPrice()) > 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) > tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
// If the next tx has different from account, the price must be lower than the current one
if i+1 < len(txs) {
next := txs[i+1]
fromNext, _ := Sender(signer, next)
if fromi != fromNext && txi.GasPrice().Cmp(next.GasPrice()) < 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice())
}
}
}

View file

@ -124,12 +124,12 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
// 1. From a zero-value address to a non-zero value (NEW VALUE)
// 2. From a non-zero value address to a zero-value address (DELETE)
// 3. From a non-zero to a non-zero (CHANGE)
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
if val == (common.Hash{}) && y.Sign() != 0 {
// 0 => non 0
return params.SstoreSetGas, nil
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
} else if val != (common.Hash{}) && y.Sign() == 0 {
// non 0 => 0
evm.StateDB.AddRefund(params.SstoreRefundGas)
return params.SstoreClearGas, nil
} else {
// non 0 => non 0 (or 0 => 0)

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -33,7 +33,7 @@ type (
var errGasUintOverflow = errors.New("gas uint64 overflow")
type operation struct {
// op is the operation function
// execute is the operation function
execute executionFunc
// gasCost is the gas function and returns the gas required for execution
gasCost gasFunc

View file

@ -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 {

View file

@ -52,7 +52,7 @@ type Config struct {
func setDefaults(cfg *Config) {
if cfg.ChainConfig == nil {
cfg.ChainConfig = &params.ChainConfig{
ChainId: big.NewInt(1),
ChainID: big.NewInt(1),
HomesteadBlock: new(big.Int),
DAOForkBlock: new(big.Int),
DAOForkSupport: false,

View file

@ -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 {

View file

@ -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)

View file

@ -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")
}
// 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.

View file

@ -251,7 +251,8 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
// Print progress logs if long enough time elapsed
if time.Since(logged) > 8*time.Second {
if number > origin {
log.Info("Tracing chain segment", "start", origin, "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin), "memory", database.TrieDB().Size())
nodes, imgs := database.TrieDB().Size()
log.Info("Tracing chain segment", "start", origin, "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin), "memory", nodes+imgs)
} else {
log.Info("Preparing state for chain trace", "block", number, "start", origin, "elapsed", time.Since(begin))
}
@ -298,6 +299,8 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
// Dereference all past tries we ourselves are done working with
database.TrieDB().Dereference(proot, common.Hash{})
proot = root
// TODO(karalabe): Do we need the preimages? Won't they accumulate too much?
}
}()
@ -526,7 +529,8 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
database.TrieDB().Dereference(proot, common.Hash{})
proot = root
}
log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "size", database.TrieDB().Size())
nodes, imgs := database.TrieDB().Size()
log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs)
return statedb, nil
}

View file

@ -215,14 +215,14 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
return clique.New(chainConfig.Clique, db)
}
// Otherwise assume proof-of-work
switch {
case config.PowMode == ethash.ModeFake:
switch config.PowMode {
case ethash.ModeFake:
log.Warn("Ethash used in fake mode")
return ethash.NewFaker()
case config.PowMode == ethash.ModeTest:
case ethash.ModeTest:
log.Warn("Ethash used in test mode")
return ethash.NewTester()
case config.PowMode == ethash.ModeShared:
case ethash.ModeShared:
log.Warn("Ethash used in shared mode")
return ethash.NewShared()
default:
@ -239,7 +239,7 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
}
}
// APIs returns the collection of RPC services the ethereum package offers.
// APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend)

View file

@ -47,7 +47,7 @@ var DefaultConfig = Config{
LightPeers: 100,
DatabaseCache: 768,
TrieCache: 256,
TrieTimeout: 5 * time.Minute,
TrieTimeout: 60 * time.Minute,
GasPrice: big.NewInt(18 * params.Shannon),
TxPool: core.DefaultTxPoolConfig,

View file

@ -680,7 +680,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
}
}
// If the head fetch already found an ancestor, return
if !common.EmptyHash(hash) {
if hash != (common.Hash{}) {
if int64(number) <= floor {
p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor)
return 0, errInvalidAncestor

View file

@ -214,7 +214,7 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync {
type stateSync struct {
d *Downloader // Downloader instance to access and manage current peerset
sched *trie.TrieSync // State trie sync scheduler defining the tasks
sched *trie.Sync // State trie sync scheduler defining the tasks
keccak hash.Hash // Keccak256 hasher to verify deliveries with
tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval

View file

@ -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
@ -292,20 +292,20 @@ func (f *Fetcher) loop() {
height := f.chainHeight()
for !f.queue.Empty() {
op := f.queue.PopItem().(*inject)
hash := op.block.Hash()
if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), false)
f.queueChangeHook(hash, false)
}
// If too high up the chain or phase, continue later
number := op.block.NumberU64()
if number > height+1 {
f.queue.Push(op, -float32(op.block.NumberU64()))
f.queue.Push(op, -float32(number))
if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), true)
f.queueChangeHook(hash, true)
}
break
}
// Otherwise if fresh and still unknown, try and import
hash := op.block.Hash()
if number+maxUncleDist < height || f.getBlock(hash) != nil {
f.forgetBlock(hash)
continue

View file

@ -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

View file

@ -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 {
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 {
ancestor := query.Skip + 1
if ancestor == 0 {
unknown = true
break
} 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
}

View file

@ -78,7 +78,7 @@
// the final result of the tracing.
result: function(ctx) {
// Save the outer calldata also
if (ctx.input.length > 4) {
if (ctx.input.length >= 4) {
this.store(slice(ctx.input, 0, 4), ctx.input.length-4)
}
return this.ids;

File diff suppressed because one or more lines are too long

View file

@ -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
}

View file

@ -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 {

View file

@ -362,7 +362,7 @@ type nodeInfo struct {
// authMsg is the authentication infos needed to login to a monitoring server.
type authMsg struct {
Id string `json:"id"`
ID string `json:"id"`
Info nodeInfo `json:"info"`
Secret string `json:"secret"`
}
@ -381,7 +381,7 @@ func (s *Service) login(conn *websocket.Conn) error {
protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0])
}
auth := &authMsg{
Id: s.node,
ID: s.node,
Info: nodeInfo{
Name: s.node,
Node: infos.Name,

View file

@ -144,7 +144,7 @@ type FilterQuery struct {
// {} or nil matches any topic list
// {{A}} matches topic A in first position
// {{}, {B}} matches any topic in first position, B in second position
// {{A}}, {B}} matches topic A in first position, B in second position
// {{A}, {B}} matches topic A in first position, B in second position
// {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position
Topics [][]common.Hash
}

View file

@ -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
@ -354,7 +355,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args SendTxArgs
var chainID *big.Int
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
chainID = config.ChainId
chainID = config.ChainID
}
return wallet.SignTxWithPassphrase(account, passwd, tx, chainID)
}
@ -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"`
@ -1096,7 +1102,7 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti
// Request the wallet to sign the transaction
var chainID *big.Int
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
chainID = config.ChainId
chainID = config.ChainID
}
return wallet.SignTx(account, tx, chainID)
}
@ -1216,7 +1222,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
var chainID *big.Int
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
chainID = config.ChainId
chainID = config.ChainID
}
signed, err := wallet.SignTx(account, tx, chainID)
if err != nil {
@ -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))
}
}

View file

@ -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({

View file

@ -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}

View file

@ -19,6 +19,7 @@ package les
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"math/big"
@ -82,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
}
@ -128,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,
@ -140,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,
@ -417,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 (
@ -428,41 +432,58 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Retrieve the next header satisfying the query
var origin *types.Header
if hashMode {
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 {
ancestor := query.Skip + 1
if ancestor == 0 {
unknown = true
break
} 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
if header := pm.blockchain.GetHeaderByNumber(origin.Number.Uint64() + query.Skip + 1); header != nil {
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash {
query.Origin.Hash = header.Hash()
var (
current = origin.Number.Uint64()
next = current + query.Skip + 1
)
if next <= current {
infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ")
p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos)
unknown = true
} else {
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
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
}
} else {
unknown = true
}
}
case query.Reverse:
// Number based traversal towards the genesis block
if query.Origin.Number >= query.Skip+1 {

View file

@ -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
}

View file

@ -69,8 +69,8 @@ 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
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
}
@ -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

View file

@ -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
}

View file

@ -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 {

View file

@ -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"),
}
)

View file

@ -89,7 +89,7 @@ type TxRelayBackend interface {
func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool {
pool := &TxPool{
config: config,
signer: types.NewEIP155Signer(config.ChainId),
signer: types.NewEIP155Signer(config.ChainID),
nonce: make(map[common.Address]uint64),
pending: make(map[common.Hash]*types.Transaction),
mined: make(map[common.Hash][]*types.Transaction),

View file

@ -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
)

View file

@ -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)
}

View file

@ -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)
}

View file

@ -134,6 +134,17 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) {
exp.getFloat(name + ".mean-rate").Set(t.RateMean())
}
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
t := metric.Snapshot()
ps := t.Percentiles([]float64{50, 75, 95, 99})
exp.getInt(name + ".count").Set(int64(len(t.Values())))
exp.getFloat(name + ".mean").Set(t.Mean())
exp.getInt(name + ".50-percentile").Set(ps[0])
exp.getInt(name + ".75-percentile").Set(ps[1])
exp.getInt(name + ".95-percentile").Set(ps[2])
exp.getInt(name + ".99-percentile").Set(ps[3])
}
func (exp *exp) syncToExpvar() {
exp.registry.Each(func(name string, i interface{}) {
switch i.(type) {
@ -149,6 +160,8 @@ func (exp *exp) syncToExpvar() {
exp.publishMeter(name, i.(metrics.Meter))
case metrics.Timer:
exp.publishTimer(name, i.(metrics.Timer))
case metrics.ResettingTimer:
exp.publishResettingTimer(name, i.(metrics.ResettingTimer))
default:
panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
}

View file

@ -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)
}

View file

@ -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()) {}
@ -210,7 +214,7 @@ func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
// poor man's math.Round(x):
// math.Floor(x + 0.5)
indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
if pct >= 0 {
if pct >= 0 && indexOfPerc > 0 {
indexOfPerc -= 1 // index offset=0
}
thresholdBoundary = t.values[indexOfPerc]

View file

@ -104,3 +104,113 @@ func TestResettingTimer(t *testing.T) {
}
}
}
func TestResettingTimerWithFivePercentiles(t *testing.T) {
tests := []struct {
values []int64
start int
end int
wantP05 int64
wantP20 int64
wantP50 int64
wantP95 int64
wantP99 int64
wantMean float64
wantMin int64
wantMax int64
}{
{
values: []int64{},
start: 1,
end: 11,
wantP05: 1, wantP20: 2, wantP50: 5, wantP95: 10, wantP99: 10,
wantMin: 1, wantMax: 10, wantMean: 5.5,
},
{
values: []int64{},
start: 1,
end: 101,
wantP05: 5, wantP20: 20, wantP50: 50, wantP95: 95, wantP99: 99,
wantMin: 1, wantMax: 100, wantMean: 50.5,
},
{
values: []int64{1},
start: 0,
end: 0,
wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 1, wantP99: 1,
wantMin: 1, wantMax: 1, wantMean: 1,
},
{
values: []int64{0},
start: 0,
end: 0,
wantP05: 0, wantP20: 0, wantP50: 0, wantP95: 0, wantP99: 0,
wantMin: 0, wantMax: 0, wantMean: 0,
},
{
values: []int64{},
start: 0,
end: 0,
wantP05: 0, wantP20: 0, wantP50: 0, wantP95: 0, wantP99: 0,
wantMin: 0, wantMax: 0, wantMean: 0,
},
{
values: []int64{1, 10},
start: 0,
end: 0,
wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 10, wantP99: 10,
wantMin: 1, wantMax: 10, wantMean: 5.5,
},
}
for ind, tt := range tests {
timer := NewResettingTimer()
for i := tt.start; i < tt.end; i++ {
tt.values = append(tt.values, int64(i))
}
for _, v := range tt.values {
timer.Update(time.Duration(v))
}
snap := timer.Snapshot()
ps := snap.Percentiles([]float64{5, 20, 50, 95, 99})
val := snap.Values()
if len(val) > 0 {
if tt.wantMin != val[0] {
t.Fatalf("%d: min: got %d, want %d", ind, val[0], tt.wantMin)
}
if tt.wantMax != val[len(val)-1] {
t.Fatalf("%d: max: got %d, want %d", ind, val[len(val)-1], tt.wantMax)
}
}
if tt.wantMean != snap.Mean() {
t.Fatalf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean)
}
if tt.wantP05 != ps[0] {
t.Fatalf("%d: p05: got %d, want %d", ind, ps[0], tt.wantP05)
}
if tt.wantP20 != ps[1] {
t.Fatalf("%d: p20: got %d, want %d", ind, ps[1], tt.wantP20)
}
if tt.wantP50 != ps[2] {
t.Fatalf("%d: p50: got %d, want %d", ind, ps[2], tt.wantP50)
}
if tt.wantP95 != ps[3] {
t.Fatalf("%d: p95: got %d, want %d", ind, ps[3], tt.wantP95)
}
if tt.wantP99 != ps[4] {
t.Fatalf("%d: p99: got %d, want %d", ind, ps[4], tt.wantP99)
}
}
}

View file

@ -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)
}
}

View file

@ -297,7 +297,6 @@ func (self *worker) update() {
func (self *worker) wait() {
for {
mustCommitNewWork := true
for result := range self.recv {
atomic.AddInt32(&self.atWork, -1)
@ -322,11 +321,6 @@ func (self *worker) wait() {
log.Error("Failed writing block to chain", "err", err)
continue
}
// check if canon block and write transactions
if stat == core.CanonStatTy {
// implicit by posting ChainHeadEvent
mustCommitNewWork = false
}
// Broadcast the block and announce chain insertion event
self.mux.Post(core.NewMinedBlockEvent{Block: block})
var (
@ -341,10 +335,6 @@ func (self *worker) wait() {
// Insert the block into the set of pending ones to wait for confirmations
self.unconfirmed.Insert(block.NumberU64(), block.Hash())
if mustCommitNewWork {
self.commitNewWork()
}
}
}
}
@ -370,7 +360,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
}
work := &Work{
config: self.config,
signer: types.NewEIP155Signer(self.config.ChainId),
signer: types.NewEIP155Signer(self.config.ChainID),
state: state,
ancestors: set.New(),
family: set.New(),

View file

@ -338,6 +338,21 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
},
}
case metrics.ResettingTimer:
t := metric.Snapshot()
ps := t.Percentiles([]float64{5, 20, 50, 80, 95})
root[name] = map[string]interface{}{
"Measurements": len(t.Values()),
"Mean": time.Duration(t.Mean()).String(),
"Percentiles": map[string]interface{}{
"5": time.Duration(ps[0]).String(),
"20": time.Duration(ps[1]).String(),
"50": time.Duration(ps[2]).String(),
"80": time.Duration(ps[3]).String(),
"95": time.Duration(ps[4]).String(),
},
}
default:
root[name] = "Unknown metric type"
}
@ -373,6 +388,21 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
},
}
case metrics.ResettingTimer:
t := metric.Snapshot()
ps := t.Percentiles([]float64{5, 20, 50, 80, 95})
root[name] = map[string]interface{}{
"Measurements": len(t.Values()),
"Mean": time.Duration(t.Mean()).String(),
"Percentiles": map[string]interface{}{
"5": time.Duration(ps[0]).String(),
"20": time.Duration(ps[1]).String(),
"50": time.Duration(ps[2]).String(),
"80": time.Duration(ps[3]).String(),
"95": time.Duration(ps[4]).String(),
},
}
default:
root[name] = "Unknown metric type"
}

View file

@ -59,7 +59,7 @@ using the same data directory will store this information in different subdirect
the data directory.
LevelDB databases are also stored within the instance subdirectory. If multiple node
instances use the same data directory, openening the databases with identical names will
instances use the same data directory, opening the databases with identical names will
create one database for each instance.
The account key store is shared among all node instances using the same data directory
@ -84,7 +84,7 @@ directory. Mode instance A opens the database "db", node instance B opens the da
static-nodes.json -- devp2p static node list of instance B
db/ -- LevelDB content for "db"
db-2/ -- LevelDB content for "db-2"
B.ipc -- JSON-RPC UNIX domain socket endpoint of instance A
B.ipc -- JSON-RPC UNIX domain socket endpoint of instance B
keystore/ -- account key store, used by both instances
*/
package node

View file

@ -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)
}
}

8
p2p/discv5/metrics.go Normal file
View file

@ -0,0 +1,8 @@
package discv5
import "github.com/ethereum/go-ethereum/metrics"
var (
ingressTrafficMeter = metrics.NewRegisteredMeter("discv5/InboundTraffic", nil)
egressTrafficMeter = metrics.NewRegisteredMeter("discv5/OutboundTraffic", nil)
)

View file

@ -334,8 +334,10 @@ func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req inter
return hash, err
}
log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr))
if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil {
if nbytes, err := t.conn.WriteToUDP(packet, toaddr); err != nil {
log.Trace(fmt.Sprint("UDP send failed:", err))
} else {
egressTrafficMeter.Mark(int64(nbytes))
}
//fmt.Println(err)
return hash, err
@ -374,6 +376,7 @@ func (t *udp) readLoop() {
buf := make([]byte, 1280)
for {
nbytes, from, err := t.conn.ReadFromUDP(buf)
ingressTrafficMeter.Mark(int64(nbytes))
if netutil.IsTemporaryError(err) {
// Ignore temporary read errors.
log.Debug(fmt.Sprintf("Temporary read error: %v", err))

View file

@ -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)

View file

@ -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"),

View file

@ -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
}

View file

@ -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
}

View file

@ -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)

View file

@ -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{

Some files were not shown because too many files have changed in this diff Show more