mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
Merge branch 'master' into ethGolint
This commit is contained in:
commit
2a9cc4ca96
167 changed files with 31844 additions and 1574 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.8.9
|
1.8.12
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,7 @@ func doLint(cmdline []string) {
|
||||||
configs := []string{
|
configs := []string{
|
||||||
"--vendor",
|
"--vendor",
|
||||||
"--tests",
|
"--tests",
|
||||||
|
"--deadline=2m",
|
||||||
"--disable-all",
|
"--disable-all",
|
||||||
"--enable=goimports",
|
"--enable=goimports",
|
||||||
"--enable=varcheck",
|
"--enable=varcheck",
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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)")
|
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)")
|
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
|
||||||
|
|
||||||
|
|
@ -75,17 +75,28 @@ func main() {
|
||||||
bins []string
|
bins []string
|
||||||
types []string
|
types []string
|
||||||
)
|
)
|
||||||
if *solFlag != "" {
|
if *solFlag != "" || *abiFlag == "-" {
|
||||||
// Generate the list of types to exclude from binding
|
// Generate the list of types to exclude from binding
|
||||||
exclude := make(map[string]bool)
|
exclude := make(map[string]bool)
|
||||||
for _, kind := range strings.Split(*excFlag, ",") {
|
for _, kind := range strings.Split(*excFlag, ",") {
|
||||||
exclude[strings.ToLower(kind)] = true
|
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 {
|
if err != nil {
|
||||||
fmt.Printf("Failed to build Solidity contract: %v\n", err)
|
fmt.Printf("Failed to build Solidity contract: %v\n", err)
|
||||||
os.Exit(-1)
|
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
|
// Gather all non-excluded contract for binding
|
||||||
for name, contract := range contracts {
|
for name, contract := range contracts {
|
||||||
if exclude[strings.ToLower(name)] {
|
if exclude[strings.ToLower(name)] {
|
||||||
|
|
@ -138,3 +149,12 @@ func main() {
|
||||||
os.Exit(-1)
|
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, "", "", "", "")
|
||||||
|
}
|
||||||
|
|
|
||||||
72
cmd/ethkey/changepassphrase.go
Normal file
72
cmd/ethkey/changepassphrase.go
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newPassphraseFlag = cli.StringFlag{
|
||||||
|
Name: "newpasswordfile",
|
||||||
|
Usage: "the file that contains the new passphrase for the keyfile",
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandChangePassphrase = cli.Command{
|
||||||
|
Name: "changepassphrase",
|
||||||
|
Usage: "change the passphrase on a keyfile",
|
||||||
|
ArgsUsage: "<keyfile>",
|
||||||
|
Description: `
|
||||||
|
Change the passphrase of a keyfile.`,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
passphraseFlag,
|
||||||
|
newPassphraseFlag,
|
||||||
|
},
|
||||||
|
Action: func(ctx *cli.Context) error {
|
||||||
|
keyfilepath := ctx.Args().First()
|
||||||
|
|
||||||
|
// Read key from file.
|
||||||
|
keyjson, err := ioutil.ReadFile(keyfilepath)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt key with passphrase.
|
||||||
|
passphrase := getPassphrase(ctx)
|
||||||
|
key, err := keystore.DecryptKey(keyjson, passphrase)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error decrypting key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a new passphrase.
|
||||||
|
fmt.Println("Please provide a new passphrase")
|
||||||
|
var newPhrase string
|
||||||
|
if passFile := ctx.String(newPassphraseFlag.Name); passFile != "" {
|
||||||
|
content, err := ioutil.ReadFile(passFile)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read new passphrase file '%s': %v", passFile, err)
|
||||||
|
}
|
||||||
|
newPhrase = strings.TrimRight(string(content), "\r\n")
|
||||||
|
} else {
|
||||||
|
newPhrase = promptPassphrase(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the key with the new passphrase.
|
||||||
|
newJson, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error encrypting with new passphrase: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then write the new keyfile in place of the old one.
|
||||||
|
if err := ioutil.WriteFile(keyfilepath, newJson, 600); err != nil {
|
||||||
|
utils.Fatalf("Error writing new keyfile to disk: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't print anything. Just return successfully,
|
||||||
|
// producing a positive exit code.
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -90,7 +90,7 @@ If you want to encrypt an existing private key, it can be specified by setting
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt key with passphrase.
|
// Encrypt key with passphrase.
|
||||||
passphrase := getPassPhrase(ctx, true)
|
passphrase := promptPassphrase(true)
|
||||||
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
|
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Error encrypting key: %v", err)
|
utils.Fatalf("Error encrypting key: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ make sure to use this feature with great caution!`,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt key with passphrase.
|
// Decrypt key with passphrase.
|
||||||
passphrase := getPassPhrase(ctx, false)
|
passphrase := getPassphrase(ctx)
|
||||||
key, err := keystore.DecryptKey(keyjson, passphrase)
|
key, err := keystore.DecryptKey(keyjson, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Error decrypting key: %v", err)
|
utils.Fatalf("Error decrypting key: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func init() {
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
commandGenerate,
|
commandGenerate,
|
||||||
commandInspect,
|
commandInspect,
|
||||||
|
commandChangePassphrase,
|
||||||
commandSignMessage,
|
commandSignMessage,
|
||||||
commandVerifyMessage,
|
commandVerifyMessage,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ To sign a message contained in a file, use the --msgfile flag.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt key with passphrase.
|
// Decrypt key with passphrase.
|
||||||
passphrase := getPassPhrase(ctx, false)
|
passphrase := getPassphrase(ctx)
|
||||||
key, err := keystore.DecryptKey(keyjson, passphrase)
|
key, err := keystore.DecryptKey(keyjson, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Error decrypting key: %v", err)
|
utils.Fatalf("Error decrypting key: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,32 @@ import (
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getPassPhrase obtains a passphrase given by the user. It first checks the
|
// promptPassphrase prompts the user for a passphrase. Set confirmation to true
|
||||||
// --passphrase command line flag and ultimately prompts the user for a
|
// 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.
|
// passphrase.
|
||||||
func getPassPhrase(ctx *cli.Context, confirmation bool) string {
|
func getPassphrase(ctx *cli.Context) string {
|
||||||
// Look for the --passphrase flag.
|
// Look for the --passwordfile flag.
|
||||||
passphraseFile := ctx.String(passphraseFlag.Name)
|
passphraseFile := ctx.String(passphraseFlag.Name)
|
||||||
if passphraseFile != "" {
|
if passphraseFile != "" {
|
||||||
content, err := ioutil.ReadFile(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.
|
// Otherwise prompt the user for the passphrase.
|
||||||
passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
|
return promptPassphrase(false)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// signHash is a helper function that calculates a hash for the given message
|
// signHash is a helper function that calculates a hash for the given message
|
||||||
|
|
|
||||||
|
|
@ -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))
|
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)
|
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 {
|
if err != nil {
|
||||||
f.lock.Unlock()
|
f.lock.Unlock()
|
||||||
if err = sendError(conn, err); err != nil {
|
if err = sendError(conn, err); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,16 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
godebug "runtime/debug"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/elastic/gosigar"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
|
@ -188,6 +192,22 @@ func init() {
|
||||||
if err := debug.Setup(ctx); err != nil {
|
if err := debug.Setup(ctx); err != nil {
|
||||||
return err
|
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
|
// Start system runtime metrics collection
|
||||||
go metrics.CollectProcessMetrics(3 * time.Second)
|
go metrics.CollectProcessMetrics(3 * time.Second)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,8 @@ func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEther
|
||||||
spec.Params.ByzantiumForkBlock = (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())
|
spec.Params.ByzantiumForkBlock = (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())
|
||||||
spec.Params.ConstantinopleForkBlock = (hexutil.Uint64)(math.MaxUint64)
|
spec.Params.ConstantinopleForkBlock = (hexutil.Uint64)(math.MaxUint64)
|
||||||
|
|
||||||
spec.Params.NetworkID = (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.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
|
||||||
|
|
||||||
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
|
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
|
||||||
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
|
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.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
|
||||||
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
|
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
|
||||||
spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
|
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.MaxCodeSize = params.MaxCodeSize
|
||||||
spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()
|
spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()
|
||||||
spec.Params.EIP98Transition = math.MaxUint64
|
spec.Params.EIP98Transition = math.MaxUint64
|
||||||
|
|
|
||||||
|
|
@ -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{}{
|
template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{
|
||||||
"Network": network,
|
"Network": network,
|
||||||
"NetworkID": conf.Genesis.Config.ChainId,
|
"NetworkID": conf.Genesis.Config.ChainID,
|
||||||
"NetworkTitle": strings.Title(network),
|
"NetworkTitle": strings.Title(network),
|
||||||
"EthstatsPage": config.ethstats,
|
"EthstatsPage": config.ethstats,
|
||||||
"ExplorerPage": config.explorer,
|
"ExplorerPage": config.explorer,
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ func (w *wizard) deployFaucet() {
|
||||||
existed := err == nil
|
existed := err == nil
|
||||||
|
|
||||||
infos.node.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ")
|
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
|
// Figure out which port to listen on
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ func (w *wizard) makeGenesis() {
|
||||||
// Query the user for some custom extras
|
// Query the user for some custom extras
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)")
|
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
|
// All done, store the genesis and flush to disk
|
||||||
log.Info("Configured new genesis block")
|
log.Info("Configured new genesis block")
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func (w *wizard) deployNode(boot bool) {
|
||||||
existed := err == nil
|
existed := err == nil
|
||||||
|
|
||||||
infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ")
|
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
|
// Figure out where the user wants to store the persistent data
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
@ -107,7 +107,7 @@ func (w *wizard) deployNode(boot bool) {
|
||||||
// Ethash based miners only need an etherbase to mine against
|
// Ethash based miners only need an etherbase to mine against
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
if infos.etherbase == "" {
|
if infos.etherbase == "" {
|
||||||
fmt.Printf("What address should the miner user?\n")
|
fmt.Printf("What address should the miner use?\n")
|
||||||
for {
|
for {
|
||||||
if address := w.readAddress(); address != nil {
|
if address := w.readAddress(); address != nil {
|
||||||
infos.etherbase = address.Hex()
|
infos.etherbase = address.Hex()
|
||||||
|
|
@ -115,7 +115,7 @@ func (w *wizard) deployNode(boot bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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()
|
infos.etherbase = w.readDefaultAddress(common.HexToAddress(infos.etherbase)).Hex()
|
||||||
}
|
}
|
||||||
} else if w.conf.Genesis.Config.Clique != nil {
|
} else if w.conf.Genesis.Config.Clique != nil {
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (w *wizard) deployWallet() {
|
||||||
existed := err == nil
|
existed := err == nil
|
||||||
|
|
||||||
infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ")
|
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
|
// Figure out which port to listen on
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
|
||||||
|
|
@ -1084,6 +1084,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
|
||||||
}
|
}
|
||||||
cfg.Genesis = core.DefaultRinkebyGenesisBlock()
|
cfg.Genesis = core.DefaultRinkebyGenesisBlock()
|
||||||
case ctx.GlobalBool(DeveloperFlag.Name):
|
case ctx.GlobalBool(DeveloperFlag.Name):
|
||||||
|
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
||||||
|
cfg.NetworkId = 1337
|
||||||
|
}
|
||||||
// Create new developer account or reuse existing one
|
// Create new developer account or reuse existing one
|
||||||
var (
|
var (
|
||||||
developer accounts.Account
|
developer accounts.Account
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,8 @@ func processArgs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *asymmetricMode && len(*argPub) > 0 {
|
if *asymmetricMode && len(*argPub) > 0 {
|
||||||
pub = crypto.ToECDSAPub(common.FromHex(*argPub))
|
var err error
|
||||||
if !isKeyValid(pub) {
|
if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil {
|
||||||
utils.Fatalf("invalid public key")
|
utils.Fatalf("invalid public key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -321,10 +321,6 @@ func startServer() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKeyValid(k *ecdsa.PublicKey) bool {
|
|
||||||
return k.X != nil && k.Y != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configureNode() {
|
func configureNode() {
|
||||||
var err error
|
var err error
|
||||||
var p2pAccept bool
|
var p2pAccept bool
|
||||||
|
|
@ -340,9 +336,8 @@ func configureNode() {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
utils.Fatalf("Error: can not convert hexadecimal string")
|
utils.Fatalf("Error: can not convert hexadecimal string")
|
||||||
}
|
}
|
||||||
pub = crypto.ToECDSAPub(b)
|
if pub, err = crypto.UnmarshalPubkey(b); err != nil {
|
||||||
if !isKeyValid(pub) {
|
utils.Fatalf("Error: invalid peer public key")
|
||||||
utils.Fatalf("Error: invalid public key")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,20 @@ package common
|
||||||
|
|
||||||
import "encoding/hex"
|
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 {
|
func ToHex(b []byte) string {
|
||||||
hex := Bytes2Hex(b)
|
hex := Bytes2Hex(b)
|
||||||
// Prefer output of "0x0" instead of "0x"
|
|
||||||
if len(hex) == 0 {
|
if len(hex) == 0 {
|
||||||
hex = "0"
|
hex = "0"
|
||||||
}
|
}
|
||||||
return "0x" + hex
|
return "0x" + hex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromHex returns the bytes represented by the hexadecimal string s.
|
||||||
|
// s may be prefixed with "0x".
|
||||||
func FromHex(s string) []byte {
|
func FromHex(s string) []byte {
|
||||||
if len(s) > 1 {
|
if len(s) > 1 {
|
||||||
if s[0:2] == "0x" || s[0:2] == "0X" {
|
if s[0:2] == "0x" || s[0:2] == "0X" {
|
||||||
|
|
@ -40,9 +45,7 @@ func FromHex(s string) []byte {
|
||||||
return Hex2Bytes(s)
|
return Hex2Bytes(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy bytes
|
// CopyBytes returns an exact copy of the provided bytes.
|
||||||
//
|
|
||||||
// Returns an exact copy of the provided bytes
|
|
||||||
func CopyBytes(b []byte) (copiedBytes []byte) {
|
func CopyBytes(b []byte) (copiedBytes []byte) {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -53,14 +56,17 @@ func CopyBytes(b []byte) (copiedBytes []byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasHexPrefix validates str begins with '0x' or '0X'.
|
||||||
func hasHexPrefix(str string) bool {
|
func hasHexPrefix(str string) bool {
|
||||||
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
|
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 {
|
func isHexCharacter(c byte) bool {
|
||||||
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
|
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 {
|
func isHex(str string) bool {
|
||||||
if len(str)%2 != 0 {
|
if len(str)%2 != 0 {
|
||||||
return false
|
return false
|
||||||
|
|
@ -73,16 +79,18 @@ func isHex(str string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bytes2Hex returns the hexadecimal encoding of d.
|
||||||
func Bytes2Hex(d []byte) string {
|
func Bytes2Hex(d []byte) string {
|
||||||
return hex.EncodeToString(d)
|
return hex.EncodeToString(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hex2Bytes returns the bytes represented by the hexadecimal string str.
|
||||||
func Hex2Bytes(str string) []byte {
|
func Hex2Bytes(str string) []byte {
|
||||||
h, _ := hex.DecodeString(str)
|
h, _ := hex.DecodeString(str)
|
||||||
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hex2BytesFixed returns bytes of a specified fixed length flen.
|
||||||
func Hex2BytesFixed(str string, flen int) []byte {
|
func Hex2BytesFixed(str string, flen int) []byte {
|
||||||
h, _ := hex.DecodeString(str)
|
h, _ := hex.DecodeString(str)
|
||||||
if len(h) == flen {
|
if len(h) == flen {
|
||||||
|
|
@ -96,6 +104,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
|
||||||
return hh
|
return hh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RightPadBytes zero-pads slice to the right up to length l.
|
||||||
func RightPadBytes(slice []byte, l int) []byte {
|
func RightPadBytes(slice []byte, l int) []byte {
|
||||||
if l <= len(slice) {
|
if l <= len(slice) {
|
||||||
return slice
|
return slice
|
||||||
|
|
@ -107,6 +116,7 @@ func RightPadBytes(slice []byte, l int) []byte {
|
||||||
return padded
|
return padded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LeftPadBytes zero-pads slice to the left up to length l.
|
||||||
func LeftPadBytes(slice []byte, l int) []byte {
|
func LeftPadBytes(slice []byte, l int) []byte {
|
||||||
if l <= len(slice) {
|
if l <= len(slice) {
|
||||||
return slice
|
return slice
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,17 @@ import (
|
||||||
|
|
||||||
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
|
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
|
||||||
|
|
||||||
|
// Contract contains information about a compiled contract, alongside its code.
|
||||||
type Contract struct {
|
type Contract struct {
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Info ContractInfo `json:"info"`
|
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 {
|
type ContractInfo struct {
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
Language string `json:"language"`
|
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 {
|
if err := cmd.Run(); err != nil {
|
||||||
return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
|
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
|
var output solcOutput
|
||||||
if err := json.Unmarshal(stdout.Bytes(), &output); err != nil {
|
if err := json.Unmarshal(combinedJSON, &output); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,9 +188,9 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
|
||||||
Info: ContractInfo{
|
Info: ContractInfo{
|
||||||
Source: source,
|
Source: source,
|
||||||
Language: "Solidity",
|
Language: "Solidity",
|
||||||
LanguageVersion: s.Version,
|
LanguageVersion: languageVersion,
|
||||||
CompilerVersion: s.Version,
|
CompilerVersion: compilerVersion,
|
||||||
CompilerOptions: strings.Join(s.makeArgs(), " "),
|
CompilerOptions: compilerOptions,
|
||||||
AbiDefinition: abi,
|
AbiDefinition: abi,
|
||||||
UserDoc: userdoc,
|
UserDoc: userdoc,
|
||||||
DeveloperDoc: devdoc,
|
DeveloperDoc: devdoc,
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ func ParseBig256(s string) (*big.Int, bool) {
|
||||||
return bigint, ok
|
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 {
|
func MustParseBig256(s string) *big.Int {
|
||||||
v, ok := ParseBig256(s)
|
v, ok := ParseBig256(s)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -186,9 +186,8 @@ func U256(x *big.Int) *big.Int {
|
||||||
func S256(x *big.Int) *big.Int {
|
func S256(x *big.Int) *big.Int {
|
||||||
if x.Cmp(tt255) < 0 {
|
if x.Cmp(tt255) < 0 {
|
||||||
return x
|
return x
|
||||||
} else {
|
|
||||||
return new(big.Int).Sub(x, tt256)
|
|
||||||
}
|
}
|
||||||
|
return new(big.Int).Sub(x, tt256)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exp implements exponentiation by squaring.
|
// Exp implements exponentiation by squaring.
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,12 @@ func limitUnsigned256(x *Number) *Number {
|
||||||
func limitSigned256(x *Number) *Number {
|
func limitSigned256(x *Number) *Number {
|
||||||
if x.num.Cmp(tt255) < 0 {
|
if x.num.Cmp(tt255) < 0 {
|
||||||
return x
|
return x
|
||||||
} else {
|
}
|
||||||
x.num.Sub(x.num, tt256)
|
x.num.Sub(x.num, tt256)
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Number function
|
// Initialiser is a Number function
|
||||||
type Initialiser func(n int64) *Number
|
type Initialiser func(n int64) *Number
|
||||||
|
|
||||||
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
|
// 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
|
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 {
|
func NewInitialiser(limiter func(*Number) *Number) Initialiser {
|
||||||
return func(n int64) *Number {
|
return func(n int64) *Number {
|
||||||
return &Number{big.NewInt(n), limiter}
|
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 {
|
func Uint256(n int64) *Number {
|
||||||
return &Number{big.NewInt(n), limitUnsigned256}
|
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 {
|
func Int256(n int64) *Number {
|
||||||
return &Number{big.NewInt(n), limitSigned256}
|
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 {
|
func Big(n int64) *Number {
|
||||||
return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
|
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 {
|
func (i *Number) Add(x, y *Number) *Number {
|
||||||
i.num.Add(x.num, y.num)
|
i.num.Add(x.num, y.num)
|
||||||
return i.limit(i)
|
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 {
|
func (i *Number) Sub(x, y *Number) *Number {
|
||||||
i.num.Sub(x.num, y.num)
|
i.num.Sub(x.num, y.num)
|
||||||
return i.limit(i)
|
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 {
|
func (i *Number) Mul(x, y *Number) *Number {
|
||||||
i.num.Mul(x.num, y.num)
|
i.num.Mul(x.num, y.num)
|
||||||
return i.limit(i)
|
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 {
|
func (i *Number) Div(x, y *Number) *Number {
|
||||||
i.num.Div(x.num, y.num)
|
i.num.Div(x.num, y.num)
|
||||||
return i.limit(i)
|
return i.limit(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets i to x % y
|
// Mod sets i to x % y
|
||||||
func (i *Number) Mod(x, y *Number) *Number {
|
func (i *Number) Mod(x, y *Number) *Number {
|
||||||
i.num.Mod(x.num, y.num)
|
i.num.Mod(x.num, y.num)
|
||||||
return i.limit(i)
|
return i.limit(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets i to x << s
|
// Lsh sets i to x << s
|
||||||
func (i *Number) Lsh(x *Number, s uint) *Number {
|
func (i *Number) Lsh(x *Number, s uint) *Number {
|
||||||
i.num.Lsh(x.num, s)
|
i.num.Lsh(x.num, s)
|
||||||
return i.limit(i)
|
return i.limit(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets i to x^y
|
// Pow sets i to x^y
|
||||||
func (i *Number) Pow(x, y *Number) *Number {
|
func (i *Number) Pow(x, y *Number) *Number {
|
||||||
i.num.Exp(x.num, y.num, big.NewInt(0))
|
i.num.Exp(x.num, y.num, big.NewInt(0))
|
||||||
return i.limit(i)
|
return i.limit(i)
|
||||||
|
|
@ -117,13 +116,13 @@ func (i *Number) Pow(x, y *Number) *Number {
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
||||||
// Set x to i
|
// Set sets x to i
|
||||||
func (i *Number) Set(x *Number) *Number {
|
func (i *Number) Set(x *Number) *Number {
|
||||||
i.num.Set(x.num)
|
i.num.Set(x.num)
|
||||||
return i.limit(i)
|
return i.limit(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set x bytes to i
|
// SetBytes sets x bytes to i
|
||||||
func (i *Number) SetBytes(x []byte) *Number {
|
func (i *Number) SetBytes(x []byte) *Number {
|
||||||
i.num.SetBytes(x)
|
i.num.SetBytes(x)
|
||||||
return i.limit(i)
|
return i.limit(i)
|
||||||
|
|
@ -140,12 +139,12 @@ func (i *Number) Cmp(x *Number) int {
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
// Returns the string representation of i
|
// String returns the string representation of i
|
||||||
func (i *Number) String() string {
|
func (i *Number) String() string {
|
||||||
return i.num.String()
|
return i.num.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the byte representation of i
|
// Bytes returns the byte representation of i
|
||||||
func (i *Number) Bytes() []byte {
|
func (i *Number) Bytes() []byte {
|
||||||
return i.num.Bytes()
|
return i.num.Bytes()
|
||||||
}
|
}
|
||||||
|
|
@ -160,17 +159,17 @@ func (i *Number) Int64() int64 {
|
||||||
return i.num.Int64()
|
return i.num.Int64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the signed version of i
|
// Int256 returns the signed version of i
|
||||||
func (i *Number) Int256() *Number {
|
func (i *Number) Int256() *Number {
|
||||||
return Int(0).Set(i)
|
return Int(0).Set(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the unsigned version of i
|
// Uint256 returns the unsigned version of i
|
||||||
func (i *Number) Uint256() *Number {
|
func (i *Number) Uint256() *Number {
|
||||||
return Uint(0).Set(i)
|
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 {
|
func (i *Number) FirstBitSet() int {
|
||||||
for j := 0; j < i.num.BitLen(); j++ {
|
for j := 0; j < i.num.BitLen(); j++ {
|
||||||
if i.num.Bit(j) > 0 {
|
if i.num.Bit(j) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ func MakeName(name, version string) string {
|
||||||
return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
|
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 {
|
func FileExist(filePath string) bool {
|
||||||
_, err := os.Stat(filePath)
|
_, err := os.Stat(filePath)
|
||||||
if err != nil && os.IsNotExist(err) {
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
|
@ -39,9 +40,10 @@ func FileExist(filePath string) bool {
|
||||||
return true
|
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) {
|
if filepath.IsAbs(filename) {
|
||||||
return filename
|
return filename
|
||||||
}
|
}
|
||||||
return filepath.Join(Datadir, filename)
|
return filepath.Join(datadir, filename)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,18 +42,29 @@ var (
|
||||||
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||||
type Hash [HashLength]byte
|
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 {
|
func BytesToHash(b []byte) Hash {
|
||||||
var h Hash
|
var h Hash
|
||||||
h.SetBytes(b)
|
h.SetBytes(b)
|
||||||
return h
|
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()) }
|
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)) }
|
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||||
|
|
||||||
// Get the string representation of the underlying hash
|
// Bytes gets the byte representation of the underlying hash.
|
||||||
func (h Hash) Str() string { return string(h[:]) }
|
|
||||||
func (h Hash) Bytes() []byte { return h[:] }
|
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[:]) }
|
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[:]) }
|
func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
|
||||||
|
|
||||||
// TerminalString implements log.TerminalStringer, formatting a string for console
|
// TerminalString implements log.TerminalStringer, formatting a string for console
|
||||||
|
|
@ -89,7 +100,8 @@ func (h Hash) MarshalText() ([]byte, error) {
|
||||||
return hexutil.Bytes(h[:]).MarshalText()
|
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) {
|
func (h *Hash) SetBytes(b []byte) {
|
||||||
if len(b) > len(h) {
|
if len(b) > len(h) {
|
||||||
b = b[len(b)-HashLength:]
|
b = b[len(b)-HashLength:]
|
||||||
|
|
@ -98,16 +110,6 @@ func (h *Hash) SetBytes(b []byte) {
|
||||||
copy(h[HashLength-len(b):], b)
|
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.
|
// Generate implements testing/quick.Generator.
|
||||||
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||||
m := rand.Intn(len(h))
|
m := rand.Intn(len(h))
|
||||||
|
|
@ -117,10 +119,6 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||||
return reflect.ValueOf(h)
|
return reflect.ValueOf(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EmptyHash(h Hash) bool {
|
|
||||||
return h == Hash{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnprefixedHash allows marshaling a Hash without 0x prefix.
|
// UnprefixedHash allows marshaling a Hash without 0x prefix.
|
||||||
type UnprefixedHash Hash
|
type UnprefixedHash Hash
|
||||||
|
|
||||||
|
|
@ -139,12 +137,20 @@ func (h UnprefixedHash) MarshalText() ([]byte, error) {
|
||||||
// Address represents the 20 byte address of an Ethereum account.
|
// Address represents the 20 byte address of an Ethereum account.
|
||||||
type Address [AddressLength]byte
|
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 {
|
func BytesToAddress(b []byte) Address {
|
||||||
var a Address
|
var a Address
|
||||||
a.SetBytes(b)
|
a.SetBytes(b)
|
||||||
return a
|
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()) }
|
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)) }
|
func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
|
||||||
|
|
||||||
// IsHexAddress verifies whether a string can represent a valid hex-encoded
|
// 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)
|
return len(s) == 2*AddressLength && isHex(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the string representation of the underlying address
|
// Bytes gets the string representation of the underlying address.
|
||||||
func (a Address) Str() string { return string(a[:]) }
|
|
||||||
func (a Address) Bytes() []byte { return a[:] }
|
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[:]) }
|
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[:]) }
|
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
|
||||||
|
|
||||||
// Hex returns an EIP55-compliant hex string representation of the address.
|
// Hex returns an EIP55-compliant hex string representation of the address.
|
||||||
|
|
@ -184,7 +193,7 @@ func (a Address) Hex() string {
|
||||||
return "0x" + string(result)
|
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 {
|
func (a Address) String() string {
|
||||||
return a.Hex()
|
return a.Hex()
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +204,8 @@ func (a Address) Format(s fmt.State, c rune) {
|
||||||
fmt.Fprintf(s, "%"+string(c), a[:])
|
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) {
|
func (a *Address) SetBytes(b []byte) {
|
||||||
if len(b) > len(a) {
|
if len(b) > len(a) {
|
||||||
b = b[len(b)-AddressLength:]
|
b = b[len(b)-AddressLength:]
|
||||||
|
|
@ -203,16 +213,6 @@ func (a *Address) SetBytes(b []byte) {
|
||||||
copy(a[AddressLength-len(b):], b)
|
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.
|
// MarshalText returns the hex representation of a.
|
||||||
func (a Address) MarshalText() ([]byte, error) {
|
func (a Address) MarshalText() ([]byte, error) {
|
||||||
return hexutil.Bytes(a[:]).MarshalText()
|
return hexutil.Bytes(a[:]).MarshalText()
|
||||||
|
|
@ -228,7 +228,7 @@ func (a *Address) UnmarshalJSON(input []byte) error {
|
||||||
return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
|
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
|
type UnprefixedAddress Address
|
||||||
|
|
||||||
// UnmarshalText decodes the address from hex. The 0x prefix is optional.
|
// UnmarshalText decodes the address from hex. The 0x prefix is optional.
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -94,14 +94,25 @@ func calcDatasetSize(epoch int) uint64 {
|
||||||
// reused between hash runs instead of requiring new ones to be created.
|
// reused between hash runs instead of requiring new ones to be created.
|
||||||
type hasher func(dest []byte, data []byte)
|
type hasher func(dest []byte, data []byte)
|
||||||
|
|
||||||
// makeHasher creates a repetitive hasher, allowing the same hash data structures
|
// makeHasher creates a repetitive hasher, allowing the same hash data structures to
|
||||||
// to be reused between hash runs instead of requiring new ones to be created.
|
// be reused between hash runs instead of requiring new ones to be created. The returned
|
||||||
// The returned function is not thread safe!
|
// function is not thread safe!
|
||||||
func makeHasher(h hash.Hash) hasher {
|
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) {
|
return func(dest []byte, data []byte) {
|
||||||
h.Write(data)
|
rh.Reset()
|
||||||
h.Sum(dest[:0])
|
rh.Write(data)
|
||||||
h.Reset()
|
rh.Read(dest[:outputLen])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ func (b *bridge) SleepBlocks(call otto.FunctionCall) (response otto.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonrpcCall struct {
|
type jsonrpcCall struct {
|
||||||
Id int64
|
ID int64
|
||||||
Method string
|
Method string
|
||||||
Params []interface{}
|
Params []interface{}
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +304,7 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
|
||||||
resps, _ := call.Otto.Object("new Array()")
|
resps, _ := call.Otto.Object("new Array()")
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`)
|
resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`)
|
||||||
resp.Set("id", req.Id)
|
resp.Set("id", req.ID)
|
||||||
var result json.RawMessage
|
var result json.RawMessage
|
||||||
err = b.client.Call(&result, req.Method, req.Params...)
|
err = b.client.Call(&result, req.Method, req.Params...)
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ type Config struct {
|
||||||
Preload []string // Absolute paths to JavaScript files to preload
|
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
|
// JavaScript console attached to a running node via an external or in-process RPC
|
||||||
// client.
|
// client.
|
||||||
type Console struct {
|
type Console struct {
|
||||||
|
|
@ -73,6 +73,8 @@ type Console struct {
|
||||||
printer io.Writer // Output writer to serialize any display strings to
|
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) {
|
func New(config Config) (*Console, error) {
|
||||||
// Handle unset config values gracefully
|
// Handle unset config values gracefully
|
||||||
if config.Prompter == nil {
|
if config.Prompter == nil {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
parentNode, parentLabel := ensParentNode(name)
|
||||||
return crypto.Keccak256Hash(parentNode[:], parentLabel[:])
|
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.
|
// Resolve is a non-transactional call that returns the content hash associated with a name.
|
||||||
func (self *ENS) Resolve(name string) (common.Hash, error) {
|
func (self *ENS) Resolve(name string) (common.Hash, error) {
|
||||||
node := ensNode(name)
|
node := EnsNode(name)
|
||||||
|
|
||||||
resolver, err := self.getResolver(node)
|
resolver, err := self.getResolver(node)
|
||||||
if err != nil {
|
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
|
// 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.
|
// owns the name, and the associated resolver implements a `setContent` function.
|
||||||
func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
|
func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
|
||||||
node := ensNode(name)
|
node := EnsNode(name)
|
||||||
|
|
||||||
resolver, err := self.getResolver(node)
|
resolver, err := self.getResolver(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ func TestENS(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("can't deploy resolver: %v", err)
|
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)
|
t.Fatalf("can't set resolver: %v", err)
|
||||||
}
|
}
|
||||||
contractBackend.Commit()
|
contractBackend.Commit()
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ func lexLabel(l *lexer) stateFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
// lexInsideString lexes the inside of a string until
|
// 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.
|
// It returns the lex text state function.
|
||||||
func lexInsideString(l *lexer) stateFn {
|
func lexInsideString(l *lexer) stateFn {
|
||||||
if l.acceptRunUntil('"') {
|
if l.acceptRunUntil('"') {
|
||||||
|
|
|
||||||
|
|
@ -674,7 +674,7 @@ func (bc *BlockChain) Stop() {
|
||||||
for !bc.triegc.Empty() {
|
for !bc.triegc.Empty() {
|
||||||
triedb.Dereference(bc.triegc.PopItem().(common.Hash), common.Hash{})
|
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")
|
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()))
|
bc.triegc.Push(root, -float32(block.NumberU64()))
|
||||||
|
|
||||||
if current := block.NumberU64(); current > triesInMemory {
|
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
|
// Find the next state trie we need to commit
|
||||||
header := bc.GetHeaderByNumber(current - triesInMemory)
|
header := bc.GetHeaderByNumber(current - triesInMemory)
|
||||||
chosen := header.Number.Uint64()
|
chosen := header.Number.Uint64()
|
||||||
|
|
||||||
// Only write to disk if we exceeded our memory allowance *and* also have at
|
// If we exceeded out time allowance, flush an entire trie to disk
|
||||||
// least a given number of tries gapped.
|
if bc.gcproc > bc.cacheConfig.TrieTimeLimit {
|
||||||
var (
|
|
||||||
size = triedb.Size()
|
|
||||||
limit = common.StorageSize(bc.cacheConfig.TrieNodeLimit) * 1024 * 1024
|
|
||||||
)
|
|
||||||
if size > limit || bc.gcproc > bc.cacheConfig.TrieTimeLimit {
|
|
||||||
// If we're exceeding limits but haven't reached a large enough memory gap,
|
// If we're exceeding limits but haven't reached a large enough memory gap,
|
||||||
// warn the user that the system is becoming unstable.
|
// warn the user that the system is becoming unstable.
|
||||||
if chosen < lastWrite+triesInMemory {
|
if chosen < lastWrite+triesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit {
|
||||||
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:
|
|
||||||
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory)
|
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory)
|
||||||
}
|
}
|
||||||
}
|
// Flush an entire trie and restart the counters
|
||||||
// If optimum or critical limits reached, write to disk
|
|
||||||
if chosen >= lastWrite+triesInMemory || size >= 2*limit || bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit {
|
|
||||||
triedb.Commit(header.Root, true)
|
triedb.Commit(header.Root, true)
|
||||||
lastWrite = chosen
|
lastWrite = chosen
|
||||||
bc.gcproc = 0
|
bc.gcproc = 0
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Garbage collect anything below our required write retention
|
// Garbage collect anything below our required write retention
|
||||||
for !bc.triegc.Empty() {
|
for !bc.triegc.Empty() {
|
||||||
root, number := bc.triegc.Pop()
|
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
|
// only reason this method exists as a separate one is to make locking cleaner
|
||||||
// with deferred statements.
|
// with deferred statements.
|
||||||
func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*types.Log, error) {
|
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
|
// Do a sanity check that the provided chain is actually ordered and linked
|
||||||
for i := 1; i < len(chain); i++ {
|
for i := 1; i < len(chain); i++ {
|
||||||
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
|
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)
|
abort, results := bc.engine.VerifyHeaders(bc, headers, seals)
|
||||||
defer close(abort)
|
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
|
// Iterate over the blocks and insert when the verifier permits
|
||||||
for i, block := range chain {
|
for i, block := range chain {
|
||||||
// If the chain is terminating, stop processing blocks
|
// 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.processed++
|
||||||
stats.usedGas += usedGas
|
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
|
// Append a single chain head event if we've progressed the chain
|
||||||
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
|
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
|
// BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
||||||
func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) {
|
func (bc *BlockChain) BadBlocks() []*types.Block {
|
||||||
headers := make([]BadBlockArgs, 0, bc.badBlocks.Len())
|
blocks := make([]*types.Block, 0, bc.badBlocks.Len())
|
||||||
for _, hash := range bc.badBlocks.Keys() {
|
for _, hash := range bc.badBlocks.Keys() {
|
||||||
if hdr, exist := bc.badBlocks.Peek(hash); exist {
|
if blk, exist := bc.badBlocks.Peek(hash); exist {
|
||||||
header := hdr.(*types.Header)
|
block := blk.(*types.Block)
|
||||||
headers = append(headers, BadBlockArgs{header.Hash(), header})
|
blocks = append(blocks, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return headers, nil
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
// addBadBlock adds a bad block to the bad-block LRU cache
|
// addBadBlock adds a bad block to the bad-block LRU cache
|
||||||
func (bc *BlockChain) addBadBlock(block *types.Block) {
|
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.
|
// 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)
|
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,
|
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||||
// caching it (associated with its hash) if found.
|
// caching it (associated with its hash) if found.
|
||||||
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||||
|
|
|
||||||
|
|
@ -578,7 +578,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
Alloc: GenesisAlloc{address: {Balance: funds}},
|
Alloc: GenesisAlloc{address: {Balance: funds}},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(gendb)
|
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) {
|
blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
|
||||||
block.SetCoinbase(common.Address{0x00})
|
block.SetCoinbase(common.Address{0x00})
|
||||||
|
|
@ -753,7 +753,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create two transactions shared between the chains:
|
// Create two transactions shared between the chains:
|
||||||
|
|
@ -859,7 +859,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
||||||
genesis = gspec.MustCommit(db)
|
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{})
|
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)}},
|
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
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{})
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
||||||
|
|
@ -1032,7 +1032,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
deleteAddr = common.Address{1}
|
deleteAddr = common.Address{1}
|
||||||
gspec = &Genesis{
|
gspec = &Genesis{
|
||||||
Config: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
|
Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
|
||||||
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
|
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
|
|
@ -1063,7 +1063,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
||||||
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
|
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1075,7 +1075,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
||||||
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
|
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1103,7 +1103,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate an invalid chain id transaction
|
// generate an invalid chain id transaction
|
||||||
config := ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
config := ¶ms.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) {
|
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
|
|
@ -1137,7 +1137,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
theAddr = common.Address{1}
|
theAddr = common.Address{1}
|
||||||
gspec = &Genesis{
|
gspec = &Genesis{
|
||||||
Config: ¶ms.ChainConfig{
|
Config: ¶ms.ChainConfig{
|
||||||
ChainId: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
HomesteadBlock: new(big.Int),
|
HomesteadBlock: new(big.Int),
|
||||||
EIP155Block: new(big.Int),
|
EIP155Block: new(big.Int),
|
||||||
EIP158Block: big.NewInt(2),
|
EIP158Block: big.NewInt(2),
|
||||||
|
|
@ -1153,7 +1153,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
)
|
)
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,43 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
|
||||||
return chain
|
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
|
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||||
// database by hash and number, caching it if found.
|
// database by hash and number, caching it if found.
|
||||||
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
|
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
|
||||||
func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
|
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 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
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.
|
// WriteCanonicalHash stores the hash assigned to a canonical block number.
|
||||||
func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
|
func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
|
||||||
key := append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
|
if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {
|
||||||
if err := db.Put(key, hash.Bytes()); err != nil {
|
|
||||||
log.Crit("Failed to store number to hash mapping", "err", err)
|
log.Crit("Failed to store number to hash mapping", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCanonicalHash removes the number to hash canonical mapping.
|
// DeleteCanonicalHash removes the number to hash canonical mapping.
|
||||||
func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
|
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)
|
log.Crit("Failed to delete number to hash mapping", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadHeaderNumber returns the header number assigned to a hash.
|
// ReadHeaderNumber returns the header number assigned to a hash.
|
||||||
func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
|
func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
|
||||||
data, _ := db.Get(append(headerNumberPrefix, hash.Bytes()...))
|
data, _ := db.Get(headerNumberKey(hash))
|
||||||
if len(data) != 8 {
|
if len(data) != 8 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -129,14 +128,13 @@ func WriteFastTrieProgress(db DatabaseWriter, count uint64) {
|
||||||
|
|
||||||
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
|
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
|
||||||
func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasHeader verifies the existence of a block header corresponding to the hash.
|
// HasHeader verifies the existence of a block header corresponding to the hash.
|
||||||
func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
|
func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
|
||||||
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
if has, err := db.Has(headerKey(number, hash)); !has || err != nil {
|
||||||
if has, err := db.Has(key); !has || err != nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -161,11 +159,11 @@ func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Heade
|
||||||
func WriteHeader(db DatabaseWriter, header *types.Header) {
|
func WriteHeader(db DatabaseWriter, header *types.Header) {
|
||||||
// Write the hash -> number mapping
|
// Write the hash -> number mapping
|
||||||
var (
|
var (
|
||||||
hash = header.Hash().Bytes()
|
hash = header.Hash()
|
||||||
number = header.Number.Uint64()
|
number = header.Number.Uint64()
|
||||||
encoded = encodeBlockNumber(number)
|
encoded = encodeBlockNumber(number)
|
||||||
)
|
)
|
||||||
key := append(headerNumberPrefix, hash...)
|
key := headerNumberKey(hash)
|
||||||
if err := db.Put(key, encoded); err != nil {
|
if err := db.Put(key, encoded); err != nil {
|
||||||
log.Crit("Failed to store hash to number mapping", "err", err)
|
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 {
|
if err != nil {
|
||||||
log.Crit("Failed to RLP encode header", "err", err)
|
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 {
|
if err := db.Put(key, data); err != nil {
|
||||||
log.Crit("Failed to store header", "err", err)
|
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.
|
// DeleteHeader removes all block header data associated with a hash.
|
||||||
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
|
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)
|
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)
|
log.Crit("Failed to delete hash to number mapping", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
|
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
|
||||||
func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBodyRLP stores an RLP encoded block body into the database.
|
// WriteBodyRLP stores an RLP encoded block body into the database.
|
||||||
func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
|
func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
|
||||||
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
if err := db.Put(blockBodyKey(number, hash), rlp); err != nil {
|
||||||
if err := db.Put(key, rlp); err != nil {
|
|
||||||
log.Crit("Failed to store block body", "err", err)
|
log.Crit("Failed to store block body", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasBody verifies the existence of a block body corresponding to the hash.
|
// HasBody verifies the existence of a block body corresponding to the hash.
|
||||||
func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
|
func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
|
||||||
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil {
|
||||||
if has, err := db.Has(key); !has || err != nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
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.
|
// DeleteBody removes all block body data associated with a hash.
|
||||||
func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
|
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)
|
log.Crit("Failed to delete block body", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadTd retrieves a block's total difficulty corresponding to the hash.
|
// ReadTd retrieves a block's total difficulty corresponding to the hash.
|
||||||
func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
|
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 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -263,15 +259,14 @@ func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to RLP encode block total difficulty", "err", err)
|
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(headerTDKey(number, hash), data); err != nil {
|
||||||
if err := db.Put(key, data); err != nil {
|
|
||||||
log.Crit("Failed to store block total difficulty", "err", err)
|
log.Crit("Failed to store block total difficulty", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTd removes all block total difficulty data associated with a hash.
|
// DeleteTd removes all block total difficulty data associated with a hash.
|
||||||
func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
|
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)
|
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.
|
// ReadReceipts retrieves all the transaction receipts belonging to a block.
|
||||||
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
|
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
|
||||||
// Retrieve the flattened receipt slice
|
// Retrieve the flattened receipt slice
|
||||||
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...))
|
data, _ := db.Get(blockReceiptsKey(number, hash))
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
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)
|
log.Crit("Failed to encode block receipts", "err", err)
|
||||||
}
|
}
|
||||||
// Store the flattened receipt slice
|
// Store the flattened receipt slice
|
||||||
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
if err := db.Put(blockReceiptsKey(number, hash), bytes); err != nil {
|
||||||
if err := db.Put(key, bytes); err != nil {
|
|
||||||
log.Crit("Failed to store block receipts", "err", err)
|
log.Crit("Failed to store block receipts", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteReceipts removes all receipt data associated with a block hash.
|
// DeleteReceipts removes all receipt data associated with a block hash.
|
||||||
func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
|
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)
|
log.Crit("Failed to delete block receipts", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
package rawdb
|
package rawdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -28,7 +26,7 @@ import (
|
||||||
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
|
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
|
||||||
// hash to allow retrieving the transaction or receipt by hash.
|
// hash to allow retrieving the transaction or receipt by hash.
|
||||||
func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
|
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 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}, 0, 0
|
return common.Hash{}, 0, 0
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +51,7 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to encode transaction lookup entry", "err", err)
|
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)
|
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.
|
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
||||||
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.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
|
// 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
|
// ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
|
||||||
// section and bit index from the.
|
// section and bit index from the.
|
||||||
func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
|
func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
|
||||||
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
|
return db.Get(bloomBitsKey(bit, section, head))
|
||||||
|
|
||||||
binary.BigEndian.PutUint16(key[1:], uint16(bit))
|
|
||||||
binary.BigEndian.PutUint64(key[3:], section)
|
|
||||||
|
|
||||||
return db.Get(key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
|
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
|
||||||
// section and bit index.
|
// section and bit index.
|
||||||
func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) {
|
func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) {
|
||||||
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
|
if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
|
||||||
|
|
||||||
binary.BigEndian.PutUint16(key[1:], uint16(bit))
|
|
||||||
binary.BigEndian.PutUint64(key[3:], section)
|
|
||||||
|
|
||||||
if err := db.Put(key, bits); err != nil {
|
|
||||||
log.Crit("Failed to store bloom bits", "err", err)
|
log.Crit("Failed to store bloom bits", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func WriteDatabaseVersion(db DatabaseWriter, version int) {
|
||||||
|
|
||||||
// ReadChainConfig retrieves the consensus settings based on the given genesis hash.
|
// ReadChainConfig retrieves the consensus settings based on the given genesis hash.
|
||||||
func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
|
func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
|
||||||
data, _ := db.Get(append(configPrefix, hash[:]...))
|
data, _ := db.Get(configKey(hash))
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -66,14 +66,14 @@ func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConf
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to JSON encode chain config", "err", err)
|
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)
|
log.Crit("Failed to store chain config", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadPreimage retrieves a single preimage of the provided hash.
|
// ReadPreimage retrieves a single preimage of the provided hash.
|
||||||
func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
|
func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
|
||||||
data, _ := db.Get(append(preimagePrefix, hash.Bytes()...))
|
data, _ := db.Get(preimageKey(hash))
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
|
||||||
// current block number, and is used for debug messages only.
|
// current block number, and is used for debug messages only.
|
||||||
func WritePreimages(db DatabaseWriter, number uint64, preimages map[common.Hash][]byte) {
|
func WritePreimages(db DatabaseWriter, number uint64, preimages map[common.Hash][]byte) {
|
||||||
for hash, preimage := range preimages {
|
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)
|
log.Crit("Failed to store trie preimage", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,3 +77,58 @@ func encodeBlockNumber(number uint64) []byte {
|
||||||
binary.BigEndian.PutUint64(enc, number)
|
binary.BigEndian.PutUint64(enc, number)
|
||||||
return enc
|
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()...)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ func (self *stateObject) updateRoot(db Database) {
|
||||||
self.data.Root = self.trie.Hash()
|
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.
|
// This updates the trie root.
|
||||||
func (self *stateObject) CommitTrie(db Database) error {
|
func (self *stateObject) CommitTrie(db Database) error {
|
||||||
self.updateTrie(db)
|
self.updateTrie(db)
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ func (s *StateSuite) TestNull(c *checker.C) {
|
||||||
s.state.SetState(address, common.Hash{}, value)
|
s.state.SetState(address, common.Hash{}, value)
|
||||||
s.state.Commit(false)
|
s.state.Commit(false)
|
||||||
value = s.state.GetState(address, common.Hash{})
|
value = s.state.GetState(address, common.Hash{})
|
||||||
if !common.EmptyHash(value) {
|
if value != (common.Hash{}) {
|
||||||
c.Errorf("expected empty hash. got %x", value)
|
c.Errorf("expected empty hash. got %x", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewStateSync create a new state trie download scheduler.
|
// NewStateSync create a new state trie download scheduler.
|
||||||
func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync {
|
func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.Sync {
|
||||||
var syncer *trie.TrieSync
|
var syncer *trie.Sync
|
||||||
callback := func(leaf []byte, parent common.Hash) error {
|
callback := func(leaf []byte, parent common.Hash) error {
|
||||||
var obj Account
|
var obj Account
|
||||||
if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil {
|
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)
|
syncer.AddRawEntry(common.BytesToHash(obj.CodeHash), 64, parent)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
syncer = trie.NewTrieSync(root, database, callback)
|
syncer = trie.NewSync(root, database, callback)
|
||||||
return syncer
|
return syncer
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// and uses the input parameters for its environment. It returns the receipt
|
||||||
// for the transaction, gas used and an error if the transaction failed,
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// 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))
|
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
|
|
||||||
105
core/tx_cacher.go
Normal file
105
core/tx_cacher.go
Normal 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)
|
||||||
|
}
|
||||||
|
|
@ -222,7 +222,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
|
||||||
config: config,
|
config: config,
|
||||||
chainconfig: chainconfig,
|
chainconfig: chainconfig,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
signer: types.NewEIP155Signer(chainconfig.ChainId),
|
signer: types.NewEIP155Signer(chainconfig.ChainID),
|
||||||
pending: make(map[common.Address]*txList),
|
pending: make(map[common.Address]*txList),
|
||||||
queue: make(map[common.Address]*txList),
|
queue: make(map[common.Address]*txList),
|
||||||
beats: make(map[common.Address]time.Time),
|
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
|
// Inject any transactions discarded due to reorgs
|
||||||
log.Debug("Reinjecting stale transactions", "count", len(reinject))
|
log.Debug("Reinjecting stale transactions", "count", len(reinject))
|
||||||
|
senderCacher.recover(pool.signer, reinject)
|
||||||
pool.addTxsLocked(reinject, false)
|
pool.addTxsLocked(reinject, false)
|
||||||
|
|
||||||
// validate the pool of pending transactions, this will remove
|
// 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.
|
// Notify subsystem for new promoted transactions.
|
||||||
if len(promoted) > 0 {
|
if len(promoted) > 0 {
|
||||||
pool.txFeed.Send(NewTxsEvent{promoted})
|
go pool.txFeed.Send(NewTxsEvent{promoted})
|
||||||
}
|
}
|
||||||
// If the pending limit is overflown, start equalizing allowances
|
// If the pending limit is overflown, start equalizing allowances
|
||||||
pending := uint64(0)
|
pending := uint64(0)
|
||||||
|
|
@ -1106,7 +1107,7 @@ func (pool *TxPool) demoteUnexecutables() {
|
||||||
log.Trace("Demoting pending transaction", "hash", hash)
|
log.Trace("Demoting pending transaction", "hash", hash)
|
||||||
pool.enqueueTx(hash, tx)
|
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 {
|
if list.Len() > 0 && list.txs.Get(nonce) == nil {
|
||||||
for _, tx := range list.Cap(0) {
|
for _, tx := range list.Cap(0) {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
switch {
|
switch {
|
||||||
case config.IsEIP155(blockNumber):
|
case config.IsEIP155(blockNumber):
|
||||||
signer = NewEIP155Signer(config.ChainId)
|
signer = NewEIP155Signer(config.ChainID)
|
||||||
case config.IsHomestead(blockNumber):
|
case config.IsHomestead(blockNumber):
|
||||||
signer = HomesteadSigner{}
|
signer = HomesteadSigner{}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -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())
|
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
|
// If the next tx has different from account, the price must be lower than the current one
|
||||||
for j := i - 1; j >= 0; j-- {
|
if i+1 < len(txs) {
|
||||||
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
|
next := txs[i+1]
|
||||||
prev = j
|
fromNext, _ := Sender(signer, next)
|
||||||
break
|
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())
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
// 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)
|
// 2. From a non-zero value address to a zero-value address (DELETE)
|
||||||
// 3. From a non-zero to a non-zero (CHANGE)
|
// 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
|
// 0 => non 0
|
||||||
return params.SstoreSetGas, nil
|
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)
|
evm.StateDB.AddRefund(params.SstoreRefundGas)
|
||||||
|
|
||||||
return params.SstoreClearGas, nil
|
return params.SstoreClearGas, nil
|
||||||
} else {
|
} else {
|
||||||
// non 0 => non 0 (or 0 => 0)
|
// non 0 => non 0 (or 0 => 0)
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// pop value of the stack
|
// pop value of the stack
|
||||||
mStart, val := stack.pop(), stack.pop()
|
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)
|
evm.interpreter.intPool.put(mStart, val)
|
||||||
return nil, nil
|
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) {
|
func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
loc := common.BigToHash(stack.pop())
|
loc := stack.peek()
|
||||||
val := evm.StateDB.GetState(contract.Address(), loc).Big()
|
val := evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
||||||
stack.push(val)
|
loc.SetBytes(val.Bytes())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,3 +425,42 @@ func BenchmarkOpIsZero(b *testing.B) {
|
||||||
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||||
opBenchmark(b, opIszero, x)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ type (
|
||||||
var errGasUintOverflow = errors.New("gas uint64 overflow")
|
var errGasUintOverflow = errors.New("gas uint64 overflow")
|
||||||
|
|
||||||
type operation struct {
|
type operation struct {
|
||||||
// op is the operation function
|
// execute is the operation function
|
||||||
execute executionFunc
|
execute executionFunc
|
||||||
// gasCost is the gas function and returns the gas required for execution
|
// gasCost is the gas function and returns the gas required for execution
|
||||||
gasCost gasFunc
|
gasCost gasFunc
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,12 @@
|
||||||
|
|
||||||
package vm
|
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.
|
// Memory implements a simple memory model for the ethereum virtual machine.
|
||||||
type Memory struct {
|
type Memory struct {
|
||||||
|
|
@ -30,19 +35,32 @@ func NewMemory() *Memory {
|
||||||
|
|
||||||
// Set sets offset + size to value
|
// Set sets offset + size to value
|
||||||
func (m *Memory) Set(offset, size uint64, value []byte) {
|
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
|
// 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)
|
// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
|
||||||
if size > 0 {
|
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)
|
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
|
// Resize resizes the memory to size
|
||||||
func (m *Memory) Resize(size uint64) {
|
func (m *Memory) Resize(size uint64) {
|
||||||
if uint64(m.Len()) < size {
|
if uint64(m.Len()) < size {
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ type Config struct {
|
||||||
func setDefaults(cfg *Config) {
|
func setDefaults(cfg *Config) {
|
||||||
if cfg.ChainConfig == nil {
|
if cfg.ChainConfig == nil {
|
||||||
cfg.ChainConfig = ¶ms.ChainConfig{
|
cfg.ChainConfig = ¶ms.ChainConfig{
|
||||||
ChainId: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
HomesteadBlock: new(big.Int),
|
HomesteadBlock: new(big.Int),
|
||||||
DAOForkBlock: new(big.Int),
|
DAOForkBlock: new(big.Int),
|
||||||
DAOForkSupport: false,
|
DAOForkSupport: false,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ var (
|
||||||
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
|
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.
|
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||||
func Keccak256(data ...[]byte) []byte {
|
func Keccak256(data ...[]byte) []byte {
|
||||||
d := sha3.NewKeccak256()
|
d := sha3.NewKeccak256()
|
||||||
|
|
@ -122,12 +124,13 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {
|
||||||
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
|
// UnmarshalPubkey converts bytes to a secp256k1 public key.
|
||||||
if len(pub) == 0 {
|
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x, y := elliptic.Unmarshal(S256(), pub)
|
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 {
|
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,11 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
|
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) {
|
func TestSign(t *testing.T) {
|
||||||
key, _ := HexToECDSA(testPrivHex)
|
key, _ := HexToECDSA(testPrivHex)
|
||||||
addr := common.HexToAddress(testAddrHex)
|
addr := common.HexToAddress(testAddrHex)
|
||||||
|
|
@ -69,7 +98,7 @@ func TestSign(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ECRecover error: %s", err)
|
t.Errorf("ECRecover error: %s", err)
|
||||||
}
|
}
|
||||||
pubKey := ToECDSAPub(recoveredPub)
|
pubKey, _ := UnmarshalPubkey(recoveredPub)
|
||||||
recoveredAddr := PubkeyToAddress(*pubKey)
|
recoveredAddr := PubkeyToAddress(*pubKey)
|
||||||
if addr != recoveredAddr {
|
if addr != recoveredAddr {
|
||||||
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
|
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
|
||||||
|
|
|
||||||
29
eth/api.go
29
eth/api.go
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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")
|
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
|
// 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
|
// and returns them as a JSON list of block-hashes
|
||||||
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) {
|
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
|
||||||
return api.eth.BlockChain().BadBlocks()
|
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.
|
// StorageRangeResult is the result of a debug_storageRangeAt API call.
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,8 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
|
||||||
// Print progress logs if long enough time elapsed
|
// Print progress logs if long enough time elapsed
|
||||||
if time.Since(logged) > 8*time.Second {
|
if time.Since(logged) > 8*time.Second {
|
||||||
if number > origin {
|
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 {
|
} else {
|
||||||
log.Info("Preparing state for chain trace", "block", number, "start", origin, "elapsed", time.Since(begin))
|
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
|
// Dereference all past tries we ourselves are done working with
|
||||||
database.TrieDB().Dereference(proot, common.Hash{})
|
database.TrieDB().Dereference(proot, common.Hash{})
|
||||||
proot = root
|
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{})
|
database.TrieDB().Dereference(proot, common.Hash{})
|
||||||
proot = root
|
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
|
return statedb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,14 +215,14 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
|
||||||
return clique.New(chainConfig.Clique, db)
|
return clique.New(chainConfig.Clique, db)
|
||||||
}
|
}
|
||||||
// Otherwise assume proof-of-work
|
// Otherwise assume proof-of-work
|
||||||
switch {
|
switch config.PowMode {
|
||||||
case config.PowMode == ethash.ModeFake:
|
case ethash.ModeFake:
|
||||||
log.Warn("Ethash used in fake mode")
|
log.Warn("Ethash used in fake mode")
|
||||||
return ethash.NewFaker()
|
return ethash.NewFaker()
|
||||||
case config.PowMode == ethash.ModeTest:
|
case ethash.ModeTest:
|
||||||
log.Warn("Ethash used in test mode")
|
log.Warn("Ethash used in test mode")
|
||||||
return ethash.NewTester()
|
return ethash.NewTester()
|
||||||
case config.PowMode == ethash.ModeShared:
|
case ethash.ModeShared:
|
||||||
log.Warn("Ethash used in shared mode")
|
log.Warn("Ethash used in shared mode")
|
||||||
return ethash.NewShared()
|
return ethash.NewShared()
|
||||||
default:
|
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.
|
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||||
func (s *Ethereum) APIs() []rpc.API {
|
func (s *Ethereum) APIs() []rpc.API {
|
||||||
apis := ethapi.GetAPIs(s.APIBackend)
|
apis := ethapi.GetAPIs(s.APIBackend)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ var DefaultConfig = Config{
|
||||||
LightPeers: 100,
|
LightPeers: 100,
|
||||||
DatabaseCache: 768,
|
DatabaseCache: 768,
|
||||||
TrieCache: 256,
|
TrieCache: 256,
|
||||||
TrieTimeout: 5 * time.Minute,
|
TrieTimeout: 60 * time.Minute,
|
||||||
GasPrice: big.NewInt(18 * params.Shannon),
|
GasPrice: big.NewInt(18 * params.Shannon),
|
||||||
|
|
||||||
TxPool: core.DefaultTxPoolConfig,
|
TxPool: core.DefaultTxPoolConfig,
|
||||||
|
|
|
||||||
|
|
@ -680,7 +680,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the head fetch already found an ancestor, return
|
// If the head fetch already found an ancestor, return
|
||||||
if !common.EmptyHash(hash) {
|
if hash != (common.Hash{}) {
|
||||||
if int64(number) <= floor {
|
if int64(number) <= floor {
|
||||||
p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor)
|
p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor)
|
||||||
return 0, errInvalidAncestor
|
return 0, errInvalidAncestor
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync {
|
||||||
type stateSync struct {
|
type stateSync struct {
|
||||||
d *Downloader // Downloader instance to access and manage current peerset
|
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
|
keccak hash.Hash // Keccak256 hasher to verify deliveries with
|
||||||
tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval
|
tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ type headerFilterTask struct {
|
||||||
time time.Time // Arrival time of the headers
|
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.
|
// needing fetcher filtering.
|
||||||
type bodyFilterTask struct {
|
type bodyFilterTask struct {
|
||||||
peer string // The source peer of block bodies
|
peer string // The source peer of block bodies
|
||||||
|
|
@ -292,20 +292,20 @@ func (f *Fetcher) loop() {
|
||||||
height := f.chainHeight()
|
height := f.chainHeight()
|
||||||
for !f.queue.Empty() {
|
for !f.queue.Empty() {
|
||||||
op := f.queue.PopItem().(*inject)
|
op := f.queue.PopItem().(*inject)
|
||||||
|
hash := op.block.Hash()
|
||||||
if f.queueChangeHook != nil {
|
if f.queueChangeHook != nil {
|
||||||
f.queueChangeHook(op.block.Hash(), false)
|
f.queueChangeHook(hash, false)
|
||||||
}
|
}
|
||||||
// If too high up the chain or phase, continue later
|
// If too high up the chain or phase, continue later
|
||||||
number := op.block.NumberU64()
|
number := op.block.NumberU64()
|
||||||
if number > height+1 {
|
if number > height+1 {
|
||||||
f.queue.Push(op, -float32(op.block.NumberU64()))
|
f.queue.Push(op, -float32(number))
|
||||||
if f.queueChangeHook != nil {
|
if f.queueChangeHook != nil {
|
||||||
f.queueChangeHook(op.block.Hash(), true)
|
f.queueChangeHook(hash, true)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Otherwise if fresh and still unknown, try and import
|
// Otherwise if fresh and still unknown, try and import
|
||||||
hash := op.block.Hash()
|
|
||||||
if number+maxUncleDist < height || f.getBlock(hash) != nil {
|
if number+maxUncleDist < height || f.getBlock(hash) != nil {
|
||||||
f.forgetBlock(hash)
|
f.forgetBlock(hash)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -258,9 +258,9 @@ Logs:
|
||||||
if len(topics) > len(log.Topics) {
|
if len(topics) > len(log.Topics) {
|
||||||
continue Logs
|
continue Logs
|
||||||
}
|
}
|
||||||
for i, topics := range topics {
|
for i, sub := range topics {
|
||||||
match := len(topics) == 0 // empty rule set == wildcard
|
match := len(sub) == 0 // empty rule set == wildcard
|
||||||
for _, topic := range topics {
|
for _, topic := range sub {
|
||||||
if log.Topics[i] == topic {
|
if log.Topics[i] == topic {
|
||||||
match = true
|
match = true
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrDecode, "%v: %v", msg, err)
|
return errResp(ErrDecode, "%v: %v", msg, err)
|
||||||
}
|
}
|
||||||
hashMode := query.Origin.Hash != (common.Hash{})
|
hashMode := query.Origin.Hash != (common.Hash{})
|
||||||
|
first := true
|
||||||
|
maxNonCanonical := uint64(100)
|
||||||
|
|
||||||
// Gather headers until the fetch or network limits is reached
|
// Gather headers until the fetch or network limits is reached
|
||||||
var (
|
var (
|
||||||
|
|
@ -351,31 +353,36 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
// Retrieve the next header satisfying the query
|
// Retrieve the next header satisfying the query
|
||||||
var origin *types.Header
|
var origin *types.Header
|
||||||
if hashMode {
|
if hashMode {
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
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 {
|
} else {
|
||||||
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
||||||
}
|
}
|
||||||
if origin == nil {
|
if origin == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
number := origin.Number.Uint64()
|
|
||||||
headers = append(headers, origin)
|
headers = append(headers, origin)
|
||||||
bytes += estHeaderRlpSize
|
bytes += estHeaderRlpSize
|
||||||
|
|
||||||
// Advance to the next header of the query
|
// Advance to the next header of the query
|
||||||
switch {
|
switch {
|
||||||
case query.Origin.Hash != (common.Hash{}) && query.Reverse:
|
case hashMode && query.Reverse:
|
||||||
// Hash based traversal towards the genesis block
|
// Hash based traversal towards the genesis block
|
||||||
for i := 0; i < int(query.Skip)+1; i++ {
|
ancestor := query.Skip + 1
|
||||||
if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil {
|
if ancestor == 0 {
|
||||||
query.Origin.Hash = header.ParentHash
|
|
||||||
number--
|
|
||||||
} else {
|
|
||||||
unknown = true
|
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 hashMode && !query.Reverse:
|
||||||
case query.Origin.Hash != (common.Hash{}) && !query.Reverse:
|
|
||||||
// Hash based traversal towards the leaf block
|
// Hash based traversal towards the leaf block
|
||||||
var (
|
var (
|
||||||
current = origin.Number.Uint64()
|
current = origin.Number.Uint64()
|
||||||
|
|
@ -387,8 +394,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
unknown = true
|
unknown = true
|
||||||
} else {
|
} else {
|
||||||
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
|
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
|
||||||
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash {
|
nextHash := header.Hash()
|
||||||
query.Origin.Hash = 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 {
|
} else {
|
||||||
unknown = true
|
unknown = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
// the final result of the tracing.
|
// the final result of the tracing.
|
||||||
result: function(ctx) {
|
result: function(ctx) {
|
||||||
// Save the outer calldata also
|
// 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)
|
this.store(slice(ctx.input, 0, 4), ctx.input.length-4)
|
||||||
}
|
}
|
||||||
return this.ids;
|
return this.ids;
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -141,7 +141,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
|
||||||
// Fill the sender cache of transactions in the block.
|
// Fill the sender cache of transactions in the block.
|
||||||
txs := make([]*types.Transaction, len(body.Transactions))
|
txs := make([]*types.Transaction, len(body.Transactions))
|
||||||
for i, tx := range 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
|
txs[i] = tx.tx
|
||||||
}
|
}
|
||||||
return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil
|
return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil
|
||||||
|
|
@ -174,9 +176,9 @@ type rpcTransaction struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type txExtraInfo struct {
|
type txExtraInfo struct {
|
||||||
BlockNumber *string
|
BlockNumber *string `json:"blockNumber,omitempty"`
|
||||||
BlockHash common.Hash
|
BlockHash *common.Hash `json:"blockHash,omitempty"`
|
||||||
From common.Address
|
From *common.Address `json:"from,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
|
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 {
|
} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
|
||||||
return nil, false, fmt.Errorf("server returned transaction without signature")
|
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
|
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")
|
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
|
return json.tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ func (db *LDBDatabase) Close() {
|
||||||
if err := <-errc; err != nil {
|
if err := <-errc; err != nil {
|
||||||
db.log.Error("Metrics collection failed", "err", err)
|
db.log.Error("Metrics collection failed", "err", err)
|
||||||
}
|
}
|
||||||
|
db.quitChan = nil
|
||||||
}
|
}
|
||||||
err := db.db.Close()
|
err := db.db.Close()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
@ -189,7 +190,7 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||||
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
||||||
//
|
//
|
||||||
// This is how the write delay look like (currently):
|
// 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):
|
// This is how the iostats look like (currently):
|
||||||
// Read(MB):3895.04860 Write(MB):3654.64712
|
// Read(MB):3895.04860 Write(MB):3654.64712
|
||||||
|
|
@ -210,13 +211,19 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
lastWritePaused time.Time
|
lastWritePaused time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errc chan error
|
||||||
|
merr error
|
||||||
|
)
|
||||||
|
|
||||||
// Iterate ad infinitum and collect the stats
|
// Iterate ad infinitum and collect the stats
|
||||||
for i := 1; ; i++ {
|
for i := 1; errc == nil && merr == nil; i++ {
|
||||||
// Retrieve the database stats
|
// Retrieve the database stats
|
||||||
stats, err := db.db.GetProperty("leveldb.stats")
|
stats, err := db.db.GetProperty("leveldb.stats")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("Failed to read database stats", "err", err)
|
db.log.Error("Failed to read database stats", "err", err)
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
// Find the compaction table, skip the header
|
// Find the compaction table, skip the header
|
||||||
lines := strings.Split(stats, "\n")
|
lines := strings.Split(stats, "\n")
|
||||||
|
|
@ -225,7 +232,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
}
|
}
|
||||||
if len(lines) <= 3 {
|
if len(lines) <= 3 {
|
||||||
db.log.Error("Compaction table not found")
|
db.log.Error("Compaction table not found")
|
||||||
return
|
merr = errors.New("compaction table not found")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
lines = lines[3:]
|
lines = lines[3:]
|
||||||
|
|
||||||
|
|
@ -242,7 +250,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
|
value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("Compaction entry parsing failed", "err", err)
|
db.log.Error("Compaction entry parsing failed", "err", err)
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
compactions[i%2][idx] += value
|
compactions[i%2][idx] += value
|
||||||
}
|
}
|
||||||
|
|
@ -262,7 +271,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
writedelay, err := db.db.GetProperty("leveldb.writedelay")
|
writedelay, err := db.db.GetProperty("leveldb.writedelay")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("Failed to read database write delay statistic", "err", err)
|
db.log.Error("Failed to read database write delay statistic", "err", err)
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
delayN int64
|
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 {
|
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")
|
db.log.Error("Write delay statistic not found")
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
duration, err = time.ParseDuration(delayDuration)
|
duration, err = time.ParseDuration(delayDuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("Failed to parse delay duration", "err", err)
|
db.log.Error("Failed to parse delay duration", "err", err)
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if db.writeDelayNMeter != nil {
|
if db.writeDelayNMeter != nil {
|
||||||
db.writeDelayNMeter.Mark(delayN - delaystats[0])
|
db.writeDelayNMeter.Mark(delayN - delaystats[0])
|
||||||
|
|
@ -317,53 +329,47 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
ioStats, err := db.db.GetProperty("leveldb.iostats")
|
ioStats, err := db.db.GetProperty("leveldb.iostats")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("Failed to read database iostats", "err", err)
|
db.log.Error("Failed to read database iostats", "err", err)
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
var nRead, nWrite float64
|
||||||
parts := strings.Split(ioStats, " ")
|
parts := strings.Split(ioStats, " ")
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
|
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 n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil {
|
||||||
if len(r) < 2 {
|
|
||||||
db.log.Error("Bad syntax of read entry", "entry", parts[0])
|
db.log.Error("Bad syntax of read entry", "entry", parts[0])
|
||||||
return
|
merr = err
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
read, err := strconv.ParseFloat(r[1], 64)
|
if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil {
|
||||||
if err != nil {
|
|
||||||
db.log.Error("Read entry parsing failed", "err", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w := strings.Split(parts[1], ":")
|
|
||||||
if len(w) < 2 {
|
|
||||||
db.log.Error("Bad syntax of write entry", "entry", parts[1])
|
db.log.Error("Bad syntax of write entry", "entry", parts[1])
|
||||||
return
|
merr = err
|
||||||
}
|
continue
|
||||||
write, err := strconv.ParseFloat(w[1], 64)
|
|
||||||
if err != nil {
|
|
||||||
db.log.Error("Write entry parsing failed", "err", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if db.diskReadMeter != nil {
|
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 {
|
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[0], iostats[1] = nRead, nWrite
|
||||||
iostats[1] = write
|
|
||||||
|
|
||||||
// Sleep a bit, then repeat the stats collection
|
// Sleep a bit, then repeat the stats collection
|
||||||
select {
|
select {
|
||||||
case errc := <-db.quitChan:
|
case errc = <-db.quitChan:
|
||||||
// Quit requesting, stop hammering the database
|
// Quit requesting, stop hammering the database
|
||||||
errc <- nil
|
|
||||||
return
|
|
||||||
|
|
||||||
case <-time.After(refresh):
|
case <-time.After(refresh):
|
||||||
// Timeout, gather a new set of stats
|
// Timeout, gather a new set of stats
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if errc == nil {
|
||||||
|
errc = <-db.quitChan
|
||||||
|
}
|
||||||
|
errc <- merr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *LDBDatabase) NewBatch() Batch {
|
func (db *LDBDatabase) NewBatch() Batch {
|
||||||
|
|
|
||||||
|
|
@ -362,7 +362,7 @@ type nodeInfo struct {
|
||||||
|
|
||||||
// authMsg is the authentication infos needed to login to a monitoring server.
|
// authMsg is the authentication infos needed to login to a monitoring server.
|
||||||
type authMsg struct {
|
type authMsg struct {
|
||||||
Id string `json:"id"`
|
ID string `json:"id"`
|
||||||
Info nodeInfo `json:"info"`
|
Info nodeInfo `json:"info"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +381,7 @@ func (s *Service) login(conn *websocket.Conn) error {
|
||||||
protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0])
|
protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0])
|
||||||
}
|
}
|
||||||
auth := &authMsg{
|
auth := &authMsg{
|
||||||
Id: s.node,
|
ID: s.node,
|
||||||
Info: nodeInfo{
|
Info: nodeInfo{
|
||||||
Name: s.node,
|
Name: s.node,
|
||||||
Node: infos.Name,
|
Node: infos.Name,
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ type FilterQuery struct {
|
||||||
// {} or nil matches any topic list
|
// {} or nil matches any topic list
|
||||||
// {{A}} matches topic A in first position
|
// {{A}} matches topic A in first position
|
||||||
// {{}, {B}} matches any topic in first position, B in second 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
|
// {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position
|
||||||
Topics [][]common.Hash
|
Topics [][]common.Hash
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,9 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GasPrice returns a suggestion for a gas price.
|
// GasPrice returns a suggestion for a gas price.
|
||||||
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) {
|
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
|
||||||
return s.b.SuggestPrice(ctx)
|
price, err := s.b.SuggestPrice(ctx)
|
||||||
|
return (*hexutil.Big)(price), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtocolVersion returns the current Ethereum protocol version this node supports
|
// 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
|
var chainID *big.Int
|
||||||
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
||||||
chainID = config.ChainId
|
chainID = config.ChainID
|
||||||
}
|
}
|
||||||
return wallet.SignTxWithPassphrase(account, passwd, tx, 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
|
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 {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
pubKey := crypto.ToECDSAPub(rpk)
|
return crypto.PubkeyToAddress(*rpk), nil
|
||||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
|
||||||
return recoveredAddr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
|
// 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.
|
// 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
|
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
|
// 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
|
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||||
// block numbers are also allowed.
|
// 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)
|
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b := state.GetBalance(address)
|
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
||||||
return b, state.Error()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
|
// 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
|
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
|
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
|
||||||
// transaction hashes.
|
// 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
|
head := b.Header() // copies the header once
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"number": (*hexutil.Big)(head.Number),
|
"number": (*hexutil.Big)(head.Number),
|
||||||
|
|
@ -808,7 +806,6 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
||||||
"stateRoot": head.Root,
|
"stateRoot": head.Root,
|
||||||
"miner": head.Coinbase,
|
"miner": head.Coinbase,
|
||||||
"difficulty": (*hexutil.Big)(head.Difficulty),
|
"difficulty": (*hexutil.Big)(head.Difficulty),
|
||||||
"totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())),
|
|
||||||
"extraData": hexutil.Bytes(head.Extra),
|
"extraData": hexutil.Bytes(head.Extra),
|
||||||
"size": hexutil.Uint64(b.Size()),
|
"size": hexutil.Uint64(b.Size()),
|
||||||
"gasLimit": hexutil.Uint64(head.GasLimit),
|
"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) {
|
formatTx := func(tx *types.Transaction) (interface{}, error) {
|
||||||
return tx.Hash(), nil
|
return tx.Hash(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if fullTx {
|
if fullTx {
|
||||||
formatTx = func(tx *types.Transaction) (interface{}, error) {
|
formatTx = func(tx *types.Transaction) (interface{}, error) {
|
||||||
return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
|
return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
txs := b.Transactions()
|
txs := b.Transactions()
|
||||||
transactions := make([]interface{}, len(txs))
|
transactions := make([]interface{}, len(txs))
|
||||||
var err error
|
var err error
|
||||||
for i, tx := range b.Transactions() {
|
for i, tx := range txs {
|
||||||
if transactions[i], err = formatTx(tx); err != nil {
|
if transactions[i], err = formatTx(tx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -850,6 +845,17 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
||||||
return fields, nil
|
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
|
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
||||||
type RPCTransaction struct {
|
type RPCTransaction struct {
|
||||||
BlockHash common.Hash `json:"blockHash"`
|
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
|
// Request the wallet to sign the transaction
|
||||||
var chainID *big.Int
|
var chainID *big.Int
|
||||||
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
||||||
chainID = config.ChainId
|
chainID = config.ChainID
|
||||||
}
|
}
|
||||||
return wallet.SignTx(account, tx, chainID)
|
return wallet.SignTx(account, tx, chainID)
|
||||||
}
|
}
|
||||||
|
|
@ -1216,7 +1222,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
|
||||||
|
|
||||||
var chainID *big.Int
|
var chainID *big.Int
|
||||||
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
||||||
chainID = config.ChainId
|
chainID = config.ChainID
|
||||||
}
|
}
|
||||||
signed, err := wallet.SignTx(account, tx, chainID)
|
signed, err := wallet.SignTx(account, tx, chainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1293,14 +1299,19 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
|
||||||
return &SignTransactionResult{data, tx}, nil
|
return &SignTransactionResult{data, tx}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of
|
// PendingTransactions returns the transactions that are in the transaction pool
|
||||||
// the accounts this node manages.
|
// and have a from address that is one of the accounts this node manages.
|
||||||
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
|
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
|
||||||
pending, err := s.b.GetPoolTransactions()
|
pending, err := s.b.GetPoolTransactions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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))
|
transactions := make([]*RPCTransaction, 0, len(pending))
|
||||||
for _, tx := range pending {
|
for _, tx := range pending {
|
||||||
var signer types.Signer = types.HomesteadSigner{}
|
var signer types.Signer = types.HomesteadSigner{}
|
||||||
|
|
@ -1308,7 +1319,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
|
||||||
signer = types.NewEIP155Signer(tx.ChainId())
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
}
|
}
|
||||||
from, _ := types.Sender(signer, tx)
|
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))
|
transactions = append(transactions, newRPCPendingTransaction(tx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -313,8 +313,8 @@ web3._extend({
|
||||||
params: 2
|
params: 2
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'setMutexProfileRate',
|
name: 'setMutexProfileFraction',
|
||||||
call: 'debug_setMutexProfileRate',
|
call: 'debug_setMutexProfileFraction',
|
||||||
params: 1
|
params: 1
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
leth.ApiBackend = &LesApiBackend{leth, nil}
|
leth.ApiBackend = &LesApiBackend{leth, nil}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package les
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -82,7 +83,7 @@ type BlockChain interface {
|
||||||
InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
|
InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
|
||||||
Rollback(chain []common.Hash)
|
Rollback(chain []common.Hash)
|
||||||
GetHeaderByNumber(number uint64) *types.Header
|
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
|
Genesis() *types.Block
|
||||||
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
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
|
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||||
// with the ethereum network.
|
// 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
|
// Create the protocol manager with the base fields
|
||||||
manager := &ProtocolManager{
|
manager := &ProtocolManager{
|
||||||
lightSync: lightSync,
|
lightSync: lightSync,
|
||||||
|
|
@ -140,6 +141,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protoco
|
||||||
networkId: networkId,
|
networkId: networkId,
|
||||||
txpool: txpool,
|
txpool: txpool,
|
||||||
txrelay: txrelay,
|
txrelay: txrelay,
|
||||||
|
serverPool: serverPool,
|
||||||
peers: peers,
|
peers: peers,
|
||||||
newPeerCh: make(chan *peer),
|
newPeerCh: make(chan *peer),
|
||||||
quitSync: quitSync,
|
quitSync: quitSync,
|
||||||
|
|
@ -417,6 +419,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
hashMode := query.Origin.Hash != (common.Hash{})
|
hashMode := query.Origin.Hash != (common.Hash{})
|
||||||
|
first := true
|
||||||
|
maxNonCanonical := uint64(100)
|
||||||
|
|
||||||
// Gather headers until the fetch or network limits is reached
|
// Gather headers until the fetch or network limits is reached
|
||||||
var (
|
var (
|
||||||
|
|
@ -428,41 +432,58 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
// Retrieve the next header satisfying the query
|
// Retrieve the next header satisfying the query
|
||||||
var origin *types.Header
|
var origin *types.Header
|
||||||
if hashMode {
|
if hashMode {
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
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 {
|
} else {
|
||||||
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
||||||
}
|
}
|
||||||
if origin == nil {
|
if origin == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
number := origin.Number.Uint64()
|
|
||||||
headers = append(headers, origin)
|
headers = append(headers, origin)
|
||||||
bytes += estHeaderRlpSize
|
bytes += estHeaderRlpSize
|
||||||
|
|
||||||
// Advance to the next header of the query
|
// Advance to the next header of the query
|
||||||
switch {
|
switch {
|
||||||
case query.Origin.Hash != (common.Hash{}) && query.Reverse:
|
case hashMode && query.Reverse:
|
||||||
// Hash based traversal towards the genesis block
|
// Hash based traversal towards the genesis block
|
||||||
for i := 0; i < int(query.Skip)+1; i++ {
|
ancestor := query.Skip + 1
|
||||||
if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil {
|
if ancestor == 0 {
|
||||||
query.Origin.Hash = header.ParentHash
|
|
||||||
number--
|
|
||||||
} else {
|
|
||||||
unknown = true
|
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 hashMode && !query.Reverse:
|
||||||
case query.Origin.Hash != (common.Hash{}) && !query.Reverse:
|
|
||||||
// Hash based traversal towards the leaf block
|
// Hash based traversal towards the leaf block
|
||||||
if header := pm.blockchain.GetHeaderByNumber(origin.Number.Uint64() + query.Skip + 1); header != nil {
|
var (
|
||||||
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash {
|
current = origin.Number.Uint64()
|
||||||
query.Origin.Hash = header.Hash()
|
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 {
|
} else {
|
||||||
unknown = true
|
unknown = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unknown = true
|
unknown = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case query.Reverse:
|
case query.Reverse:
|
||||||
// Number based traversal towards the genesis block
|
// Number based traversal towards the genesis block
|
||||||
if query.Origin.Number >= query.Skip+1 {
|
if query.Origin.Number >= query.Skip+1 {
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
||||||
} else {
|
} else {
|
||||||
protocolVersions = ServerProtocolVersions
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ type sentReq struct {
|
||||||
lock sync.RWMutex // protect access to sentTo map
|
lock sync.RWMutex // protect access to sentTo map
|
||||||
sentTo map[distPeer]sentReqToPeer
|
sentTo map[distPeer]sentReqToPeer
|
||||||
|
|
||||||
reqQueued bool // a request has been queued but not sent
|
lastReqQueued bool // last request has been queued but not sent
|
||||||
reqSent bool // a request has been sent but not timed out
|
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
|
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
|
// retrieveLoop is the retrieval state machine event loop
|
||||||
func (r *sentReq) retrieveLoop() {
|
func (r *sentReq) retrieveLoop() {
|
||||||
go r.tryRequest()
|
go r.tryRequest()
|
||||||
r.reqQueued = true
|
r.lastReqQueued = true
|
||||||
state := r.stateRequesting
|
state := r.stateRequesting
|
||||||
|
|
||||||
for state != nil {
|
for state != nil {
|
||||||
|
|
@ -214,7 +214,7 @@ func (r *sentReq) stateRequesting() reqStateFn {
|
||||||
case rpSoftTimeout:
|
case rpSoftTimeout:
|
||||||
// last request timed out, try asking a new peer
|
// last request timed out, try asking a new peer
|
||||||
go r.tryRequest()
|
go r.tryRequest()
|
||||||
r.reqQueued = true
|
r.lastReqQueued = true
|
||||||
return r.stateRequesting
|
return r.stateRequesting
|
||||||
case rpDeliveredValid:
|
case rpDeliveredValid:
|
||||||
r.stop(nil)
|
r.stop(nil)
|
||||||
|
|
@ -233,7 +233,7 @@ func (r *sentReq) stateNoMorePeers() reqStateFn {
|
||||||
select {
|
select {
|
||||||
case <-time.After(retryQueue):
|
case <-time.After(retryQueue):
|
||||||
go r.tryRequest()
|
go r.tryRequest()
|
||||||
r.reqQueued = true
|
r.lastReqQueued = true
|
||||||
return r.stateRequesting
|
return r.stateRequesting
|
||||||
case ev := <-r.eventsCh:
|
case ev := <-r.eventsCh:
|
||||||
r.update(ev)
|
r.update(ev)
|
||||||
|
|
@ -260,22 +260,26 @@ func (r *sentReq) stateStopped() reqStateFn {
|
||||||
func (r *sentReq) update(ev reqPeerEvent) {
|
func (r *sentReq) update(ev reqPeerEvent) {
|
||||||
switch ev.event {
|
switch ev.event {
|
||||||
case rpSent:
|
case rpSent:
|
||||||
r.reqQueued = false
|
r.lastReqQueued = false
|
||||||
if ev.peer != nil {
|
r.lastReqSentTo = ev.peer
|
||||||
r.reqSent = true
|
|
||||||
}
|
|
||||||
case rpSoftTimeout:
|
case rpSoftTimeout:
|
||||||
r.reqSent = false
|
r.lastReqSentTo = nil
|
||||||
r.reqSrtoCount++
|
r.reqSrtoCount++
|
||||||
case rpHardTimeout, rpDeliveredValid, rpDeliveredInvalid:
|
case rpHardTimeout:
|
||||||
r.reqSrtoCount--
|
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
|
// waiting returns true if the retrieval mechanism is waiting for an answer from
|
||||||
// any peer
|
// any peer
|
||||||
func (r *sentReq) waiting() bool {
|
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
|
// tryRequest tries to send the request to a new peer and waits for it to either
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ type LesServer struct {
|
||||||
|
|
||||||
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
||||||
quitSync := make(chan struct{})
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -433,6 +433,18 @@ func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []c
|
||||||
return self.hc.GetBlockHashesFromHash(hash, max)
|
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,
|
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||||
// caching it (associated with its hash) if found.
|
// caching it (associated with its hash) if found.
|
||||||
func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header {
|
func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||||
|
|
|
||||||
|
|
@ -59,18 +59,18 @@ type trustedCheckpoint struct {
|
||||||
var (
|
var (
|
||||||
mainnetCheckpoint = trustedCheckpoint{
|
mainnetCheckpoint = trustedCheckpoint{
|
||||||
name: "mainnet",
|
name: "mainnet",
|
||||||
sectionIdx: 170,
|
sectionIdx: 174,
|
||||||
sectionHead: common.HexToHash("3bb2c28bcce463d57968f14f56cdb3fbf35349ab7a701f44c1afb57349c9a356"),
|
sectionHead: common.HexToHash("a3ef48cd8f1c3a08419f0237fc7763491fe89497b3144b17adf87c1c43664613"),
|
||||||
chtRoot: common.HexToHash("d92b6d0853455f8439086292338e87f69781921680dd7aa072fb71547b87415e"),
|
chtRoot: common.HexToHash("dcbeed9f4dea1b3cb75601bb27c51b9960c28e5850275402ac49a150a667296e"),
|
||||||
bloomTrieRoot: common.HexToHash("e4e8250a2fefddead7ae42daecd848cbf9b66d748a8270f8bbd4370b764bb9e9"),
|
bloomTrieRoot: common.HexToHash("6b7497a4a03e33870a2383cb6f5e70570f12b1bf5699063baf8c71d02ca90b02"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ropstenCheckpoint = trustedCheckpoint{
|
ropstenCheckpoint = trustedCheckpoint{
|
||||||
name: "ropsten",
|
name: "ropsten",
|
||||||
sectionIdx: 97,
|
sectionIdx: 102,
|
||||||
sectionHead: common.HexToHash("719448c67c01eb5b9f27833a36a4e34612f66801316d7ff37daf9e77fb4cd095"),
|
sectionHead: common.HexToHash("9017ab08465cb2b2dee035ee5b817bbd7fa28e2c8d2cd903e0aed1cccb249e89"),
|
||||||
chtRoot: common.HexToHash("a7857afc15930ca6e583b6c3d563a025144011655843d52d28e2fdaadd417bea"),
|
chtRoot: common.HexToHash("f61c10a7a787a5ef15f0ae1ae6c13c64331e57e79d0466d2bd9b0c06833fe956"),
|
||||||
bloomTrieRoot: common.HexToHash("9c71d4b50cbec86dfeaa8e08992de8a4667b81d13c54d6522b17ce2fc5d36416"),
|
bloomTrieRoot: common.HexToHash("69f2ad19aa46d5213a90137b3d2c9bff8a7c9483f7170f0125096ff450c9a873"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ type TxRelayBackend interface {
|
||||||
func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool {
|
func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool {
|
||||||
pool := &TxPool{
|
pool := &TxPool{
|
||||||
config: config,
|
config: config,
|
||||||
signer: types.NewEIP155Signer(config.ChainId),
|
signer: types.NewEIP155Signer(config.ChainID),
|
||||||
nonce: make(map[common.Address]uint64),
|
nonce: make(map[common.Address]uint64),
|
||||||
pending: make(map[common.Hash]*types.Transaction),
|
pending: make(map[common.Hash]*types.Transaction),
|
||||||
mined: make(map[common.Hash][]*types.Transaction),
|
mined: make(map[common.Hash][]*types.Transaction),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
timeFormat = "2006-01-02T15:04:05-0700"
|
timeFormat = "2006-01-02T15:04:05-0700"
|
||||||
termTimeFormat = "01-02|15:04:05"
|
termTimeFormat = "01-02|15:04:05.999999"
|
||||||
floatFormat = 'f'
|
floatFormat = 'f'
|
||||||
termMsgJust = 40
|
termMsgJust = 40
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const timeKey = "t"
|
||||||
const lvlKey = "lvl"
|
const lvlKey = "lvl"
|
||||||
const msgKey = "msg"
|
const msgKey = "msg"
|
||||||
const errorKey = "LOG15_ERROR"
|
const errorKey = "LOG15_ERROR"
|
||||||
|
const skipLevel = 2
|
||||||
|
|
||||||
type Lvl int
|
type Lvl int
|
||||||
|
|
||||||
|
|
@ -127,13 +128,13 @@ type logger struct {
|
||||||
h *swapHandler
|
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{
|
l.h.Log(&Record{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Lvl: lvl,
|
Lvl: lvl,
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
Ctx: newContext(l.ctx, ctx),
|
Ctx: newContext(l.ctx, ctx),
|
||||||
Call: stack.Caller(2),
|
Call: stack.Caller(skip),
|
||||||
KeyNames: RecordKeyNames{
|
KeyNames: RecordKeyNames{
|
||||||
Time: timeKey,
|
Time: timeKey,
|
||||||
Msg: msgKey,
|
Msg: msgKey,
|
||||||
|
|
@ -157,27 +158,27 @@ func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *logger) Trace(msg string, ctx ...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{}) {
|
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{}) {
|
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{}) {
|
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{}) {
|
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{}) {
|
func (l *logger) Crit(msg string, ctx ...interface{}) {
|
||||||
l.write(msg, LvlCrit, ctx)
|
l.write(msg, LvlCrit, ctx, skipLevel)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
21
log/root.go
21
log/root.go
|
|
@ -31,31 +31,40 @@ func Root() Logger {
|
||||||
|
|
||||||
// Trace is a convenient alias for Root().Trace
|
// Trace is a convenient alias for Root().Trace
|
||||||
func Trace(msg string, ctx ...interface{}) {
|
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
|
// Debug is a convenient alias for Root().Debug
|
||||||
func Debug(msg string, ctx ...interface{}) {
|
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
|
// Info is a convenient alias for Root().Info
|
||||||
func Info(msg string, ctx ...interface{}) {
|
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
|
// Warn is a convenient alias for Root().Warn
|
||||||
func Warn(msg string, ctx ...interface{}) {
|
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
|
// Error is a convenient alias for Root().Error
|
||||||
func Error(msg string, ctx ...interface{}) {
|
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
|
// Crit is a convenient alias for Root().Crit
|
||||||
func Crit(msg string, ctx ...interface{}) {
|
func Crit(msg string, ctx ...interface{}) {
|
||||||
root.write(msg, LvlCrit, ctx)
|
root.write(msg, LvlCrit, ctx, skipLevel)
|
||||||
os.Exit(1)
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,17 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) {
|
||||||
exp.getFloat(name + ".mean-rate").Set(t.RateMean())
|
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() {
|
func (exp *exp) syncToExpvar() {
|
||||||
exp.registry.Each(func(name string, i interface{}) {
|
exp.registry.Each(func(name string, i interface{}) {
|
||||||
switch i.(type) {
|
switch i.(type) {
|
||||||
|
|
@ -149,6 +160,8 @@ func (exp *exp) syncToExpvar() {
|
||||||
exp.publishMeter(name, i.(metrics.Meter))
|
exp.publishMeter(name, i.(metrics.Meter))
|
||||||
case metrics.Timer:
|
case metrics.Timer:
|
||||||
exp.publishTimer(name, i.(metrics.Timer))
|
exp.publishTimer(name, i.(metrics.Timer))
|
||||||
|
case metrics.ResettingTimer:
|
||||||
|
exp.publishResettingTimer(name, i.(metrics.ResettingTimer))
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
|
panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,17 +68,20 @@ func CollectProcessMetrics(refresh time.Duration) {
|
||||||
}
|
}
|
||||||
// Iterate loading the different stats and updating the meters
|
// Iterate loading the different stats and updating the meters
|
||||||
for i := 1; ; i++ {
|
for i := 1; ; i++ {
|
||||||
runtime.ReadMemStats(memstats[i%2])
|
location1 := i % 2
|
||||||
memAllocs.Mark(int64(memstats[i%2].Mallocs - memstats[(i-1)%2].Mallocs))
|
location2 := (i - 1) % 2
|
||||||
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))
|
|
||||||
|
|
||||||
if ReadDiskStats(diskstats[i%2]) == nil {
|
runtime.ReadMemStats(memstats[location1])
|
||||||
diskReads.Mark(diskstats[i%2].ReadCount - diskstats[(i-1)%2].ReadCount)
|
memAllocs.Mark(int64(memstats[location1].Mallocs - memstats[location2].Mallocs))
|
||||||
diskReadBytes.Mark(diskstats[i%2].ReadBytes - diskstats[(i-1)%2].ReadBytes)
|
memFrees.Mark(int64(memstats[location1].Frees - memstats[location2].Frees))
|
||||||
diskWrites.Mark(diskstats[i%2].WriteCount - diskstats[(i-1)%2].WriteCount)
|
memInuse.Mark(int64(memstats[location1].Alloc - memstats[location2].Alloc))
|
||||||
diskWriteBytes.Mark(diskstats[i%2].WriteBytes - diskstats[(i-1)%2].WriteBytes)
|
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)
|
time.Sleep(refresh)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,11 @@ type NilResettingTimer struct {
|
||||||
func (NilResettingTimer) Values() []int64 { return nil }
|
func (NilResettingTimer) Values() []int64 { return nil }
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
// Snapshot is a no-op.
|
||||||
func (NilResettingTimer) Snapshot() ResettingTimer { return NilResettingTimer{} }
|
func (NilResettingTimer) Snapshot() ResettingTimer {
|
||||||
|
return &ResettingTimerSnapshot{
|
||||||
|
values: []int64{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Time is a no-op.
|
// Time is a no-op.
|
||||||
func (NilResettingTimer) Time(func()) {}
|
func (NilResettingTimer) Time(func()) {}
|
||||||
|
|
@ -210,7 +214,7 @@ func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
|
||||||
// poor man's math.Round(x):
|
// poor man's math.Round(x):
|
||||||
// math.Floor(x + 0.5)
|
// math.Floor(x + 0.5)
|
||||||
indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 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
|
indexOfPerc -= 1 // index offset=0
|
||||||
}
|
}
|
||||||
thresholdBoundary = t.values[indexOfPerc]
|
thresholdBoundary = t.values[indexOfPerc]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ func TestTimerStop(t *testing.T) {
|
||||||
func TestTimerFunc(t *testing.T) {
|
func TestTimerFunc(t *testing.T) {
|
||||||
tm := NewTimer()
|
tm := NewTimer()
|
||||||
tm.Time(func() { time.Sleep(50e6) })
|
tm.Time(func() { time.Sleep(50e6) })
|
||||||
if max := tm.Max(); 35e6 > max || max > 95e6 {
|
if max := tm.Max(); 35e6 > max || max > 145e6 {
|
||||||
t.Errorf("tm.Max(): 35e6 > %v || %v > 95e6\n", max, max)
|
t.Errorf("tm.Max(): 35e6 > %v || %v > 145e6\n", max, max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,6 @@ func (self *worker) update() {
|
||||||
|
|
||||||
func (self *worker) wait() {
|
func (self *worker) wait() {
|
||||||
for {
|
for {
|
||||||
mustCommitNewWork := true
|
|
||||||
for result := range self.recv {
|
for result := range self.recv {
|
||||||
atomic.AddInt32(&self.atWork, -1)
|
atomic.AddInt32(&self.atWork, -1)
|
||||||
|
|
||||||
|
|
@ -322,11 +321,6 @@ func (self *worker) wait() {
|
||||||
log.Error("Failed writing block to chain", "err", err)
|
log.Error("Failed writing block to chain", "err", err)
|
||||||
continue
|
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
|
// Broadcast the block and announce chain insertion event
|
||||||
self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
||||||
var (
|
var (
|
||||||
|
|
@ -341,10 +335,6 @@ func (self *worker) wait() {
|
||||||
|
|
||||||
// Insert the block into the set of pending ones to wait for confirmations
|
// Insert the block into the set of pending ones to wait for confirmations
|
||||||
self.unconfirmed.Insert(block.NumberU64(), block.Hash())
|
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{
|
work := &Work{
|
||||||
config: self.config,
|
config: self.config,
|
||||||
signer: types.NewEIP155Signer(self.config.ChainId),
|
signer: types.NewEIP155Signer(self.config.ChainID),
|
||||||
state: state,
|
state: state,
|
||||||
ancestors: set.New(),
|
ancestors: set.New(),
|
||||||
family: set.New(),
|
family: set.New(),
|
||||||
|
|
|
||||||
30
node/api.go
30
node/api.go
|
|
@ -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:
|
default:
|
||||||
root[name] = "Unknown metric type"
|
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:
|
default:
|
||||||
root[name] = "Unknown metric type"
|
root[name] = "Unknown metric type"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ using the same data directory will store this information in different subdirect
|
||||||
the data directory.
|
the data directory.
|
||||||
|
|
||||||
LevelDB databases are also stored within the instance subdirectory. If multiple node
|
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.
|
create one database for each instance.
|
||||||
|
|
||||||
The account key store is shared among all node instances using the same data directory
|
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
|
static-nodes.json -- devp2p static node list of instance B
|
||||||
db/ -- LevelDB content for "db"
|
db/ -- LevelDB content for "db"
|
||||||
db-2/ -- LevelDB content for "db-2"
|
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
|
keystore/ -- account key store, used by both instances
|
||||||
*/
|
*/
|
||||||
package node
|
package node
|
||||||
|
|
|
||||||
|
|
@ -480,16 +480,16 @@ func (tab *Table) doRevalidate(done chan<- struct{}) {
|
||||||
b := tab.buckets[bi]
|
b := tab.buckets[bi]
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// The node responded, move it to the front.
|
// 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)
|
b.bump(last)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// No reply received, pick a replacement or delete the node if there aren't
|
// No reply received, pick a replacement or delete the node if there aren't
|
||||||
// any replacements.
|
// any replacements.
|
||||||
if r := tab.replace(b, last); r != nil {
|
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 {
|
} 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
8
p2p/discv5/metrics.go
Normal 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)
|
||||||
|
)
|
||||||
|
|
@ -334,8 +334,10 @@ func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req inter
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr))
|
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))
|
log.Trace(fmt.Sprint("UDP send failed:", err))
|
||||||
|
} else {
|
||||||
|
egressTrafficMeter.Mark(int64(nbytes))
|
||||||
}
|
}
|
||||||
//fmt.Println(err)
|
//fmt.Println(err)
|
||||||
return hash, err
|
return hash, err
|
||||||
|
|
@ -374,6 +376,7 @@ func (t *udp) readLoop() {
|
||||||
buf := make([]byte, 1280)
|
buf := make([]byte, 1280)
|
||||||
for {
|
for {
|
||||||
nbytes, from, err := t.conn.ReadFromUDP(buf)
|
nbytes, from, err := t.conn.ReadFromUDP(buf)
|
||||||
|
ingressTrafficMeter.Mark(int64(nbytes))
|
||||||
if netutil.IsTemporaryError(err) {
|
if netutil.IsTemporaryError(err) {
|
||||||
// Ignore temporary read errors.
|
// Ignore temporary read errors.
|
||||||
log.Debug(fmt.Sprintf("Temporary read error: %v", err))
|
log.Debug(fmt.Sprintf("Temporary read error: %v", err))
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"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
|
// 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
|
// but often just used to forward and push messages to directly connected peers
|
||||||
func (p *Peer) Send(msg interface{}) error {
|
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)
|
code, found := p.spec.GetCode(msg)
|
||||||
if !found {
|
if !found {
|
||||||
return errorf(ErrInvalidMsgType, "%v", code)
|
return errorf(ErrInvalidMsgType, "%v", code)
|
||||||
|
|
|
||||||
|
|
@ -373,15 +373,14 @@ WAIT:
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
func XTestMultiplePeersDropSelf(t *testing.T) {
|
||||||
func TestMultiplePeersDropSelf(t *testing.T) {
|
|
||||||
runMultiplePeers(t, 0,
|
runMultiplePeers(t, 0,
|
||||||
fmt.Errorf("subprotocol error"),
|
fmt.Errorf("subprotocol error"),
|
||||||
fmt.Errorf("Message handler error: (msg code 3): dropped"),
|
fmt.Errorf("Message handler error: (msg code 3): dropped"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiplePeersDropOther(t *testing.T) {
|
func XTestMultiplePeersDropOther(t *testing.T) {
|
||||||
runMultiplePeers(t, 1,
|
runMultiplePeers(t, 1,
|
||||||
fmt.Errorf("Message handler error: (msg code 3): dropped"),
|
fmt.Errorf("Message handler error: (msg code 3): dropped"),
|
||||||
fmt.Errorf("subprotocol error"),
|
fmt.Errorf("subprotocol error"),
|
||||||
|
|
|
||||||
|
|
@ -528,9 +528,9 @@ func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) {
|
||||||
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
|
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
|
||||||
}
|
}
|
||||||
// TODO: fewer pointless conversions
|
// TODO: fewer pointless conversions
|
||||||
pub := crypto.ToECDSAPub(pubKey65)
|
pub, err := crypto.UnmarshalPubkey(pubKey65)
|
||||||
if pub.X == nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid public key")
|
return nil, err
|
||||||
}
|
}
|
||||||
return ecies.ImportECDSAPublic(pub), nil
|
return ecies.ImportECDSAPublic(pub), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/simulations/pipes"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -159,7 +160,7 @@ func TestProtocolHandshake(t *testing.T) {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
)
|
)
|
||||||
|
|
||||||
fd0, fd1, err := tcpPipe()
|
fd0, fd1, err := pipes.TCPPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -601,31 +602,3 @@ func TestHandshakeForwardCompatibility(t *testing.T) {
|
||||||
t.Errorf("ingress-mac('foo') mismatch:\ngot %x\nwant %x", fooIngressHash, wantFooIngressHash)
|
t.Errorf("ingress-mac('foo') mismatch:\ngot %x\nwant %x", fooIngressHash, wantFooIngressHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcpPipe creates an in process full duplex pipe based on a localhost TCP socket
|
|
||||||
func tcpPipe() (net.Conn, net.Conn, error) {
|
|
||||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer l.Close()
|
|
||||||
|
|
||||||
var aconn net.Conn
|
|
||||||
aerr := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
var err error
|
|
||||||
aconn, err = l.Accept()
|
|
||||||
aerr <- err
|
|
||||||
}()
|
|
||||||
|
|
||||||
dconn, err := net.Dial("tcp", l.Addr().String())
|
|
||||||
if err != nil {
|
|
||||||
<-aerr
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if err := <-aerr; err != nil {
|
|
||||||
dconn.Close()
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return aconn, dconn, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -594,13 +594,13 @@ running:
|
||||||
// This channel is used by AddPeer to add to the
|
// This channel is used by AddPeer to add to the
|
||||||
// ephemeral static peer list. Add it to the dialer,
|
// ephemeral static peer list. Add it to the dialer,
|
||||||
// it will keep the node connected.
|
// 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)
|
dialstate.addStatic(n)
|
||||||
case n := <-srv.removestatic:
|
case n := <-srv.removestatic:
|
||||||
// This channel is used by RemovePeer to send a
|
// This channel is used by RemovePeer to send a
|
||||||
// disconnect request to a peer and begin the
|
// disconnect request to a peer and begin the
|
||||||
// stop keeping the node connected
|
// stop keeping the node connected
|
||||||
srv.log.Debug("Removing static node", "node", n)
|
srv.log.Trace("Removing static node", "node", n)
|
||||||
dialstate.removeStatic(n)
|
dialstate.removeStatic(n)
|
||||||
if p, ok := peers[n.ID]; ok {
|
if p, ok := peers[n.ID]; ok {
|
||||||
p.Disconnect(DiscRequested)
|
p.Disconnect(DiscRequested)
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/reexec"
|
"github.com/docker/docker/pkg/reexec"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"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
|
// DockerAdapter is a NodeAdapter which runs simulation nodes inside Docker
|
||||||
// containers.
|
// containers.
|
||||||
//
|
//
|
||||||
|
|
@ -52,7 +55,7 @@ func NewDockerAdapter() (*DockerAdapter, error) {
|
||||||
// It is reasonable to require this because the caller can just
|
// It is reasonable to require this because the caller can just
|
||||||
// compile the current binary in a Docker container.
|
// compile the current binary in a Docker container.
|
||||||
if runtime.GOOS != "linux" {
|
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 {
|
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.NoDiscovery = true
|
||||||
conf.Stack.P2P.NAT = nil
|
conf.Stack.P2P.NAT = nil
|
||||||
conf.Stack.NoUSB = true
|
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{
|
node := &DockerNode{
|
||||||
ExecNode: ExecNode{
|
ExecNode: ExecNode{
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue