aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml8
-rw-r--r--README.md4
-rw-r--r--VERSION2
-rw-r--r--appveyor.yml4
-rw-r--r--build/ci.go19
-rw-r--r--cmd/geth/library.c24
-rw-r--r--cmd/geth/library.go46
-rw-r--r--cmd/geth/library_android.go56
-rw-r--r--cmd/swarm/hash.go (renamed from cmd/bzzhash/main.go)19
-rw-r--r--cmd/swarm/main.go (renamed from cmd/bzzd/main.go)105
-rw-r--r--cmd/swarm/upload.go (renamed from cmd/bzzup/main.go)108
-rw-r--r--cmd/utils/cmd.go31
-rw-r--r--core/tx_pool.go14
-rw-r--r--eth/api.go19
-rw-r--r--miner/unconfirmed.go118
-rw-r--r--miner/unconfirmed_test.go85
-rw-r--r--miner/worker.go88
-rw-r--r--params/version.go2
-rw-r--r--swarm/network/protocol.go2
19 files changed, 454 insertions, 300 deletions
diff --git a/.travis.yml b/.travis.yml
index 87725251b..d13b77c17 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,15 +13,15 @@ matrix:
go: 1.6.2
- os: linux
dist: trusty
- go: 1.7
+ go: 1.7.4
- os: osx
- go: 1.7
+ go: 1.7.4
# This builder does the Ubuntu PPA and Linux Azure uploads
- os: linux
dist: trusty
sudo: required
- go: 1.7
+ go: 1.7.4
env:
- ubuntu-ppa
- azure-linux
@@ -55,7 +55,7 @@ matrix:
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
- os: osx
- go: 1.7
+ go: 1.7.4
env:
- azure-osx
- mobile
diff --git a/README.md b/README.md
index 770546010..66f59470f 100644
--- a/README.md
+++ b/README.md
@@ -39,9 +39,7 @@ The go-ethereum project comes with several wrappers/executables found in the `cm
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
-| `bzzd` | swarm daemon. This is the entrypoint for the swarm network. `bzzd --help` for command line options. See https://swarm-guide.readthedocs.io for swarm documentation. |
-| `bzzup` | swarm command line file uploader. `bzzup --help` for command line options |
-| `bzzhash` | command to calculate the swarm hash of a file or directory. `bzzhash --help` for command line options |
+| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
## Running geth
diff --git a/VERSION b/VERSION
index 9075be495..eac1e0ada 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.5.5
+1.5.6
diff --git a/appveyor.yml b/appveyor.yml
index dbdda9b6c..f5115f6f9 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -22,8 +22,8 @@ environment:
install:
- rmdir C:\go /s /q
- - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-%GETH_ARCH%.zip
- - 7z x go1.7.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
+ - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.4.windows-%GETH_ARCH%.zip
+ - 7z x go1.7.4.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version
- gcc --version
diff --git a/build/ci.go b/build/ci.go
index 602eb8239..867fc3732 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -72,9 +72,7 @@ var (
executablePath("abigen"),
executablePath("evm"),
executablePath("geth"),
- executablePath("bzzd"),
- executablePath("bzzhash"),
- executablePath("bzzup"),
+ executablePath("swarm"),
executablePath("rlpdump"),
}
@@ -93,16 +91,8 @@ var (
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
},
{
- Name: "bzzd",
- Description: "Ethereum Swarm daemon",
- },
- {
- Name: "bzzup",
- Description: "Ethereum Swarm command line file/directory uploader",
- },
- {
- Name: "bzzhash",
- Description: "Ethereum Swarm file/directory hash calculator",
+ Name: "swarm",
+ Description: "Ethereum Swarm daemon and tools",
},
{
Name: "abigen",
@@ -112,7 +102,8 @@ var (
// Distros for which packages are created.
// Note: vivid is unsupported because there is no golang-1.6 package for it.
- debDistros = []string{"trusty", "wily", "xenial", "yakkety"}
+ // Note: wily is unsupported because it was officially deprecated on lanchpad.
+ debDistros = []string{"trusty", "xenial", "yakkety"}
)
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
diff --git a/cmd/geth/library.c b/cmd/geth/library.c
deleted file mode 100644
index f738621a8..000000000
--- a/cmd/geth/library.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of go-ethereum.
-//
-// go-ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// go-ethereum 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 General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
-
-// Simple wrapper to translate the API exposed methods and types to inthernal
-// Go versions of the same types.
-
-#include "_cgo_export.h"
-
-int run(const char* args) {
- return doRun((char*)args);
-}
diff --git a/cmd/geth/library.go b/cmd/geth/library.go
deleted file mode 100644
index b8ffaaed7..000000000
--- a/cmd/geth/library.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of go-ethereum.
-//
-// go-ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// go-ethereum 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 General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
-
-// Contains a simple library definition to allow creating a Geth instance from
-// straight C code.
-
-package main
-
-// #ifdef __cplusplus
-// extern "C" {
-// #endif
-//
-// extern int run(const char*);
-//
-// #ifdef __cplusplus
-// }
-// #endif
-import "C"
-import (
- "fmt"
- "os"
- "strings"
-)
-
-//export doRun
-func doRun(args *C.char) C.int {
- // This is equivalent to geth.main, just modified to handle the function arg passing
- if err := app.Run(strings.Split("geth "+C.GoString(args), " ")); err != nil {
- fmt.Fprintln(os.Stderr, err)
- return -1
- }
- return 0
-}
diff --git a/cmd/geth/library_android.go b/cmd/geth/library_android.go
deleted file mode 100644
index fb021bfe0..000000000
--- a/cmd/geth/library_android.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of go-ethereum.
-//
-// go-ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// go-ethereum 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 General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
-
-// Contains specialized code for running Geth on Android.
-
-package main
-
-// #include <android/log.h>
-// #cgo LDFLAGS: -llog
-import "C"
-import (
- "bufio"
- "os"
-)
-
-func init() {
- // Redirect the standard output and error to logcat
- oldStdout, oldStderr := os.Stdout, os.Stderr
-
- outRead, outWrite, _ := os.Pipe()
- errRead, errWrite, _ := os.Pipe()
-
- os.Stdout = outWrite
- os.Stderr = errWrite
-
- go func() {
- scanner := bufio.NewScanner(outRead)
- for scanner.Scan() {
- line := scanner.Text()
- C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stdout"), C.CString(line))
- oldStdout.WriteString(line + "\n")
- }
- }()
-
- go func() {
- scanner := bufio.NewScanner(errRead)
- for scanner.Scan() {
- line := scanner.Text()
- C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stderr"), C.CString(line))
- oldStderr.WriteString(line + "\n")
- }
- }()
-}
diff --git a/cmd/bzzhash/main.go b/cmd/swarm/hash.go
index 0ae99acc0..0a20bea82 100644
--- a/cmd/bzzhash/main.go
+++ b/cmd/swarm/hash.go
@@ -19,22 +19,21 @@ package main
import (
"fmt"
+ "log"
"os"
- "runtime"
"github.com/ethereum/go-ethereum/swarm/storage"
+ "gopkg.in/urfave/cli.v1"
)
-func main() {
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- if len(os.Args) < 2 {
- fmt.Println("Usage: bzzhash <file name>")
- os.Exit(0)
+func hash(ctx *cli.Context) {
+ args := ctx.Args()
+ if len(args) < 1 {
+ log.Fatal("Usage: swarm hash <file name>")
}
- f, err := os.Open(os.Args[1])
+ f, err := os.Open(args[0])
if err != nil {
- fmt.Println("Error opening file " + os.Args[1])
+ fmt.Println("Error opening file " + args[1])
os.Exit(1)
}
@@ -42,7 +41,7 @@ func main() {
chunker := storage.NewTreeChunker(storage.NewChunkerParams())
key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
if err != nil {
- fmt.Fprintf(os.Stderr, "%v\n", err)
+ log.Fatalf("%v\n", err)
} else {
fmt.Printf("%v\n", key)
}
diff --git a/cmd/bzzd/main.go b/cmd/swarm/main.go
index 4bb2ca04a..04930760e 100644
--- a/cmd/bzzd/main.go
+++ b/cmd/swarm/main.go
@@ -43,11 +43,21 @@ import (
"gopkg.in/urfave/cli.v1"
)
-const clientIdentifier = "bzzd"
+const (
+ clientIdentifier = "swarm"
+ versionString = "0.2"
+)
var (
- gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
- app = utils.NewApp(gitCommit, "Ethereum Swarm server daemon")
+ gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
+ app = utils.NewApp(gitCommit, "Ethereum Swarm")
+ testbetBootNodes = []string{
+ "enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429",
+ "enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430",
+ "enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431",
+ "enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432",
+ "enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433",
+ }
)
var (
@@ -65,7 +75,7 @@ var (
}
SwarmNetworkIdFlag = cli.IntFlag{
Name: "bzznetworkid",
- Usage: "Network identifier (integer, default 322=swarm testnet)",
+ Usage: "Network identifier (integer, default 3=swarm testnet)",
Value: network.NetworkId,
}
SwarmConfigPathFlag = cli.StringFlag{
@@ -85,10 +95,25 @@ var (
Usage: "URL of the Ethereum API provider",
Value: node.DefaultIPCEndpoint("geth"),
}
+ SwarmApiFlag = cli.StringFlag{
+ Name: "bzzapi",
+ Usage: "Swarm HTTP endpoint",
+ Value: "http://127.0.0.1:8500",
+ }
+ SwarmRecursiveUploadFlag = cli.BoolFlag{
+ Name: "recursive",
+ Usage: "Upload directories recursively",
+ }
+ SwarmWantManifestFlag = cli.BoolTFlag{
+ Name: "manifest",
+ Usage: "Automatic manifest upload",
+ }
+ SwarmUploadDefaultPath = cli.StringFlag{
+ Name: "defaultpath",
+ Usage: "path to file served for empty url path (none)",
+ }
)
-var defaultBootnodes = []string{}
-
func init() {
// Override flag defaults so bzzd can run alongside geth.
utils.ListenPortFlag.Value = 30399
@@ -96,8 +121,39 @@ func init() {
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
// Set up the cli app.
- app.Commands = nil
app.Action = bzzd
+ app.HideVersion = true // we have a command to print the version
+ app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
+ app.Commands = []cli.Command{
+ cli.Command{
+ Action: version,
+ Name: "version",
+ Usage: "Print version numbers",
+ ArgsUsage: " ",
+ Description: `
+The output of this command is supposed to be machine-readable.
+`,
+ },
+ cli.Command{
+ Action: upload,
+ Name: "up",
+ Usage: "upload a file or directory to swarm using the HTTP API",
+ ArgsUsage: " <file>",
+ Description: `
+"upload a file or directory to swarm using the HTTP API and prints the root hash",
+`,
+ },
+ cli.Command{
+ Action: hash,
+ Name: "hash",
+ Usage: "print the swarm hash of a file or directory",
+ ArgsUsage: " <file>",
+ Description: `
+Prints the swarm hash of file or directory.
+`,
+ },
+ }
+
app.Flags = []cli.Flag{
utils.IdentityFlag,
utils.DataDirFlag,
@@ -123,6 +179,11 @@ func init() {
SwarmAccountFlag,
SwarmNetworkIdFlag,
ChequebookAddrFlag,
+ // upload flags
+ SwarmApiFlag,
+ SwarmRecursiveUploadFlag,
+ SwarmWantManifestFlag,
+ SwarmUploadDefaultPath,
}
app.Flags = append(app.Flags, debug.Flags...)
app.Before = func(ctx *cli.Context) error {
@@ -142,17 +203,33 @@ func main() {
}
}
+func version(ctx *cli.Context) error {
+ fmt.Println(strings.Title(clientIdentifier))
+ fmt.Println("Version:", versionString)
+ if gitCommit != "" {
+ fmt.Println("Git Commit:", gitCommit)
+ }
+ fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name))
+ fmt.Println("Go Version:", runtime.Version())
+ fmt.Println("OS:", runtime.GOOS)
+ fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
+ fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
+ return nil
+}
+
func bzzd(ctx *cli.Context) error {
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
registerBzzService(ctx, stack)
utils.StartNode(stack)
-
+ networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name)
// Add bootnodes as initial peers.
if ctx.GlobalIsSet(utils.BootnodesFlag.Name) {
bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",")
injectBootnodes(stack.Server(), bootnodes)
} else {
- injectBootnodes(stack.Server(), defaultBootnodes)
+ if networkId == 3 {
+ injectBootnodes(stack.Server(), testbetBootNodes)
+ }
}
stack.Wait()
@@ -182,13 +259,11 @@ func registerBzzService(ctx *cli.Context, stack *node.Node) {
boot := func(ctx *node.ServiceContext) (node.Service, error) {
var client *ethclient.Client
- if ethapi == "" {
- err = fmt.Errorf("use ethapi flag to connect to a an eth client and talk to the blockchain")
- } else {
+ if len(ethapi) > 0 {
client, err = ethclient.Dial(ethapi)
- }
- if err != nil {
- utils.Fatalf("Can't connect: %v", err)
+ if err != nil {
+ utils.Fatalf("Can't connect: %v", err)
+ }
}
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled)
}
diff --git a/cmd/bzzup/main.go b/cmd/swarm/upload.go
index 7d251aadb..d048bbc40 100644
--- a/cmd/bzzup/main.go
+++ b/cmd/swarm/upload.go
@@ -20,7 +20,6 @@ package main
import (
"bytes"
"encoding/json"
- "flag"
"fmt"
"io"
"io/ioutil"
@@ -28,58 +27,83 @@ import (
"mime"
"net/http"
"os"
+ "os/user"
+ "path"
"path/filepath"
"strings"
+
+ "gopkg.in/urfave/cli.v1"
)
-func main() {
+func upload(ctx *cli.Context) {
+ args := ctx.Args()
var (
- bzzapiFlag = flag.String("bzzapi", "http://127.0.0.1:8500", "Swarm HTTP endpoint")
- recursiveFlag = flag.Bool("recursive", false, "Upload directories recursively")
- manifestFlag = flag.Bool("manifest", true, "Skip automatic manifest upload")
+ bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+ recursive = ctx.GlobalBool(SwarmRecursiveUploadFlag.Name)
+ wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
+ defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name)
)
- log.SetOutput(os.Stderr)
- log.SetFlags(0)
- flag.Parse()
- if flag.NArg() != 1 {
+ if len(args) != 1 {
log.Fatal("need filename as the first and only argument")
}
var (
- file = flag.Arg(0)
- client = &client{api: *bzzapiFlag}
+ file = args[0]
+ client = &client{api: bzzapi}
mroot manifest
+ entry manifestEntry
)
- fi, err := os.Stat(file)
+ fi, err := os.Stat(expandPath(file))
if err != nil {
log.Fatal(err)
}
if fi.IsDir() {
- if !*recursiveFlag {
+ if !recursive {
log.Fatal("argument is a directory and recursive upload is disabled")
}
- mroot, err = client.uploadDirectory(file)
+ mroot, err = client.uploadDirectory(file, defaultPath)
} else {
- mroot, err = client.uploadFile(file, fi)
- if *manifestFlag {
- // Wrap the raw file entry in a proper manifest so both hashes get printed.
- mroot = manifest{Entries: []manifest{mroot}}
- }
+ entry, err = client.uploadFile(file, fi)
+ mroot = manifest{[]manifestEntry{entry}}
}
if err != nil {
log.Fatalln("upload failed:", err)
}
- if *manifestFlag {
- hash, err := client.uploadManifest(mroot)
- if err != nil {
- log.Fatalln("manifest upload failed:", err)
+ if !wantManifest {
+ // Print the manifest. This is the only output to stdout.
+ mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
+ fmt.Println(string(mrootJSON))
+ return
+ }
+ hash, err := client.uploadManifest(mroot)
+ if err != nil {
+ log.Fatalln("manifest upload failed:", err)
+ }
+ fmt.Println(hash)
+}
+
+// Expands a file path
+// 1. replace tilde with users home dir
+// 2. expands embedded environment variables
+// 3. cleans the path, e.g. /a/b/../c -> /a/c
+// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
+func expandPath(p string) string {
+ if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
+ if home := homeDir(); home != "" {
+ p = home + p[1:]
}
- mroot.Hash = hash
}
+ return path.Clean(os.ExpandEnv(p))
+}
- // Print the manifest. This is the only output to stdout.
- mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
- fmt.Println(string(mrootJSON))
+func homeDir() string {
+ if home := os.Getenv("HOME"); home != "" {
+ return home
+ }
+ if usr, err := user.Current(); err == nil {
+ return usr.HomeDir
+ }
+ return ""
}
// client wraps interaction with the swarm HTTP gateway.
@@ -88,24 +112,40 @@ type client struct {
}
// manifest is the JSON representation of a swarm manifest.
+type manifestEntry struct {
+ Hash string `json:"hash,omitempty"`
+ ContentType string `json:"contentType,omitempty"`
+ Path string `json:"path,omitempty"`
+}
+
+// manifest is the JSON representation of a swarm manifest.
type manifest struct {
- Hash string `json:"hash,omitempty"`
- ContentType string `json:"contentType,omitempty"`
- Path string `json:"path,omitempty"`
- Entries []manifest `json:"entries,omitempty"`
+ Entries []manifestEntry `json:"entries,omitempty"`
}
-func (c *client) uploadFile(file string, fi os.FileInfo) (manifest, error) {
+func (c *client) uploadFile(file string, fi os.FileInfo) (manifestEntry, error) {
hash, err := c.uploadFileContent(file, fi)
- m := manifest{
+ m := manifestEntry{
Hash: hash,
ContentType: mime.TypeByExtension(filepath.Ext(fi.Name())),
}
return m, err
}
-func (c *client) uploadDirectory(dir string) (manifest, error) {
+func (c *client) uploadDirectory(dir string, defaultPath string) (manifest, error) {
dirm := manifest{}
+ if len(defaultPath) > 0 {
+ fi, err := os.Stat(defaultPath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ entry, err := c.uploadFile(defaultPath, fi)
+ if err != nil {
+ log.Fatal(err)
+ }
+ entry.Path = ""
+ dirm.Entries = append(dirm.Entries, entry)
+ }
prefix := filepath.ToSlash(filepath.Clean(dir)) + "/"
err := filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || fi.IsDir() {
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index 584afc804..a56507e4d 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -18,12 +18,14 @@
package utils
import (
+ "compress/gzip"
"fmt"
"io"
"os"
"os/signal"
"regexp"
"runtime"
+ "strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -133,7 +135,15 @@ func ImportChain(chain *core.BlockChain, fn string) error {
return err
}
defer fh.Close()
- stream := rlp.NewStream(fh, 0)
+
+ var reader io.Reader = fh
+ if strings.HasSuffix(fn, ".gz") {
+ if reader, err = gzip.NewReader(reader); err != nil {
+ return err
+ }
+ }
+
+ stream := rlp.NewStream(reader, 0)
// Run actual the import.
blocks := make(types.Blocks, importBatchSize)
@@ -195,10 +205,18 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
return err
}
defer fh.Close()
- if err := blockchain.Export(fh); err != nil {
+
+ var writer io.Writer = fh
+ if strings.HasSuffix(fn, ".gz") {
+ writer = gzip.NewWriter(writer)
+ defer writer.(*gzip.Writer).Close()
+ }
+
+ if err := blockchain.Export(writer); err != nil {
return err
}
glog.Infoln("Exported blockchain to ", fn)
+
return nil
}
@@ -210,7 +228,14 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
return err
}
defer fh.Close()
- if err := blockchain.ExportN(fh, first, last); err != nil {
+
+ var writer io.Writer = fh
+ if strings.HasSuffix(fn, ".gz") {
+ writer = gzip.NewWriter(writer)
+ defer writer.(*gzip.Writer).Close()
+ }
+
+ if err := blockchain.ExportN(writer, first, last); err != nil {
return err
}
glog.Infoln("Exported blockchain to ", fn)
diff --git a/core/tx_pool.go b/core/tx_pool.go
index b805cf226..65e076df9 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -124,6 +124,8 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState
quit: make(chan struct{}),
}
+ pool.resetState()
+
pool.wg.Add(2)
go pool.eventLoop()
go pool.expirationLoop()
@@ -196,12 +198,8 @@ func (pool *TxPool) Stop() {
}
func (pool *TxPool) State() *state.ManagedState {
- pool.mu.Lock()
- defer pool.mu.Unlock()
-
- if pool.pendingState == nil {
- pool.resetState()
- }
+ pool.mu.RLock()
+ defer pool.mu.RUnlock()
return pool.pendingState
}
@@ -381,10 +379,6 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
//
// Note, this method assumes the pool lock is held!
func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) {
- // Init delayed since tx pool could have been started before any state sync
- if pool.pendingState == nil {
- pool.resetState()
- }
// Try to insert the transaction into the pending queue
if pool.pending[addr] == nil {
pool.pending[addr] = newTxList(true)
diff --git a/eth/api.go b/eth/api.go
index a86ed95cf..0a1d097e3 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -18,6 +18,7 @@ package eth
import (
"bytes"
+ "compress/gzip"
"errors"
"fmt"
"io"
@@ -25,6 +26,7 @@ import (
"math/big"
"os"
"runtime"
+ "strings"
"time"
"github.com/ethereum/ethash"
@@ -217,8 +219,14 @@ func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
}
defer out.Close()
+ var writer io.Writer = out
+ if strings.HasSuffix(file, ".gz") {
+ writer = gzip.NewWriter(writer)
+ defer writer.(*gzip.Writer).Close()
+ }
+
// Export the blockchain
- if err := api.eth.BlockChain().Export(out); err != nil {
+ if err := api.eth.BlockChain().Export(writer); err != nil {
return false, err
}
return true, nil
@@ -243,8 +251,15 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) {
}
defer in.Close()
+ var reader io.Reader = in
+ if strings.HasSuffix(file, ".gz") {
+ if reader, err = gzip.NewReader(reader); err != nil {
+ return false, err
+ }
+ }
+
// Run actual the import in pre-configured batches
- stream := rlp.NewStream(in, 0)
+ stream := rlp.NewStream(reader, 0)
blocks, index := make([]*types.Block, 0, 2500), 0
for batch := 0; ; batch++ {
diff --git a/miner/unconfirmed.go b/miner/unconfirmed.go
new file mode 100644
index 000000000..86a30de35
--- /dev/null
+++ b/miner/unconfirmed.go
@@ -0,0 +1,118 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package miner
+
+import (
+ "container/ring"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
+)
+
+// headerRetriever is used by the unconfirmed block set to verify whether a previously
+// mined block is part of the canonical chain or not.
+type headerRetriever interface {
+ // GetHeaderByNumber retrieves the canonical header associated with a block number.
+ GetHeaderByNumber(number uint64) *types.Header
+}
+
+// unconfirmedBlock is a small collection of metadata about a locally mined block
+// that is placed into a unconfirmed set for canonical chain inclusion tracking.
+type unconfirmedBlock struct {
+ index uint64
+ hash common.Hash
+}
+
+// unconfirmedBlocks implements a data structure to maintain locally mined blocks
+// have have not yet reached enough maturity to guarantee chain inclusion. It is
+// used by the miner to provide logs to the user when a previously mined block
+// has a high enough guarantee to not be reorged out of te canonical chain.
+type unconfirmedBlocks struct {
+ chain headerRetriever // Blockchain to verify canonical status through
+ depth uint // Depth after which to discard previous blocks
+ blocks *ring.Ring // Block infos to allow canonical chain cross checks
+ lock sync.RWMutex // Protects the fields from concurrent access
+}
+
+// newUnconfirmedBlocks returns new data structure to track currently unconfirmed blocks.
+func newUnconfirmedBlocks(chain headerRetriever, depth uint) *unconfirmedBlocks {
+ return &unconfirmedBlocks{
+ chain: chain,
+ depth: depth,
+ }
+}
+
+// Insert adds a new block to the set of unconfirmed ones.
+func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) {
+ // If a new block was mined locally, shift out any old enough blocks
+ set.Shift(index)
+
+ // Create the new item as its own ring
+ item := ring.New(1)
+ item.Value = &unconfirmedBlock{
+ index: index,
+ hash: hash,
+ }
+ // Set as the initial ring or append to the end
+ set.lock.Lock()
+ defer set.lock.Unlock()
+
+ if set.blocks == nil {
+ set.blocks = item
+ } else {
+ set.blocks.Move(-1).Link(item)
+ }
+ // Display a log for the user to notify of a new mined block unconfirmed
+ glog.V(logger.Info).Infof("🔨 mined potential block #%d [%x…], waiting for %d blocks to confirm", index, hash.Bytes()[:4], set.depth)
+}
+
+// Shift drops all unconfirmed blocks from the set which exceed the unconfirmed sets depth
+// allowance, checking them against the canonical chain for inclusion or staleness
+// report.
+func (set *unconfirmedBlocks) Shift(height uint64) {
+ set.lock.Lock()
+ defer set.lock.Unlock()
+
+ for set.blocks != nil {
+ // Retrieve the next unconfirmed block and abort if too fresh
+ next := set.blocks.Value.(*unconfirmedBlock)
+ if next.index+uint64(set.depth) > height {
+ break
+ }
+ // Block seems to exceed depth allowance, check for canonical status
+ header := set.chain.GetHeaderByNumber(next.index)
+ switch {
+ case header == nil:
+ glog.V(logger.Warn).Infof("failed to retrieve header of mined block #%d [%x…]", next.index, next.hash.Bytes()[:4])
+ case header.Hash() == next.hash:
+ glog.V(logger.Info).Infof("🔗 mined block #%d [%x…] reached canonical chain", next.index, next.hash.Bytes()[:4])
+ default:
+ glog.V(logger.Info).Infof("⑂ mined block #%d [%x…] became a side fork", next.index, next.hash.Bytes()[:4])
+ }
+ // Drop the block out of the ring
+ if set.blocks.Value == set.blocks.Next().Value {
+ set.blocks = nil
+ } else {
+ set.blocks = set.blocks.Move(-1)
+ set.blocks.Unlink(1)
+ set.blocks = set.blocks.Move(1)
+ }
+ }
+}
diff --git a/miner/unconfirmed_test.go b/miner/unconfirmed_test.go
new file mode 100644
index 000000000..456af1764
--- /dev/null
+++ b/miner/unconfirmed_test.go
@@ -0,0 +1,85 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package miner
+
+import (
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+// noopHeaderRetriever is an implementation of headerRetriever that always
+// returns nil for any requested headers.
+type noopHeaderRetriever struct{}
+
+func (r *noopHeaderRetriever) GetHeaderByNumber(number uint64) *types.Header {
+ return nil
+}
+
+// Tests that inserting blocks into the unconfirmed set accumulates them until
+// the desired depth is reached, after which they begin to be dropped.
+func TestUnconfirmedInsertBounds(t *testing.T) {
+ limit := uint(10)
+
+ pool := newUnconfirmedBlocks(new(noopHeaderRetriever), limit)
+ for depth := uint64(0); depth < 2*uint64(limit); depth++ {
+ // Insert multiple blocks for the same level just to stress it
+ for i := 0; i < int(depth); i++ {
+ pool.Insert(depth, common.Hash([32]byte{byte(depth), byte(i)}))
+ }
+ // Validate that no blocks below the depth allowance are left in
+ pool.blocks.Do(func(block interface{}) {
+ if block := block.(*unconfirmedBlock); block.index+uint64(limit) <= depth {
+ t.Errorf("depth %d: block %x not dropped", depth, block.hash)
+ }
+ })
+ }
+}
+
+// Tests that shifting blocks out of the unconfirmed set works both for normal
+// cases as well as for corner cases such as empty sets, empty shifts or full
+// shifts.
+func TestUnconfirmedShifts(t *testing.T) {
+ // Create a pool with a few blocks on various depths
+ limit, start := uint(10), uint64(25)
+
+ pool := newUnconfirmedBlocks(new(noopHeaderRetriever), limit)
+ for depth := start; depth < start+uint64(limit); depth++ {
+ pool.Insert(depth, common.Hash([32]byte{byte(depth)}))
+ }
+ // Try to shift below the limit and ensure no blocks are dropped
+ pool.Shift(start + uint64(limit) - 1)
+ if n := pool.blocks.Len(); n != int(limit) {
+ t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit)
+ }
+ // Try to shift half the blocks out and verify remainder
+ pool.Shift(start + uint64(limit) - 1 + uint64(limit/2))
+ if n := pool.blocks.Len(); n != int(limit)/2 {
+ t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit/2)
+ }
+ // Try to shift all the remaining blocks out and verify emptyness
+ pool.Shift(start + 2*uint64(limit))
+ if n := pool.blocks.Len(); n != 0 {
+ t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0)
+ }
+ // Try to shift out from the empty set and make sure it doesn't break
+ pool.Shift(start + 3*uint64(limit))
+ if n := pool.blocks.Len(); n != 0 {
+ t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0)
+ }
+}
diff --git a/miner/worker.go b/miner/worker.go
index fdc6b7d8e..f29566c0a 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -55,26 +55,20 @@ type Agent interface {
GetHashRate() int64
}
-type uint64RingBuffer struct {
- ints []uint64 //array of all integers in buffer
- next int //where is the next insertion? assert 0 <= next < len(ints)
-}
-
// Work is the workers current environment and holds
// all of the current state information
type Work struct {
config *params.ChainConfig
signer types.Signer
- state *state.StateDB // apply state changes here
- ancestors *set.Set // ancestor set (used for checking uncle parent validity)
- family *set.Set // family set (used for checking uncle invalidity)
- uncles *set.Set // uncle set
- tcount int // tx count in cycle
- ownedAccounts *set.Set
- lowGasTxs types.Transactions
- failedTxs types.Transactions
- localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
+ state *state.StateDB // apply state changes here
+ ancestors *set.Set // ancestor set (used for checking uncle parent validity)
+ family *set.Set // family set (used for checking uncle invalidity)
+ uncles *set.Set // uncle set
+ tcount int // tx count in cycle
+ ownedAccounts *set.Set
+ lowGasTxs types.Transactions
+ failedTxs types.Transactions
Block *types.Block // the new block
@@ -123,6 +117,8 @@ type worker struct {
txQueueMu sync.Mutex
txQueue map[common.Hash]*types.Transaction
+ unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations
+
// atomic status counters
mining int32
atWork int32
@@ -144,6 +140,7 @@ func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend,
coinbase: coinbase,
txQueue: make(map[common.Hash]*types.Transaction),
agents: make(map[Agent]struct{}),
+ unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), 5),
fullValidation: false,
}
worker.events = worker.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{})
@@ -269,18 +266,6 @@ func (self *worker) update() {
}
}
-func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *uint64RingBuffer) (minedBlocks *uint64RingBuffer) {
- if prevMinedBlocks == nil {
- minedBlocks = &uint64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth+1)}
- } else {
- minedBlocks = prevMinedBlocks
- }
-
- minedBlocks.ints[minedBlocks.next] = blockNumber
- minedBlocks.next = (minedBlocks.next + 1) % len(minedBlocks.ints)
- return minedBlocks
-}
-
func (self *worker) wait() {
for {
mustCommitNewWork := true
@@ -355,17 +340,8 @@ func (self *worker) wait() {
}
}(block, work.state.Logs(), work.receipts)
}
-
- // check staleness and display confirmation
- var stale, confirm string
- canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
- if canonBlock != nil && canonBlock.Hash() != block.Hash() {
- stale = "stale "
- } else {
- confirm = "Wait 5 blocks for confirmation"
- work.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), work.localMinedBlocks)
- }
- glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)
+ // Insert the block into the set of pending ones to wait for confirmations
+ self.unconfirmed.Insert(block.NumberU64(), block.Hash())
if mustCommitNewWork {
self.commitNewWork()
@@ -417,9 +393,6 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
// Keep track of transactions which return errors so they can be removed
work.tcount = 0
work.ownedAccounts = accountAddressesSet(accounts)
- if self.current != nil {
- work.localMinedBlocks = self.current.localMinedBlocks
- }
self.current = work
return nil
}
@@ -435,38 +408,6 @@ func (w *worker) setGasPrice(p *big.Int) {
w.mux.Post(core.GasPriceChanged{Price: w.gasPrice})
}
-func (self *worker) isBlockLocallyMined(current *Work, deepBlockNum uint64) bool {
- //Did this instance mine a block at {deepBlockNum} ?
- var isLocal = false
- for idx, blockNum := range current.localMinedBlocks.ints {
- if deepBlockNum == blockNum {
- isLocal = true
- current.localMinedBlocks.ints[idx] = 0 //prevent showing duplicate logs
- break
- }
- }
- //Short-circuit on false, because the previous and following tests must both be true
- if !isLocal {
- return false
- }
-
- //Does the block at {deepBlockNum} send earnings to my coinbase?
- var block = self.chain.GetBlockByNumber(deepBlockNum)
- return block != nil && block.Coinbase() == self.coinbase
-}
-
-func (self *worker) logLocalMinedBlocks(current, previous *Work) {
- if previous != nil && current.localMinedBlocks != nil {
- nextBlockNum := current.Block.NumberU64()
- for checkBlockNum := previous.Block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
- inspectBlockNum := checkBlockNum - miningLogAtDepth
- if self.isBlockLocallyMined(current, inspectBlockNum) {
- glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum)
- }
- }
- }
-}
-
func (self *worker) commitNewWork() {
self.mu.Lock()
defer self.mu.Unlock()
@@ -513,7 +454,6 @@ func (self *worker) commitNewWork() {
}
}
}
- previous := self.current
// Could potentially happen if starting to mine in an odd state.
err := self.makeCurrent(parent, header)
if err != nil {
@@ -574,7 +514,7 @@ func (self *worker) commitNewWork() {
// We only care about logging if we're actually mining.
if atomic.LoadInt32(&self.mining) == 1 {
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart))
- self.logLocalMinedBlocks(work, previous)
+ self.unconfirmed.Shift(work.Block.NumberU64() - 1)
}
self.push(work)
}
diff --git a/params/version.go b/params/version.go
index f8c0d3c9a..ba7a57381 100644
--- a/params/version.go
+++ b/params/version.go
@@ -21,7 +21,7 @@ import "fmt"
const (
VersionMajor = 1 // Major version component of the current release
VersionMinor = 5 // Minor version component of the current release
- VersionPatch = 5 // Patch version component of the current release
+ VersionPatch = 6 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string
)
diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go
index a3ffd338f..4fffaac6d 100644
--- a/swarm/network/protocol.go
+++ b/swarm/network/protocol.go
@@ -51,7 +51,7 @@ const (
Version = 0
ProtocolLength = uint64(8)
ProtocolMaxMsgSize = 10 * 1024 * 1024
- NetworkId = 322
+ NetworkId = 3
)
const (