aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml11
-rw-r--r--README.md1
-rw-r--r--build/ci.go6
-rw-r--r--cmd/puppeth/genesis.go28
-rw-r--r--consensus/ethash/algorithm.go43
-rw-r--r--consensus/ethash/algorithm_go1.7.go47
-rw-r--r--consensus/ethash/algorithm_go1.8.go63
-rw-r--r--consensus/ethash/algorithm_go1.8_test.go37
-rw-r--r--consensus/ethash/algorithm_test.go16
-rw-r--r--consensus/ethash/consensus.go10
-rw-r--r--core/asm/lexer.go4
-rw-r--r--eth/handler.go3
-rw-r--r--internal/ethapi/api.go4
-rw-r--r--les/handler.go3
-rw-r--r--node/api.go10
-rw-r--r--swarm/api/http/error.go43
-rw-r--r--swarm/api/http/error_templates.go11
-rw-r--r--swarm/api/http/error_test.go40
-rw-r--r--swarm/api/http/server.go22
20 files changed, 195 insertions, 210 deletions
diff --git a/.gitignore b/.gitignore
index 0763d8492..b8d292901 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,9 @@ profile.cov
# IdeaIDE
.idea
+# VS Code
+.vscode
+
# dashboard
/dashboard/assets/flow-typed
/dashboard/assets/node_modules
diff --git a/.travis.yml b/.travis.yml
index 3941fa785..a76a78954 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,17 +6,6 @@ matrix:
- os: linux
dist: trusty
sudo: required
- go: 1.7.x
- script:
- - sudo modprobe fuse
- - sudo chmod 666 /dev/fuse
- - sudo chown root:$USER /etc/fuse.conf
- - go run build/ci.go install
- - go run build/ci.go test -coverage
-
- - os: linux
- dist: trusty
- sudo: required
go: 1.8.x
script:
- sudo modprobe fuse
diff --git a/README.md b/README.md
index aad14ed7d..3d0d4d35d 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@ Official golang implementation of the Ethereum protocol.
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/ethereum/go-ethereum)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
+[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Automated builds are available for stable releases and the unstable master branch.
diff --git a/build/ci.go b/build/ci.go
index 544483c42..24b58c1ae 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -182,13 +182,13 @@ func doInstall(cmdline []string) {
// Check Go version. People regularly open issues about compilation
// failure with outdated Go. This should save them the trouble.
if !strings.Contains(runtime.Version(), "devel") {
- // Figure out the minor version number since we can't textually compare (1.10 < 1.7)
+ // Figure out the minor version number since we can't textually compare (1.10 < 1.8)
var minor int
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
- if minor < 7 {
+ if minor < 8 {
log.Println("You have Go version", runtime.Version())
- log.Println("go-ethereum requires at least Go version 1.7 and cannot")
+ log.Println("go-ethereum requires at least Go version 1.8 and cannot")
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
os.Exit(1)
}
diff --git a/cmd/puppeth/genesis.go b/cmd/puppeth/genesis.go
index f747f4739..1974a94aa 100644
--- a/cmd/puppeth/genesis.go
+++ b/cmd/puppeth/genesis.go
@@ -168,19 +168,18 @@ type parityChainSpec struct {
Engine struct {
Ethash struct {
Params struct {
- MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"`
- DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"`
- GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"`
- DurationLimit *hexutil.Big `json:"durationLimit"`
- BlockReward *hexutil.Big `json:"blockReward"`
- HomesteadTransition uint64 `json:"homesteadTransition"`
- EIP150Transition uint64 `json:"eip150Transition"`
- EIP160Transition uint64 `json:"eip160Transition"`
- EIP161abcTransition uint64 `json:"eip161abcTransition"`
- EIP161dTransition uint64 `json:"eip161dTransition"`
- EIP649Reward *hexutil.Big `json:"eip649Reward"`
- EIP100bTransition uint64 `json:"eip100bTransition"`
- EIP649Transition uint64 `json:"eip649Transition"`
+ MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"`
+ DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"`
+ DurationLimit *hexutil.Big `json:"durationLimit"`
+ BlockReward *hexutil.Big `json:"blockReward"`
+ HomesteadTransition uint64 `json:"homesteadTransition"`
+ EIP150Transition uint64 `json:"eip150Transition"`
+ EIP160Transition uint64 `json:"eip160Transition"`
+ EIP161abcTransition uint64 `json:"eip161abcTransition"`
+ EIP161dTransition uint64 `json:"eip161dTransition"`
+ EIP649Reward *hexutil.Big `json:"eip649Reward"`
+ EIP100bTransition uint64 `json:"eip100bTransition"`
+ EIP649Transition uint64 `json:"eip649Transition"`
} `json:"params"`
} `json:"Ethash"`
} `json:"engine"`
@@ -188,6 +187,7 @@ type parityChainSpec struct {
Params struct {
MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"`
MinGasLimit hexutil.Uint64 `json:"minGasLimit"`
+ GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"`
NetworkID hexutil.Uint64 `json:"networkID"`
MaxCodeSize uint64 `json:"maxCodeSize"`
EIP155Transition uint64 `json:"eip155Transition"`
@@ -270,7 +270,6 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
}
spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty)
spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor)
- spec.Engine.Ethash.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit)
spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward)
spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64()
@@ -284,6 +283,7 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
+ spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64())
spec.Params.MaxCodeSize = params.MaxCodeSize
spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()
diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go
index 10767bb31..905a7b1ea 100644
--- a/consensus/ethash/algorithm.go
+++ b/consensus/ethash/algorithm.go
@@ -19,6 +19,7 @@ package ethash
import (
"encoding/binary"
"hash"
+ "math/big"
"reflect"
"runtime"
"sync"
@@ -47,6 +48,48 @@ const (
loopAccesses = 64 // Number of accesses in hashimoto loop
)
+// cacheSize returns the size of the ethash verification cache that belongs to a certain
+// block number.
+func cacheSize(block uint64) uint64 {
+ epoch := int(block / epochLength)
+ if epoch < maxEpoch {
+ return cacheSizes[epoch]
+ }
+ return calcCacheSize(epoch)
+}
+
+// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
+// however, we always take the highest prime below the linearly growing threshold in order
+// to reduce the risk of accidental regularities leading to cyclic behavior.
+func calcCacheSize(epoch int) uint64 {
+ size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
+ for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
+ size -= 2 * hashBytes
+ }
+ return size
+}
+
+// datasetSize returns the size of the ethash mining dataset that belongs to a certain
+// block number.
+func datasetSize(block uint64) uint64 {
+ epoch := int(block / epochLength)
+ if epoch < maxEpoch {
+ return datasetSizes[epoch]
+ }
+ return calcDatasetSize(epoch)
+}
+
+// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
+// however, we always take the highest prime below the linearly growing threshold in order
+// to reduce the risk of accidental regularities leading to cyclic behavior.
+func calcDatasetSize(epoch int) uint64 {
+ size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
+ for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
+ size -= 2 * mixBytes
+ }
+ return size
+}
+
// hasher is a repetitive hasher allowing the same hash data structures to be
// reused between hash runs instead of requiring new ones to be created.
type hasher func(dest []byte, data []byte)
diff --git a/consensus/ethash/algorithm_go1.7.go b/consensus/ethash/algorithm_go1.7.go
deleted file mode 100644
index c7f7f48e4..000000000
--- a/consensus/ethash/algorithm_go1.7.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-// +build !go1.8
-
-package ethash
-
-// cacheSize calculates and returns the size of the ethash verification cache that
-// belongs to a certain block number. The cache size grows linearly, however, we
-// always take the highest prime below the linearly growing threshold in order to
-// reduce the risk of accidental regularities leading to cyclic behavior.
-func cacheSize(block uint64) uint64 {
- // If we have a pre-generated value, use that
- epoch := int(block / epochLength)
- if epoch < maxEpoch {
- return cacheSizes[epoch]
- }
- // We don't have a way to verify primes fast before Go 1.8
- panic("fast prime testing unsupported in Go < 1.8")
-}
-
-// datasetSize calculates and returns the size of the ethash mining dataset that
-// belongs to a certain block number. The dataset size grows linearly, however, we
-// always take the highest prime below the linearly growing threshold in order to
-// reduce the risk of accidental regularities leading to cyclic behavior.
-func datasetSize(block uint64) uint64 {
- // If we have a pre-generated value, use that
- epoch := int(block / epochLength)
- if epoch < maxEpoch {
- return datasetSizes[epoch]
- }
- // We don't have a way to verify primes fast before Go 1.8
- panic("fast prime testing unsupported in Go < 1.8")
-}
diff --git a/consensus/ethash/algorithm_go1.8.go b/consensus/ethash/algorithm_go1.8.go
deleted file mode 100644
index 975fdffe5..000000000
--- a/consensus/ethash/algorithm_go1.8.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-// +build go1.8
-
-package ethash
-
-import "math/big"
-
-// cacheSize returns the size of the ethash verification cache that belongs to a certain
-// block number.
-func cacheSize(block uint64) uint64 {
- epoch := int(block / epochLength)
- if epoch < maxEpoch {
- return cacheSizes[epoch]
- }
- return calcCacheSize(epoch)
-}
-
-// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
-// however, we always take the highest prime below the linearly growing threshold in order
-// to reduce the risk of accidental regularities leading to cyclic behavior.
-func calcCacheSize(epoch int) uint64 {
- size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
- for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
- size -= 2 * hashBytes
- }
- return size
-}
-
-// datasetSize returns the size of the ethash mining dataset that belongs to a certain
-// block number.
-func datasetSize(block uint64) uint64 {
- epoch := int(block / epochLength)
- if epoch < maxEpoch {
- return datasetSizes[epoch]
- }
- return calcDatasetSize(epoch)
-}
-
-// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
-// however, we always take the highest prime below the linearly growing threshold in order
-// to reduce the risk of accidental regularities leading to cyclic behavior.
-func calcDatasetSize(epoch int) uint64 {
- size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
- for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
- size -= 2 * mixBytes
- }
- return size
-}
diff --git a/consensus/ethash/algorithm_go1.8_test.go b/consensus/ethash/algorithm_go1.8_test.go
deleted file mode 100644
index 6648bd6a9..000000000
--- a/consensus/ethash/algorithm_go1.8_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-// +build go1.8
-
-package ethash
-
-import "testing"
-
-// Tests whether the dataset size calculator works correctly by cross checking the
-// hard coded lookup table with the value generated by it.
-func TestSizeCalculations(t *testing.T) {
- // Verify all the cache and dataset sizes from the lookup table.
- for epoch, want := range cacheSizes {
- if size := calcCacheSize(epoch); size != want {
- t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want)
- }
- }
- for epoch, want := range datasetSizes {
- if size := calcDatasetSize(epoch); size != want {
- t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want)
- }
- }
-}
diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go
index a54f3b582..841e39233 100644
--- a/consensus/ethash/algorithm_test.go
+++ b/consensus/ethash/algorithm_test.go
@@ -30,6 +30,22 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)
+// Tests whether the dataset size calculator works correctly by cross checking the
+// hard coded lookup table with the value generated by it.
+func TestSizeCalculations(t *testing.T) {
+ // Verify all the cache and dataset sizes from the lookup table.
+ for epoch, want := range cacheSizes {
+ if size := calcCacheSize(epoch); size != want {
+ t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want)
+ }
+ }
+ for epoch, want := range datasetSizes {
+ if size := calcDatasetSize(epoch); size != want {
+ t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want)
+ }
+ }
+}
+
// Tests that verification caches can be correctly generated.
func TestCacheGeneration(t *testing.T) {
tests := []struct {
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index 92a23d4a4..3f860bf47 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -53,7 +53,6 @@ var (
errDuplicateUncle = errors.New("duplicate uncle")
errUncleIsAncestor = errors.New("uncle is ancestor")
errDanglingUncle = errors.New("uncle's parent is not ancestor")
- errNonceOutOfRange = errors.New("nonce out of range")
errInvalidDifficulty = errors.New("non-positive difficulty")
errInvalidMixDigest = errors.New("invalid mix digest")
errInvalidPoW = errors.New("invalid proof-of-work")
@@ -474,18 +473,13 @@ func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Head
if ethash.shared != nil {
return ethash.shared.VerifySeal(chain, header)
}
- // Sanity check that the block number is below the lookup table size (60M blocks)
- number := header.Number.Uint64()
- if number/epochLength >= maxEpoch {
- // Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check)
- return errNonceOutOfRange
- }
// Ensure that we have a valid difficulty for the block
if header.Difficulty.Sign() <= 0 {
return errInvalidDifficulty
}
-
// Recompute the digest and PoW value and verify against the header
+ number := header.Number.Uint64()
+
cache := ethash.cache(number)
size := datasetSize(number)
if ethash.config.PowMode == ModeTest {
diff --git a/core/asm/lexer.go b/core/asm/lexer.go
index a34b2cbd8..405499950 100644
--- a/core/asm/lexer.go
+++ b/core/asm/lexer.go
@@ -206,7 +206,7 @@ func lexLine(l *lexer) stateFn {
return lexComment
case isSpace(r):
l.ignore()
- case isAlphaNumeric(r) || r == '_':
+ case isLetter(r) || r == '_':
return lexElement
case isNumber(r):
return lexNumber
@@ -278,7 +278,7 @@ func lexElement(l *lexer) stateFn {
return lexLine
}
-func isAlphaNumeric(t rune) bool {
+func isLetter(t rune) bool {
return unicode.IsLetter(t)
}
diff --git a/eth/handler.go b/eth/handler.go
index c2426544f..3fae0cd00 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -249,7 +249,8 @@ func (pm *ProtocolManager) newPeer(pv int, p *p2p.Peer, rw p2p.MsgReadWriter) *p
// handle is the callback invoked to manage the life cycle of an eth peer. When
// this function terminates, the peer is disconnected.
func (pm *ProtocolManager) handle(p *peer) error {
- if pm.peers.Len() >= pm.maxPeers {
+ // Ignore maxPeers if this is a trusted peer
+ if pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted {
return p2p.DiscTooManyPeers
}
p.Log().Debug("Ethereum peer connected", "name", p.Name())
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index d021b127c..20a060e72 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -1035,14 +1035,14 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
if tx == nil {
- return nil, errors.New("unknown transaction")
+ return nil, nil
}
receipts, err := s.b.GetReceipts(ctx, blockHash)
if err != nil {
return nil, err
}
if len(receipts) <= int(index) {
- return nil, errors.New("unknown receipt")
+ return nil, nil
}
receipt := receipts[index]
diff --git a/les/handler.go b/les/handler.go
index 864abe605..9627f392b 100644
--- a/les/handler.go
+++ b/les/handler.go
@@ -260,7 +260,8 @@ func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgRea
// handle is the callback invoked to manage the life cycle of a les peer. When
// this function terminates, the peer is disconnected.
func (pm *ProtocolManager) handle(p *peer) error {
- if pm.peers.Len() >= pm.maxPeers {
+ // Ignore maxPeers if this is a trusted peer
+ if pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted {
return p2p.DiscTooManyPeers
}
diff --git a/node/api.go b/node/api.go
index 992a7c416..a3b8bc0bb 100644
--- a/node/api.go
+++ b/node/api.go
@@ -308,6 +308,11 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
// Fill the counter with the metric details, formatting if requested
if raw {
switch metric := metric.(type) {
+ case metrics.Counter:
+ root[name] = map[string]interface{}{
+ "Overall": float64(metric.Count()),
+ }
+
case metrics.Meter:
root[name] = map[string]interface{}{
"AvgRate01Min": metric.Rate1(),
@@ -338,6 +343,11 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
}
} else {
switch metric := metric.(type) {
+ case metrics.Counter:
+ root[name] = map[string]interface{}{
+ "Overall": float64(metric.Count()),
+ }
+
case metrics.Meter:
root[name] = map[string]interface{}{
"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
diff --git a/swarm/api/http/error.go b/swarm/api/http/error.go
index 831cf23fe..9a65412cf 100644
--- a/swarm/api/http/error.go
+++ b/swarm/api/http/error.go
@@ -35,6 +35,7 @@ import (
//templateMap holds a mapping of an HTTP error code to a template
var templateMap map[int]*template.Template
+var caseErrors []CaseError
//metrics variables
var (
@@ -51,6 +52,13 @@ type ErrorParams struct {
Details template.HTML
}
+//a custom error case struct that would be used to store validators and
+//additional error info to display with client responses.
+type CaseError struct {
+ Validator func(*Request) bool
+ Msg func(*Request) string
+}
+
//we init the error handling right on boot time, so lookup and http response is fast
func init() {
initErrHandling()
@@ -74,6 +82,29 @@ func initErrHandling() {
//assign formatted HTML to the code
templateMap[code] = template.Must(template.New(fmt.Sprintf("%d", code)).Parse(tname))
}
+
+ caseErrors = []CaseError{
+ {
+ Validator: func(r *Request) bool { return r.uri != nil && r.uri.Addr != "" && strings.HasPrefix(r.uri.Addr, "0x") },
+ Msg: func(r *Request) string {
+ uriCopy := r.uri
+ uriCopy.Addr = strings.TrimPrefix(uriCopy.Addr, "0x")
+ return fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.<br/>
+ Please click <a href='%[1]s'>here</a> if your browser does not redirect you.<script>setTimeout("location.href='%[1]s';",5000);</script>`, "/"+uriCopy.String())
+ },
+ }}
+}
+
+//ValidateCaseErrors is a method that process the request object through certain validators
+//that assert if certain conditions are met for further information to log as an error
+func ValidateCaseErrors(r *Request) string {
+ for _, err := range caseErrors {
+ if err.Validator(r) {
+ return err.Msg(r)
+ }
+ }
+
+ return ""
}
//ShowMultipeChoices is used when a user requests a resource in a manifest which results
@@ -82,10 +113,10 @@ func initErrHandling() {
//For example, if the user requests bzz:/<hash>/read and that manifest contains entries
//"readme.md" and "readinglist.txt", a HTML page is returned with this two links.
//This only applies if the manifest has no default entry
-func ShowMultipleChoices(w http.ResponseWriter, r *http.Request, list api.ManifestList) {
+func ShowMultipleChoices(w http.ResponseWriter, r *Request, list api.ManifestList) {
msg := ""
if list.Entries == nil {
- ShowError(w, r, "Internal Server Error", http.StatusInternalServerError)
+ ShowError(w, r, "Could not resolve", http.StatusInternalServerError)
return
}
//make links relative
@@ -102,7 +133,7 @@ func ShowMultipleChoices(w http.ResponseWriter, r *http.Request, list api.Manife
//create clickable link for each entry
msg += "<a href='" + base + e.Path + "'>" + e.Path + "</a><br/>"
}
- respond(w, r, &ErrorParams{
+ respond(w, &r.Request, &ErrorParams{
Code: http.StatusMultipleChoices,
Details: template.HTML(msg),
Timestamp: time.Now().Format(time.RFC1123),
@@ -115,13 +146,15 @@ func ShowMultipleChoices(w http.ResponseWriter, r *http.Request, list api.Manife
//The function just takes a string message which will be displayed in the error page.
//The code is used to evaluate which template will be displayed
//(and return the correct HTTP status code)
-func ShowError(w http.ResponseWriter, r *http.Request, msg string, code int) {
+func ShowError(w http.ResponseWriter, r *Request, msg string, code int) {
+ additionalMessage := ValidateCaseErrors(r)
if code == http.StatusInternalServerError {
log.Error(msg)
}
- respond(w, r, &ErrorParams{
+ respond(w, &r.Request, &ErrorParams{
Code: code,
Msg: msg,
+ Details: template.HTML(additionalMessage),
Timestamp: time.Now().Format(time.RFC1123),
template: getTemplate(code),
})
diff --git a/swarm/api/http/error_templates.go b/swarm/api/http/error_templates.go
index 0457cb8a7..cc9b996ba 100644
--- a/swarm/api/http/error_templates.go
+++ b/swarm/api/http/error_templates.go
@@ -168,6 +168,11 @@ func GetGenericErrorPage() string {
{{.Msg}}
</td>
</tr>
+ <tr>
+ <td class="value">
+ {{.Details}}
+ </td>
+ </tr>
<tr>
<td class="key">
@@ -342,6 +347,12 @@ func GetNotFoundErrorPage() string {
{{.Msg}}
</td>
</tr>
+ <tr>
+ <td class="value">
+ {{.Details}}
+ </td>
+ </tr>
+
<tr>
<td class="key">
diff --git a/swarm/api/http/error_test.go b/swarm/api/http/error_test.go
index c2c8b908b..dc545722e 100644
--- a/swarm/api/http/error_test.go
+++ b/swarm/api/http/error_test.go
@@ -18,12 +18,13 @@ package http_test
import (
"encoding/json"
- "golang.org/x/net/html"
"io/ioutil"
"net/http"
"strings"
"testing"
+ "golang.org/x/net/html"
+
"github.com/ethereum/go-ethereum/swarm/testutil"
)
@@ -96,8 +97,37 @@ func Test500Page(t *testing.T) {
defer resp.Body.Close()
respbody, err = ioutil.ReadAll(resp.Body)
- if resp.StatusCode != 500 || !strings.Contains(string(respbody), "500") {
- t.Fatalf("Invalid Status Code received, expected 500, got %d", resp.StatusCode)
+ if resp.StatusCode != 404 {
+ t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode)
+ }
+
+ _, err = html.Parse(strings.NewReader(string(respbody)))
+ if err != nil {
+ t.Fatalf("HTML validation failed for error page returned!")
+ }
+}
+func Test500PageWith0xHashPrefix(t *testing.T) {
+ srv := testutil.NewTestSwarmServer(t)
+ defer srv.Close()
+
+ var resp *http.Response
+ var respbody []byte
+
+ url := srv.URL + "/bzz:/0xthisShouldFailWith500CodeAndAHelpfulMessage"
+ resp, err := http.Get(url)
+
+ if err != nil {
+ t.Fatalf("Request failed: %v", err)
+ }
+ defer resp.Body.Close()
+ respbody, err = ioutil.ReadAll(resp.Body)
+
+ if resp.StatusCode != 404 {
+ t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode)
+ }
+
+ if !strings.Contains(string(respbody), "The requested hash seems to be prefixed with") {
+ t.Fatalf("Did not receive the expected error message")
}
_, err = html.Parse(strings.NewReader(string(respbody)))
@@ -127,8 +157,8 @@ func TestJsonResponse(t *testing.T) {
defer resp.Body.Close()
respbody, err = ioutil.ReadAll(resp.Body)
- if resp.StatusCode != 500 {
- t.Fatalf("Invalid Status Code received, expected 500, got %d", resp.StatusCode)
+ if resp.StatusCode != 404 {
+ t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode)
}
if !isJSON(string(respbody)) {
diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go
index df90fd04f..b8e7436cf 100644
--- a/swarm/api/http/server.go
+++ b/swarm/api/http/server.go
@@ -336,7 +336,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
key, err := s.api.Resolve(r.uri)
if err != nil {
getFail.Inc(1)
- s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
+ s.NotFound(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
return
}
@@ -421,7 +421,7 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
key, err := s.api.Resolve(r.uri)
if err != nil {
getFilesFail.Inc(1)
- s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
+ s.NotFound(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
return
}
@@ -494,7 +494,7 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
key, err := s.api.Resolve(r.uri)
if err != nil {
getListFail.Inc(1)
- s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
+ s.NotFound(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
return
}
@@ -598,7 +598,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
key, err := s.api.Resolve(r.uri)
if err != nil {
getFileFail.Inc(1)
- s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
+ s.NotFound(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
return
}
@@ -628,7 +628,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
s.logDebug(fmt.Sprintf("Multiple choices! --> %v", list))
//show a nice page links to available entries
- ShowMultipleChoices(w, &r.Request, list)
+ ShowMultipleChoices(w, r, list)
return
}
@@ -693,7 +693,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// strictly a traditional PUT request which replaces content
// at a URI, and POST is more ubiquitous)
if uri.Raw() || uri.DeprecatedRaw() {
- ShowError(w, r, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest)
+ ShowError(w, req, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest)
return
} else {
s.HandlePostFiles(w, req)
@@ -701,7 +701,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
case "DELETE":
if uri.Raw() || uri.DeprecatedRaw() {
- ShowError(w, r, fmt.Sprintf("No DELETE to %s allowed.", uri), http.StatusBadRequest)
+ ShowError(w, req, fmt.Sprintf("No DELETE to %s allowed.", uri), http.StatusBadRequest)
return
}
s.HandleDelete(w, req)
@@ -725,7 +725,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.HandleGetFile(w, req)
default:
- ShowError(w, r, fmt.Sprintf("Method "+r.Method+" is not supported.", uri), http.StatusMethodNotAllowed)
+ ShowError(w, req, fmt.Sprintf("Method "+r.Method+" is not supported.", uri), http.StatusMethodNotAllowed)
}
}
@@ -757,13 +757,13 @@ func (s *Server) logError(format string, v ...interface{}) {
}
func (s *Server) BadRequest(w http.ResponseWriter, r *Request, reason string) {
- ShowError(w, &r.Request, fmt.Sprintf("Bad request %s %s: %s", r.Method, r.uri, reason), http.StatusBadRequest)
+ ShowError(w, r, fmt.Sprintf("Bad request %s %s: %s", r.Request.Method, r.uri, reason), http.StatusBadRequest)
}
func (s *Server) Error(w http.ResponseWriter, r *Request, err error) {
- ShowError(w, &r.Request, fmt.Sprintf("Error serving %s %s: %s", r.Method, r.uri, err), http.StatusInternalServerError)
+ ShowError(w, r, fmt.Sprintf("Error serving %s %s: %s", r.Request.Method, r.uri, err), http.StatusInternalServerError)
}
func (s *Server) NotFound(w http.ResponseWriter, r *Request, err error) {
- ShowError(w, &r.Request, fmt.Sprintf("NOT FOUND error serving %s %s: %s", r.Method, r.uri, err), http.StatusNotFound)
+ ShowError(w, r, fmt.Sprintf("NOT FOUND error serving %s %s: %s", r.Request.Method, r.uri, err), http.StatusNotFound)
}