Upgrade geth 1.8.17 plus add metrics during compilation time (#1273)

This commit updates geth to 1.8.17 and adds a possibility to enable metrics during compilation time.

The cascade of issues forced us to upgrade geth to 1.8.17 in order to allow enabling metrics during compilation time. 1.8.17 introduced `NodeID` refactoring and `enode` package which affected our peers pool and integration with Discovery V5.
This commit is contained in:
Adam Babik 2018-11-14 08:03:58 +01:00 committed by GitHub
parent 5b2d7dc212
commit 52a1bdfed6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
286 changed files with 9249 additions and 19195 deletions

42
Gopkg.lock generated
View File

@ -88,7 +88,7 @@
revision = "935e0e8a636ca4ba70b713f3e38a19e1b77739e8"
[[projects]]
digest = "1:1dc638d013f2a6f6ae13568584e8fee7e172cbf295e82064ded18bcf6d63c04c"
digest = "1:e221b8d0ccd91e9ee0a2ddda27ec75518dd683de945d01c87816f64ce418bf91"
name = "github.com/ethereum/go-ethereum"
packages = [
".",
@ -132,6 +132,7 @@
"eth/tracers",
"eth/tracers/internal/tracers",
"ethapi",
"ethclient",
"ethdb",
"event",
"internal/debug",
@ -140,7 +141,6 @@
"les/flowcontrol",
"light",
"log",
"log/term",
"metrics",
"metrics/exp",
"miner",
@ -148,6 +148,7 @@
"p2p",
"p2p/discover",
"p2p/discv5",
"p2p/enode",
"p2p/enr",
"p2p/nat",
"p2p/netutil",
@ -157,9 +158,9 @@
"trie",
]
pruneopts = "T"
revision = "31f0afca344c53678e98032d6306e0e4ff7b9be1"
revision = "2ad6673303bb48f8e3c2865386cfa928e92dbcbd"
source = "github.com/status-im/go-ethereum"
version = "v1.8.16"
version = "v1.8.17"
[[projects]]
digest = "1:5ac7ecd476a2355a5201229081df2e5f57333ecf703e1f69dde699ae34169c1b"
@ -635,11 +636,11 @@
revision = "5411d3eea5978e6cdc258b30de592b60df6aba96"
[[projects]]
digest = "1:f3b286c0af7136e7afa8093165abb64159742bd31f580d7b000d21e1d7e73256"
digest = "1:b95b22ee36277368bbf22e0fbe4f1be366585516914d6cfe4b3dc7b8b37eda5f"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = "NUT"
revision = "281032e84ae07510239465db46bf442aa44b953a"
revision = "3fb116b820352b7f0c281308a4d6250c22d94e27"
[[projects]]
branch = "master"
@ -790,11 +791,11 @@
[[projects]]
branch = "master"
digest = "1:5d3c51d0f96ff0b228582e5e36295a33da8e16d106cd9dc31538096bd35dce1e"
digest = "1:f3044238fc5d70eca12cc181b1e6d5270570d85a7b7046686381e618a783a7d6"
name = "github.com/status-im/go-multiaddr-ethv4"
packages = ["."]
pruneopts = "NUT"
revision = "17cb1ad76379d65e802eacc786d8f67eebd7cd6d"
revision = "cbcba3a7c121e29718d9011ffc9e2b78ac6d5c99"
[[projects]]
branch = "master"
@ -810,7 +811,7 @@
[[projects]]
branch = "master"
digest = "1:b88d64c27ed467659fa0ee1806bc790b88c37bcbff0b8fcd1b97d6a3ee7f9703"
digest = "1:5fb8fc6a365f62e1d771b8a33c808a111ace9ba3506089f00ec252ec1e257a83"
name = "github.com/status-im/rendezvous"
packages = [
".",
@ -818,15 +819,15 @@
"server",
]
pruneopts = "NUT"
revision = "55370cdfd9f288059b03c04e23784bb8829a894c"
revision = "fbcc46a78cd43fef95a110df664aab513116a850"
[[projects]]
digest = "1:9552f5ea7e82e95910e182bd41b6c71933b50717990a61ac517bfa1cc6f653dc"
digest = "1:fe884981c5589ade6ea86ca876be4a744ea1344c6e8cfa17e434fcf270b04598"
name = "github.com/status-im/whisper"
packages = ["whisperv6"]
pruneopts = "NUT"
revision = "14e1bbfd9ba956e7fc7649e815aa19e4386b26da"
version = "v1.2.0"
revision = "e25ea1d673d5982b16fd3e51ed2a0d8f91b809d9"
version = "v1.3.0"
[[projects]]
digest = "1:572c783a763db6383aca3179976eb80e4c900f52eba56cba8bb2e3cea7ce720e"
@ -1016,17 +1017,6 @@
pruneopts = "NUT"
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
[[projects]]
branch = "master"
digest = "1:95f24cc9a9a50da8aa144484a7c625c2e30dcbddf8e3bc336d2d92108b8c769e"
name = "golang.org/x/tools"
packages = [
"go/ast/astutil",
"imports",
]
pruneopts = "NUT"
revision = "ac136b6c2db7c4d43955e4bc7174db36dc0539c0"
[[projects]]
digest = "1:6aba14c40a7d987288b30c37893238d136e027788f27f8bb9c7ad98b15d30040"
name = "gopkg.in/go-playground/validator.v9"
@ -1087,15 +1077,17 @@
"github.com/ethereum/go-ethereum/crypto/sha3",
"github.com/ethereum/go-ethereum/eth",
"github.com/ethereum/go-ethereum/eth/downloader",
"github.com/ethereum/go-ethereum/eth/filters",
"github.com/ethereum/go-ethereum/ethapi",
"github.com/ethereum/go-ethereum/ethclient",
"github.com/ethereum/go-ethereum/event",
"github.com/ethereum/go-ethereum/les",
"github.com/ethereum/go-ethereum/log",
"github.com/ethereum/go-ethereum/metrics",
"github.com/ethereum/go-ethereum/node",
"github.com/ethereum/go-ethereum/p2p",
"github.com/ethereum/go-ethereum/p2p/discover",
"github.com/ethereum/go-ethereum/p2p/discv5",
"github.com/ethereum/go-ethereum/p2p/enode",
"github.com/ethereum/go-ethereum/p2p/enr",
"github.com/ethereum/go-ethereum/p2p/nat",
"github.com/ethereum/go-ethereum/params",

View File

@ -24,12 +24,12 @@
[[constraint]]
name = "github.com/ethereum/go-ethereum"
version = "=v1.8.16"
version = "=v1.8.17"
source = "github.com/status-im/go-ethereum"
[[constraint]]
name = "github.com/status-im/whisper"
version = "=v1.2.0"
version = "=v1.3.0"
[[override]]
name = "github.com/golang/protobuf"
@ -84,7 +84,7 @@
[[override]]
name = "github.com/mattn/go-isatty"
revision = "281032e84ae07510239465db46bf442aa44b953a"
revision = "3fb116b820352b7f0c281308a4d6250c22d94e27"
[[override]]
name = "github.com/pborman/uuid"
@ -151,8 +151,8 @@
revision = "36e9d2ebbde5e3f13ab2e25625fd453271d6522e"
[[constraint]]
branch = "master"
name = "github.com/status-im/rendezvous"
branch = "master"
[[override]]
name = "github.com/deckarep/golang-set"

View File

@ -37,7 +37,11 @@ GIT_COMMIT = $(shell tag=`git describe --exact-match --tag 2>/dev/null`; \
else git rev-parse --short HEAD; fi)
AUTHOR = $(shell echo $$USER)
BUILD_FLAGS ?= $(shell echo "-ldflags '-X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X github.com/status-im/status-go/params.Version=$(GIT_COMMIT)'")
ENABLE_METRICS ?= false
BUILD_FLAGS ?= $(shell echo "-ldflags '\
-X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` \
-X github.com/status-im/status-go/params.Version=$(GIT_COMMIT) \
-X github.com/status-im/status-go/vendor/github.com/ethereum/go-ethereum/metrics.EnabledStr=$(ENABLE_METRICS)'")
XGO_GO ?= latest
XGOVERSION ?= 1.10.x
@ -258,7 +262,7 @@ test-unit: UNIT_TEST_PACKAGES = $(shell go list ./... | \
grep -v /t/benchmarks | \
grep -v /lib)
test-unit: ##@tests Run unit and integration tests
go test -v $(UNIT_TEST_PACKAGES) $(gotest_extraflags)
go test -v -failfast $(UNIT_TEST_PACKAGES) $(gotest_extraflags)
test-unit-race: gotest_extraflags=-race
test-unit-race: test-unit ##@tests Run unit and integration tests with -race flag

View File

@ -1 +1 @@
0.16.8-beta
0.17.0

View File

@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
ma "github.com/multiformats/go-multiaddr"
)
@ -123,7 +124,7 @@ func makeProxiedENR(n *discv5.Node) (enr.Record, error) {
if err != nil {
return record, fmt.Errorf("unable to generate private key. error : %v", err)
}
if err := enr.SignV4(&record, key); err != nil {
if err := enode.SignV4(&record, key); err != nil {
return record, fmt.Errorf("unable to sign enr record. error: %v", err)
}
return record, nil

View File

@ -10,8 +10,8 @@ import (
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
ma "github.com/multiformats/go-multiaddr"
"github.com/status-im/rendezvous"
@ -29,7 +29,7 @@ var (
errDiscoveryIsStopped = errors.New("discovery is stopped")
)
func NewRendezvous(servers []ma.Multiaddr, identity *ecdsa.PrivateKey, node *discover.Node) (*Rendezvous, error) {
func NewRendezvous(servers []ma.Multiaddr, identity *ecdsa.PrivateKey, node *enode.Node) (*Rendezvous, error) {
r := new(Rendezvous)
r.node = node
r.identity = identity
@ -62,7 +62,7 @@ type Rendezvous struct {
servers []ma.Multiaddr
registrationPeriod time.Duration
bucketSize int
node *discover.Node
node *enode.Node
identity *ecdsa.PrivateKey
recordMu sync.Mutex
@ -109,11 +109,11 @@ func (r *Rendezvous) MakeRecord() (record enr.Record, err error) {
if r.identity == nil {
return record, errIdentityIsNil
}
record.Set(enr.IP(r.node.IP))
record.Set(enr.TCP(r.node.TCP))
record.Set(enr.UDP(r.node.UDP))
record.Set(enr.IP(r.node.IP()))
record.Set(enr.TCP(r.node.TCP()))
record.Set(enr.UDP(r.node.UDP()))
// public key is added to ENR when ENR is signed
if err := enr.SignV4(&record, r.identity); err != nil {
if err := enode.SignV4(&record, r.identity); err != nil {
return record, err
}
r.record = &record
@ -226,7 +226,7 @@ func (r *Rendezvous) Discover(
func enrToNode(record enr.Record) (*discv5.Node, error) {
var (
key enr.Secp256k1
key enode.Secp256k1
ip enr.IP
tport enr.TCP
uport enr.UDP

View File

@ -6,8 +6,8 @@ import (
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
lcrypto "github.com/libp2p/go-libp2p-crypto"
ma "github.com/multiformats/go-multiaddr"
@ -35,7 +35,7 @@ func TestRendezvousDiscovery(t *testing.T) {
defer srv.Stop()
identity, err := crypto.GenerateKey()
require.NoError(t, err)
node := discover.NewNode(discover.PubkeyID(&identity.PublicKey), net.IP{10, 10, 10, 10}, 10, 20)
node := enode.NewV4(&identity.PublicKey, net.IP{10, 10, 10, 10}, 10, 20)
c, err := NewRendezvous([]ma.Multiaddr{srv.Addr()}, identity, node)
require.NoError(t, err)
require.NoError(t, c.Start())
@ -65,12 +65,12 @@ func TestMakeRecordReturnsCachedRecord(t *testing.T) {
identity, err := crypto.GenerateKey()
require.NoError(t, err)
record := enr.Record{}
require.NoError(t, enr.SignV4(&record, identity))
require.NoError(t, enode.SignV4(&record, identity))
c := NewRendezvousWithENR(nil, record)
rst, err := c.MakeRecord()
require.NoError(t, err)
require.NotNil(t, rst.NodeAddr())
require.Equal(t, record.NodeAddr(), rst.NodeAddr())
require.NotNil(t, enode.V4ID{}.NodeAddr(&rst))
require.Equal(t, enode.V4ID{}.NodeAddr(&record), enode.V4ID{}.NodeAddr(&rst))
}
func TestRendezvousRegisterAndDiscoverExitGracefully(t *testing.T) {
@ -88,7 +88,7 @@ func BenchmarkRendezvousStart(b *testing.B) {
require.NoError(b, err)
addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/7777")
require.NoError(b, err)
node := discover.NewNode(discover.PubkeyID(&identity.PublicKey), net.IP{10, 10, 10, 10}, 10, 20)
node := enode.NewV4(&identity.PublicKey, net.IP{10, 10, 10, 10}, 10, 20)
b.ResetTimer()
for n := 0; n < b.N; n++ {

View File

@ -7,7 +7,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
)
var logger = log.New("package", "mailserver/registry")
@ -32,7 +32,7 @@ func NewVerifier(contractCaller bind.ContractCaller, contractAddress common.Addr
}
// VerifyNode checks if a given node is trusted using a smart contract.
func (v *Verifier) VerifyNode(ctx context.Context, nodeID discover.NodeID) bool {
func (v *Verifier) VerifyNode(ctx context.Context, nodeID enode.ID) bool {
res, err := v.rc.Exists(&bind.CallOpts{Context: ctx}, nodeID.Bytes())
logger.Debug("verifying node", "id", nodeID, "verified", res)
if err != nil {

View File

@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/stretchr/testify/suite"
)
@ -61,18 +61,18 @@ func (s *VerifierTestSuite) setupAccount() {
s.from = crypto.PubkeyToAddress(s.privKey.PublicKey)
}
func (s *VerifierTestSuite) add(nodeID discover.NodeID) {
func (s *VerifierTestSuite) add(nodeID enode.ID) {
auth := bind.NewKeyedTransactor(s.privKey)
_, err := s.registry.Add(auth, nodeID[:])
_, err := s.registry.Add(auth, nodeID.Bytes())
s.Require().NoError(err)
s.backend.Commit()
}
func (s *VerifierTestSuite) generateNodeID() discover.NodeID {
func (s *VerifierTestSuite) generateNodeID() enode.ID {
k, err := crypto.GenerateKey()
s.Require().NoError(err)
return discover.PubkeyID(&k.PublicKey)
return enode.PubkeyToIDV4(&k.PublicKey)
}
func (s *VerifierTestSuite) TestVerifyNode() {

View File

@ -16,8 +16,8 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/status-im/status-go/mailserver"
"github.com/status-im/status-go/params"
@ -340,15 +340,15 @@ func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb
})
}
// parseNodes creates list of discover.Node out of enode strings.
func parseNodes(enodes []string) []*discover.Node {
var nodes []*discover.Node
for _, enode := range enodes {
parsedPeer, err := discover.ParseNode(enode)
// parseNodes creates list of enode.Node out of enode strings.
func parseNodes(enodes []string) []*enode.Node {
var nodes []*enode.Node
for _, item := range enodes {
parsedPeer, err := enode.ParseV4(item)
if err == nil {
nodes = append(nodes, parsedPeer)
} else {
logger.Error("Failed to parse enode", "enode", enode, "err", err)
logger.Error("Failed to parse enode", "enode", item, "err", err)
}
}
@ -370,10 +370,10 @@ func parseNodesV5(enodes []string) []*discv5.Node {
return nodes
}
func parseNodesToNodeID(enodes []string) []discover.NodeID {
nodeIDs := make([]discover.NodeID, 0, len(enodes))
func parseNodesToNodeID(enodes []string) []enode.ID {
nodeIDs := make([]enode.ID, 0, len(enodes))
for _, node := range parseNodes(enodes) {
nodeIDs = append(nodeIDs, node.ID)
nodeIDs = append(nodeIDs, node.ID())
}
return nodeIDs
}

View File

@ -1,10 +1,11 @@
package node
import (
"fmt"
"net"
"testing"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/params"
. "github.com/status-im/status-go/t/utils"
"github.com/stretchr/testify/require"
@ -62,12 +63,15 @@ func TestMakeNodeMalformedBootnodes(t *testing.T) {
}
func TestParseNodesToNodeID(t *testing.T) {
identity, err := crypto.GenerateKey()
require.NoError(t, err)
node := enode.NewV4(&identity.PublicKey, net.IP{10, 10, 10, 10}, 10, 20)
nodeIDs := parseNodesToNodeID([]string{
"enode://badkey@127.0.0.1:30303",
fmt.Sprintf("enode://%s@127.0.0.1:30303", discover.NodeID{1}),
node.String(),
})
require.Len(t, nodeIDs, 1)
require.Equal(t, discover.NodeID{1}, nodeIDs[0])
require.Equal(t, node.ID(), nodeIDs[0])
}
func TestNewGethNodeConfig(t *testing.T) {

View File

@ -17,7 +17,8 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
ma "github.com/multiformats/go-multiaddr"
whisper "github.com/status-im/whisper/whisperv6"
"github.com/syndtr/goleveldb/leveldb"
@ -190,17 +191,25 @@ func (n *StatusNode) discoveryEnabled() bool {
return n.config != nil && (!n.config.NoDiscovery || n.config.Rendezvous) && n.config.ClusterConfig.Enabled
}
func (n *StatusNode) discoverNode() *discover.Node {
func (n *StatusNode) discoverNode() (*enode.Node, error) {
if !n.isRunning() {
return nil
return nil, nil
}
discNode := n.gethNode.Server().Self()
if n.config.AdvertiseAddr != "" {
n.log.Info("using AdvertiseAddr for rendezvous", "addr", n.config.AdvertiseAddr)
discNode.IP = net.ParseIP(n.config.AdvertiseAddr)
if n.config.AdvertiseAddr == "" {
return discNode, nil
}
return discNode
n.log.Info("Using AdvertiseAddr for rendezvous", "addr", n.config.AdvertiseAddr)
r := discNode.Record()
r.Set(enr.IP(net.ParseIP(n.config.AdvertiseAddr)))
if err := enode.SignV4(r, n.Server().PrivateKey); err != nil {
return nil, err
}
return enode.New(enode.ValidSchemes[r.IdentityScheme()], r)
}
func (n *StatusNode) startRendezvous() (discovery.Discovery, error) {
@ -218,7 +227,12 @@ func (n *StatusNode) startRendezvous() (discovery.Discovery, error) {
return nil, fmt.Errorf("failed to parse rendezvous node %s: %v", n.config.ClusterConfig.RendezvousNodes[0], err)
}
}
return discovery.NewRendezvous(maddrs, n.gethNode.Server().PrivateKey, n.discoverNode())
node, err := n.discoverNode()
if err != nil {
return nil, fmt.Errorf("failed to get a discover node: %v", err)
}
return discovery.NewRendezvous(maddrs, n.gethNode.Server().PrivateKey, node)
}
func (n *StatusNode) startDiscovery() error {
@ -414,7 +428,7 @@ func (n *StatusNode) AddPeer(url string) error {
// addPeer adds new static peer node
func (n *StatusNode) addPeer(url string) error {
parsedNode, err := discover.ParseNode(url)
parsedNode, err := enode.ParseV4(url)
if err != nil {
return err
}
@ -429,7 +443,7 @@ func (n *StatusNode) addPeer(url string) error {
}
func (n *StatusNode) removePeer(url string) error {
parsedNode, err := discover.ParseNode(url)
parsedNode, err := enode.ParseV4(url)
if err != nil {
return err
}

View File

@ -13,7 +13,7 @@ import (
"github.com/ethereum/go-ethereum/les"
gethnode "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
whisper "github.com/status-im/whisper/whisperv6"
"github.com/status-im/status-go/discovery"
@ -234,7 +234,7 @@ func TestStatusNodeReconnectStaticPeers(t *testing.T) {
require.NoError(t, <-errCh)
}
require.Equal(t, 1, n.PeerCount())
require.Equal(t, peer.Server().Self().ID.String(), n.GethNode().Server().PeersInfo()[0].ID)
require.Equal(t, peer.Server().Self().ID().String(), n.GethNode().Server().PeersInfo()[0].ID)
// reconnect static peers
errDropCh := helpers.WaitForPeerAsync(n.Server(), peerURL, p2p.PeerEventTypeDrop, time.Second*30)
@ -252,7 +252,7 @@ func isPeerConnected(node *StatusNode, peerURL string) (bool, error) {
return false, ErrNoRunningNode
}
parsedPeer, err := discover.ParseNode(peerURL)
parsedPeer, err := enode.ParseV4(peerURL)
if err != nil {
return false, err
}
@ -260,7 +260,7 @@ func isPeerConnected(node *StatusNode, peerURL string) (bool, error) {
server := node.GethNode().Server()
for _, peer := range server.PeersInfo() {
if peer.ID == parsedPeer.ID.String() {
if peer.ID == parsedPeer.ID().String() {
return true, nil
}
}
@ -292,7 +292,9 @@ func TestStatusNodeDiscoverNode(t *testing.T) {
}
n := New()
require.NoError(t, n.Start(&config))
require.Equal(t, net.ParseIP("127.0.0.1").To4(), n.discoverNode().IP)
node, err := n.discoverNode()
require.NoError(t, err)
require.Equal(t, net.ParseIP("127.0.0.1").To4(), node.IP())
config = params.NodeConfig{
NoDiscovery: true,
@ -301,5 +303,7 @@ func TestStatusNodeDiscoverNode(t *testing.T) {
}
n = New()
require.NoError(t, n.Start(&config))
require.Equal(t, net.ParseIP("127.0.0.2"), n.discoverNode().IP)
node, err = n.discoverNode()
require.NoError(t, err)
require.Equal(t, net.ParseIP("127.0.0.2").To4(), node.IP())
}

View File

@ -3,6 +3,7 @@ package peers
import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/db"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
@ -18,8 +19,8 @@ type Cache struct {
db *leveldb.DB
}
func makePeerKey(peerID discv5.NodeID, topic discv5.Topic) []byte {
return db.Key(db.PeersCache, []byte(topic), peerID[:])
func makePeerKey(peerID enode.ID, topic discv5.Topic) []byte {
return db.Key(db.PeersCache, []byte(topic), peerID.Bytes())
}
// AddPeer stores peer with a following key: <topic><peer ID>
@ -28,12 +29,16 @@ func (d *Cache) AddPeer(peer *discv5.Node, topic discv5.Topic) error {
if err != nil {
return err
}
return d.db.Put(makePeerKey(peer.ID, topic), data, nil)
pk, err := peer.ID.Pubkey()
if err != nil {
return err
}
return d.db.Put(makePeerKey(enode.PubkeyToIDV4(pk), topic), data, nil)
}
// RemovePeer deletes a peer from database.
func (d *Cache) RemovePeer(peerID discv5.NodeID, topic discv5.Topic) error {
return d.db.Delete(makePeerKey(peerID, topic), nil)
func (d *Cache) RemovePeer(nodeID enode.ID, topic discv5.Topic) error {
return d.db.Delete(makePeerKey(nodeID, topic), nil)
}
// GetPeersRange returns peers for a given topic with a limit.

View File

@ -4,6 +4,9 @@ import (
"net"
"testing"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -11,6 +14,59 @@ import (
"github.com/syndtr/goleveldb/leveldb/storage"
)
func TestPeersRange(t *testing.T) {
peersDB, err := newInMemoryCache()
require.NoError(t, err)
topic := discv5.Topic("test")
peerCount := 3
peers, err := createDiscv5Peers(peerCount)
require.NoError(t, err)
addedPeerIDs := make(map[string]struct{})
for _, peer := range peers {
assert.NoError(t, peersDB.AddPeer(peer, topic))
addedPeerIDs[peer.String()] = struct{}{}
}
// check if all peers are cached
cachedNodes := peersDB.GetPeersRange(topic, peerCount)
require.Len(t, cachedNodes, peerCount)
// and returned peers are these we just created
for _, node := range cachedNodes {
_, ok := addedPeerIDs[node.String()]
assert.True(t, ok)
}
// test removing peers
pk, err := peers[0].ID.Pubkey()
require.NoError(t, err)
require.NoError(t, peersDB.RemovePeer(enode.PubkeyToIDV4(pk), topic))
cachedNodes = peersDB.GetPeersRange(topic, peerCount)
require.Len(t, cachedNodes, peerCount-1)
}
func TestMultipleTopics(t *testing.T) {
peersDB, err := newInMemoryCache()
require.NoError(t, err)
topics := []discv5.Topic{discv5.Topic("first"), discv5.Topic("second")}
peerCount := 3
peers, err := createDiscv5Peers(peerCount)
require.NoError(t, err)
for i := range topics {
for _, peer := range peers {
assert.NoError(t, peersDB.AddPeer(peer, topics[i]))
}
}
for i := range topics {
nodes := peersDB.GetPeersRange(topics[i], peerCount+1)
assert.Len(t, nodes, peerCount)
}
}
// newInMemoryCache creates a cache for tests
func newInMemoryCache() (*Cache, error) {
memdb, err := leveldb.Open(storage.NewMemStorage(), nil)
@ -20,49 +76,22 @@ func newInMemoryCache() (*Cache, error) {
return NewCache(memdb), nil
}
func TestPeersRange(t *testing.T) {
peersDB, err := newInMemoryCache()
require.NoError(t, err)
topic := discv5.Topic("test")
peers := [3]*discv5.Node{
discv5.NewNode(discv5.NodeID{3}, net.IPv4(100, 100, 0, 3), 32311, 32311),
discv5.NewNode(discv5.NodeID{4}, net.IPv4(100, 100, 0, 4), 32311, 32311),
discv5.NewNode(discv5.NodeID{2}, net.IPv4(100, 100, 0, 2), 32311, 32311),
}
for _, peer := range peers {
assert.NoError(t, peersDB.AddPeer(peer, topic))
}
nodes := peersDB.GetPeersRange(topic, 3)
require.Len(t, nodes, 3)
// object will be ordered by memcpy order of bytes 2,3,4 in our case
// order of tests is intentionally mixed to make it obvious that range is
// not ordered by the insertion time
assert.Equal(t, peers[2].String(), nodes[0].String())
assert.Equal(t, peers[0].String(), nodes[1].String())
assert.Equal(t, peers[1].String(), nodes[2].String())
func createDiscv5Peers(count int) ([]*discv5.Node, error) {
nodes := make([]*discv5.Node, count)
assert.NoError(t, peersDB.RemovePeer(peers[1].ID, topic))
require.Len(t, peersDB.GetPeersRange(topic, 3), 2)
}
for i := 0; i < count; i++ {
id, err := crypto.GenerateKey()
if err != nil {
return nil, err
}
func TestMultipleTopics(t *testing.T) {
peersDB, err := newInMemoryCache()
require.NoError(t, err)
topics := []discv5.Topic{discv5.Topic("first"), discv5.Topic("second")}
for i := range topics {
peers := [3]*discv5.Node{
discv5.NewNode(discv5.NodeID{byte(i), 1}, net.IPv4(100, 100, 0, 3), 32311, 32311),
discv5.NewNode(discv5.NodeID{byte(i), 2}, net.IPv4(100, 100, 0, 4), 32311, 32311),
discv5.NewNode(discv5.NodeID{byte(i), 3}, net.IPv4(100, 100, 0, 2), 32311, 32311)}
for _, peer := range peers {
assert.NoError(t, peersDB.AddPeer(peer, topics[i]))
}
}
for i := range topics {
nodes := peersDB.GetPeersRange(topics[i], 10)
assert.Len(t, nodes, 3)
for _, n := range nodes {
assert.Equal(t, byte(i), n.ID[0])
}
nodes[i] = discv5.NewNode(
discv5.PubkeyID(&id.PublicKey),
net.IPv4(10, 10, 0, byte(i)),
32311,
32311,
)
}
return nodes, nil
}

View File

@ -4,15 +4,14 @@ import (
"context"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/signal"
)
// Verifier verifies if a give node is trusted.
type Verifier interface {
VerifyNode(context.Context, discover.NodeID) bool
VerifyNode(context.Context, enode.ID) bool
}
// MailServerDiscoveryTopic topic name for mailserver discovery.
@ -53,7 +52,7 @@ var sendEnodeDiscovered = signal.SendEnodeDiscovered
// ConfirmAdded calls base TopicPool ConfirmAdded method and sends a signal
// confirming the enode has been discovered.
func (t *cacheOnlyTopicPool) ConfirmAdded(server *p2p.Server, nodeID discover.NodeID) {
func (t *cacheOnlyTopicPool) ConfirmAdded(server *p2p.Server, nodeID enode.ID) {
trusted := t.verifier.VerifyNode(context.TODO(), nodeID)
if trusted {
// add to cache only if trusted
@ -62,26 +61,24 @@ func (t *cacheOnlyTopicPool) ConfirmAdded(server *p2p.Server, nodeID discover.No
t.subtractToLimits()
}
id := discv5.NodeID(nodeID)
// If a peer was trusted, it was moved to connectedPeers,
// signal was sent and we can safely remove it.
if peer, ok := t.connectedPeers[id]; ok {
if peer, ok := t.connectedPeers[nodeID]; ok {
t.removeServerPeer(server, peer)
// Delete it from `connectedPeers` immediately to
// prevent removing it from the cache which logic is
// implemented in TopicPool.
delete(t.connectedPeers, id)
delete(t.connectedPeers, nodeID)
}
// It a peer was not trusted, it is still in pendingPeers.
// We should remove it from the p2p.Server.
if peer, ok := t.pendingPeers[id]; ok {
if peer, ok := t.pendingPeers[nodeID]; ok {
t.removeServerPeer(server, peer.peerInfo)
// Delete it from `connectedPeers` immediately to
// prevent removing it from the cache which logic is
// implemented in TopicPool.
delete(t.pendingPeers, id)
delete(t.pendingPeers, nodeID)
}
}

View File

@ -8,8 +8,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/params"
"github.com/stretchr/testify/suite"
)
@ -60,12 +60,16 @@ func (s *CacheOnlyTopicPoolSuite) TestReplacementPeerIsCounted() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
id1, err := crypto.GenerateKey()
s.Require().NoError(err)
peer1 := discv5.NewNode(discv5.PubkeyID(&id1.PublicKey), s.peer.Self().IP(), 32311, 32311)
id2, err := crypto.GenerateKey()
s.Require().NoError(err)
peer2 := discv5.NewNode(discv5.PubkeyID(&id2.PublicKey), s.peer.Self().IP(), 32311, 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.topicPool.ConfirmAdded(s.peer, enode.PubkeyToIDV4(&id1.PublicKey))
s.topicPool.ConfirmAdded(s.peer, enode.PubkeyToIDV4(&id1.PublicKey))
s.True(s.topicPool.MaxReached())
// When we stop searching for peers (when Max limit is reached)
@ -90,9 +94,12 @@ func (s *CacheOnlyTopicPoolSuite) TestConfirmAddedSignals() {
sentTopic = topic
}
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.Equal((discv5.NodeID{1}).String(), sentNodeID)
id, err := crypto.GenerateKey()
s.Require().NoError(err)
nodeID := enode.PubkeyToIDV4(&id.PublicKey)
s.topicPool.ConfirmAdded(s.peer, nodeID)
s.Equal(nodeID.String(), sentNodeID)
s.Equal(MailServerDiscoveryTopic, sentTopic)
}
@ -104,9 +111,11 @@ func (s *CacheOnlyTopicPoolSuite) TestNotTrustedPeer() {
s.topicPool.maxCachedPeers = 1
s.topicPool.verifier = &testFalseVerifier{}
foundPeer := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, foundPeer)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(foundPeer.ID))
id, err := crypto.GenerateKey()
s.Require().NoError(err)
foundPeer := discv5.NewNode(discv5.PubkeyID(&id.PublicKey), s.peer.Self().IP(), 32311, 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, foundPeer))
s.topicPool.ConfirmAdded(s.peer, enode.PubkeyToIDV4(&id.PublicKey))
s.False(signalCalled)
// limits should not change
@ -118,12 +127,12 @@ func (s *CacheOnlyTopicPoolSuite) TestNotTrustedPeer() {
type testTrueVerifier struct{}
func (v *testTrueVerifier) VerifyNode(context.Context, discover.NodeID) bool {
func (v *testTrueVerifier) VerifyNode(context.Context, enode.ID) bool {
return true
}
type testFalseVerifier struct{}
func (v *testFalseVerifier) VerifyNode(context.Context, discover.NodeID) bool {
func (v *testFalseVerifier) VerifyNode(context.Context, enode.ID) bool {
return false
}

View File

@ -1,6 +1,7 @@
package peers
import (
"crypto/ecdsa"
"errors"
"sync"
"time"
@ -10,8 +11,8 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/contracts"
"github.com/status-im/status-go/discovery"
@ -58,7 +59,7 @@ type Options struct {
// filled before really stopping the search.
TopicStopSearchDelay time.Duration
// TrustedMailServers is a list of trusted nodes.
TrustedMailServers []discover.NodeID
TrustedMailServers []enode.ID
// MailServerRegistryAddress is the MailServerRegistry contract address
MailServerRegistryAddress string
}
@ -83,6 +84,12 @@ type peerInfo struct {
added bool
node *discv5.Node
// store public key separately to make peerInfo more independent from discv5
publicKey *ecdsa.PublicKey
}
func (p *peerInfo) NodeID() enode.ID {
return enode.PubkeyToIDV4(p.publicKey)
}
// PeerPool manages discovered peers and connects them to p2p server
@ -292,7 +299,7 @@ func (p *PeerPool) handleServerPeers(server *p2p.Server, events <-chan *p2p.Peer
}
// handleAddedPeer notifies all topics about added peer.
func (p *PeerPool) handleAddedPeer(server *p2p.Server, nodeID discover.NodeID) {
func (p *PeerPool) handleAddedPeer(server *p2p.Server, nodeID enode.ID) {
p.mu.Lock()
defer p.mu.Unlock()
for _, t := range p.topics {
@ -337,7 +344,7 @@ func (p *PeerPool) allTopicsStopped() (all bool) {
// handleDroppedPeer notifies every topic about dropped peer and returns true if any peer have connections
// below min limit
func (p *PeerPool) handleDroppedPeer(server *p2p.Server, nodeID discover.NodeID) (any bool) {
func (p *PeerPool) handleDroppedPeer(server *p2p.Server, nodeID enode.ID) (any bool) {
p.mu.Lock()
defer p.mu.Unlock()
for _, t := range p.topics {

View File

@ -11,8 +11,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
lcrypto "github.com/libp2p/go-libp2p-crypto"
ma "github.com/multiformats/go-multiaddr"
"github.com/status-im/whisper/whisperv6"
@ -130,7 +130,7 @@ func (s *PeerPoolSimulationSuite) TearDown() {
}
}
func (s *PeerPoolSimulationSuite) getPeerFromEvent(events <-chan *p2p.PeerEvent, etype p2p.PeerEventType) (nodeID discover.NodeID) {
func (s *PeerPoolSimulationSuite) getPeerFromEvent(events <-chan *p2p.PeerEvent, etype p2p.PeerEventType) (nodeID enode.ID) {
select {
case ev := <-events:
if ev.Type == etype {
@ -241,7 +241,7 @@ func (s *PeerPoolSimulationSuite) singleTopicDiscoveryWithFailover() {
// wait for the peer to be found and connected
connectedPeer := s.getPeerFromEvent(events, p2p.PeerEventTypeAdd)
s.Equal(s.peers[0].Self().ID, connectedPeer)
s.Equal(s.peers[0].Self().ID(), connectedPeer)
// as the upper limit was reached, Discovery should be stoped
s.Equal(signal.EventDiscoverySummary, s.getPoolEvent(poolEvents))
s.Equal(signal.EventDiscoveryStopped, s.getPoolEvent(poolEvents))
@ -262,7 +262,7 @@ func (s *PeerPoolSimulationSuite) singleTopicDiscoveryWithFailover() {
register = NewRegister(s.discovery[2], topic)
s.Require().NoError(register.Start())
defer register.Stop()
s.Equal(s.peers[2].Self().ID, s.getPeerFromEvent(events, p2p.PeerEventTypeAdd))
s.Equal(s.peers[2].Self().ID(), s.getPeerFromEvent(events, p2p.PeerEventTypeAdd))
// Discovery can be stopped again.
s.Require().Equal(signal.EventDiscoverySummary, s.getPoolEvent(poolEvents))
s.Equal(signal.EventDiscoveryStopped, s.getPoolEvent(poolEvents))
@ -494,7 +494,7 @@ func (s *PeerPoolSimulationSuite) TestMailServerPeersDiscovery() {
0,
true,
100 * time.Millisecond,
[]discover.NodeID{s.peers[0].Self().ID},
[]enode.ID{s.peers[0].Self().ID()},
"",
}
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
@ -503,20 +503,20 @@ func (s *PeerPoolSimulationSuite) TestMailServerPeersDiscovery() {
// wait for and verify the mail server peer
connectedPeer := s.getPeerFromEvent(events, p2p.PeerEventTypeAdd)
s.Equal(s.peers[0].Self().ID, connectedPeer)
s.Equal(s.peers[0].Self().ID().String(), connectedPeer.String())
// wait for a summary event to be sure that ConfirmAdded() was called
s.Equal(signal.EventDiscoverySummary, s.getPoolEvent(poolEvents))
s.Equal(s.peers[0].Self().ID.String(), (<-summaries)[0].ID)
s.Equal(s.peers[0].Self().ID().String(), (<-summaries)[0].ID)
// check cache
cachedPeers := peerPool.cache.GetPeersRange(MailServerDiscoveryTopic, 5)
s.Require().Len(cachedPeers, 1)
s.Equal(s.peers[0].Self().ID[:], cachedPeers[0].ID[:])
s.Equal(discv5.PubkeyID(s.peers[0].Self().Pubkey()), cachedPeers[0].ID)
// wait for another event as the peer should be removed
disconnectedPeer := s.getPeerFromEvent(events, p2p.PeerEventTypeDrop)
s.Equal(s.peers[0].Self().ID, disconnectedPeer)
s.Equal(s.peers[0].Self().ID().String(), disconnectedPeer.String())
s.Equal(signal.EventDiscoverySummary, s.getPoolEvent(poolEvents))
s.Len(<-summaries, 0)
}

View File

@ -9,8 +9,8 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/discovery"
"github.com/status-im/status-go/params"
)
@ -30,10 +30,10 @@ type TopicPoolInterface interface {
BelowMin() bool
SearchRunning() bool
StartSearch(server *p2p.Server) error
ConfirmDropped(server *p2p.Server, nodeID discover.NodeID) bool
ConfirmDropped(server *p2p.Server, nodeID enode.ID) bool
AddPeerFromTable(server *p2p.Server) *discv5.Node
MaxReached() bool
ConfirmAdded(server *p2p.Server, nodeID discover.NodeID)
ConfirmAdded(server *p2p.Server, nodeID enode.ID)
isStopped() bool
Topic() discv5.Topic
SetLimits(limits params.Limits)
@ -50,9 +50,9 @@ func newTopicPool(discovery discovery.Discovery, topic discv5.Topic, limits para
fastMode: fastMode,
slowMode: slowMode,
fastModeTimeout: DefaultTopicFastModeTimeout,
pendingPeers: make(map[discv5.NodeID]*peerInfoItem),
pendingPeers: make(map[enode.ID]*peerInfoItem),
discoveredPeersQueue: make(peerPriorityQueue, 0),
connectedPeers: make(map[discv5.NodeID]*peerInfo),
connectedPeers: make(map[enode.ID]*peerInfo),
cache: cache,
maxCachedPeers: limits.Max * maxCachedPeersMultiplier,
}
@ -83,9 +83,9 @@ type TopicPool struct {
period chan time.Duration
fastModeTimeoutCancel chan struct{}
pendingPeers map[discv5.NodeID]*peerInfoItem // contains found and requested to be connected peers but not confirmed
discoveredPeersQueue peerPriorityQueue // priority queue to find the most recently discovered peers; does not containt peers requested to connect
connectedPeers map[discv5.NodeID]*peerInfo // currently connected peers
pendingPeers map[enode.ID]*peerInfoItem // contains found and requested to be connected peers but not confirmed
discoveredPeersQueue peerPriorityQueue // priority queue to find the most recently discovered peers; does not containt peers requested to connect
connectedPeers map[enode.ID]*peerInfo // currently connected peers
stopSearchTimeout *time.Time
@ -94,10 +94,10 @@ type TopicPool struct {
}
func (t *TopicPool) addToPendingPeers(peer *peerInfo) {
if _, ok := t.pendingPeers[peer.node.ID]; ok {
if _, ok := t.pendingPeers[peer.NodeID()]; ok {
return
}
t.pendingPeers[peer.node.ID] = &peerInfoItem{
t.pendingPeers[peer.NodeID()] = &peerInfoItem{
peerInfo: peer,
index: notQueuedIndex,
}
@ -105,7 +105,7 @@ func (t *TopicPool) addToPendingPeers(peer *peerInfo) {
// addToQueue adds the passed peer to the queue if it is already pending.
func (t *TopicPool) addToQueue(peer *peerInfo) {
if p, ok := t.pendingPeers[peer.node.ID]; ok {
if p, ok := t.pendingPeers[peer.NodeID()]; ok {
heap.Push(&t.discoveredPeersQueue, p)
}
}
@ -119,7 +119,7 @@ func (t *TopicPool) popFromQueue() *peerInfo {
return item.peerInfo
}
func (t *TopicPool) removeFromPendingPeers(nodeID discv5.NodeID) {
func (t *TopicPool) removeFromPendingPeers(nodeID enode.ID) {
peer, ok := t.pendingPeers[nodeID]
if !ok {
return
@ -130,7 +130,7 @@ func (t *TopicPool) removeFromPendingPeers(nodeID discv5.NodeID) {
}
}
func (t *TopicPool) updatePendingPeer(nodeID discv5.NodeID, time mclock.AbsTime) {
func (t *TopicPool) updatePendingPeer(nodeID enode.ID, time mclock.AbsTime) {
peer, ok := t.pendingPeers[nodeID]
if !ok {
return
@ -141,7 +141,7 @@ func (t *TopicPool) updatePendingPeer(nodeID discv5.NodeID, time mclock.AbsTime)
}
}
func (t *TopicPool) movePeerFromPoolToConnected(nodeID discv5.NodeID) {
func (t *TopicPool) movePeerFromPoolToConnected(nodeID enode.ID) {
peer, ok := t.pendingPeers[nodeID]
if !ok {
return
@ -264,19 +264,19 @@ func (t *TopicPool) limitFastMode(timeout time.Duration) chan struct{} {
// (we can't know in advance if peer will be connected, thats why we allow
// to overflow for short duration)
// 4. Switch search to slow mode if it is running.
func (t *TopicPool) ConfirmAdded(server *p2p.Server, nodeID discover.NodeID) {
func (t *TopicPool) ConfirmAdded(server *p2p.Server, nodeID enode.ID) {
t.mu.Lock()
defer t.mu.Unlock()
discV5NodeID := discv5.NodeID(nodeID)
peerInfoItem, ok := t.pendingPeers[discV5NodeID]
peerInfoItem, ok := t.pendingPeers[nodeID]
inbound := !ok || !peerInfoItem.added
log.Debug("peer added event", "peer", nodeID.String(), "inbound", inbound)
// inbound connection
if inbound {
return
}
peer := peerInfoItem.peerInfo // get explicit reference
// established connection means that the node
@ -285,7 +285,7 @@ func (t *TopicPool) ConfirmAdded(server *p2p.Server, nodeID discover.NodeID) {
log.Error("failed to persist a peer", "error", err)
}
t.movePeerFromPoolToConnected(discV5NodeID)
t.movePeerFromPoolToConnected(nodeID)
// if the upper limit is already reached, drop this peer
if len(t.connectedPeers) > t.limits.Max {
log.Debug("max limit is reached drop the peer", "ID", nodeID, "topic", t.topic)
@ -310,21 +310,19 @@ func (t *TopicPool) ConfirmAdded(server *p2p.Server, nodeID discover.NodeID) {
// 4. Delete a peer from cache and peer table.
// Returns false if peer is not in our table or we requested removal of this peer.
// Otherwise peer is removed and true is returned.
func (t *TopicPool) ConfirmDropped(server *p2p.Server, nodeID discover.NodeID) bool {
func (t *TopicPool) ConfirmDropped(server *p2p.Server, nodeID enode.ID) bool {
t.mu.Lock()
defer t.mu.Unlock()
discV5NodeID := discv5.NodeID(nodeID)
// either inbound or connected from another topic
peer, exist := t.connectedPeers[discV5NodeID]
peer, exist := t.connectedPeers[nodeID]
if !exist {
return false
}
log.Debug("disconnect", "ID", nodeID, "dismissed", peer.dismissed)
delete(t.connectedPeers, discV5NodeID)
delete(t.connectedPeers, nodeID)
// Peer was removed by us because exceeded the limit.
// Add it back to the pool as it can be useful in the future.
if peer.dismissed {
@ -339,7 +337,7 @@ func (t *TopicPool) ConfirmDropped(server *p2p.Server, nodeID discover.NodeID) b
// That's why we need to call `removeServerPeer` manually.
t.removeServerPeer(server, peer)
if err := t.cache.RemovePeer(discV5NodeID, t.topic); err != nil {
if err := t.cache.RemovePeer(nodeID, t.topic); err != nil {
log.Error("failed to remove peer from cache", "error", err)
}
@ -416,15 +414,18 @@ func (t *TopicPool) StartSearch(server *p2p.Server) error {
}
func (t *TopicPool) handleFoundPeers(server *p2p.Server, found <-chan *discv5.Node, lookup <-chan bool) {
selfID := discv5.NodeID(server.Self().ID)
selfID := discv5.PubkeyID(server.Self().Pubkey())
for {
select {
case <-t.quit:
return
case <-lookup:
case node := <-found:
if node.ID != selfID {
t.processFoundNode(server, node)
if node.ID == selfID {
continue
}
if err := t.processFoundNode(server, node); err != nil {
log.Error("failed to process found node", "node", node, "error", err)
}
}
}
@ -435,24 +436,32 @@ func (t *TopicPool) handleFoundPeers(server *p2p.Server, found <-chan *discv5.No
// 1. every time when node is processed we need to update discoveredTime.
// peer will be considered as valid later only if it was discovered < 60m ago
// 2. if peer is connected or if max limit is reached we are not a adding peer to p2p server
func (t *TopicPool) processFoundNode(server *p2p.Server, node *discv5.Node) {
func (t *TopicPool) processFoundNode(server *p2p.Server, node *discv5.Node) error {
t.mu.Lock()
defer t.mu.Unlock()
log.Debug("peer found", "ID", node.ID, "topic", t.topic)
// peer is already connected so update only discoveredTime
if peer, ok := t.connectedPeers[node.ID]; ok {
peer.discoveredTime = mclock.Now()
return
pk, err := node.ID.Pubkey()
if err != nil {
return err
}
if _, ok := t.pendingPeers[node.ID]; ok {
t.updatePendingPeer(node.ID, mclock.Now())
nodeID := enode.PubkeyToIDV4(pk)
log.Debug("peer found", "ID", nodeID, "topic", t.topic)
// peer is already connected so update only discoveredTime
if peer, ok := t.connectedPeers[nodeID]; ok {
peer.discoveredTime = mclock.Now()
return nil
}
if _, ok := t.pendingPeers[nodeID]; ok {
t.updatePendingPeer(nodeID, mclock.Now())
} else {
t.addToPendingPeers(&peerInfo{
discoveredTime: mclock.Now(),
node: node,
publicKey: pk,
})
}
log.Debug(
@ -460,31 +469,24 @@ func (t *TopicPool) processFoundNode(server *p2p.Server, node *discv5.Node) {
"connected", len(t.connectedPeers), "max", t.maxCachedPeers)
// the upper limit is not reached, so let's add this peer
if len(t.connectedPeers) < t.maxCachedPeers {
t.addServerPeer(server, t.pendingPeers[node.ID].peerInfo)
t.addServerPeer(server, t.pendingPeers[nodeID].peerInfo)
} else {
t.addToQueue(t.pendingPeers[node.ID].peerInfo)
t.addToQueue(t.pendingPeers[nodeID].peerInfo)
}
return nil
}
func (t *TopicPool) addServerPeer(server *p2p.Server, info *peerInfo) {
info.added = true
server.AddPeer(discover.NewNode(
discover.NodeID(info.node.ID),
info.node.IP,
info.node.UDP,
info.node.TCP,
))
n := enode.NewV4(info.publicKey, info.node.IP, int(info.node.TCP), int(info.node.UDP))
server.AddPeer(n)
}
func (t *TopicPool) removeServerPeer(server *p2p.Server, info *peerInfo) {
log.Debug("request to remove a peer", "id", info.node.ID.String())
info.added = false
server.RemovePeer(discover.NewNode(
discover.NodeID(info.node.ID),
info.node.IP,
info.node.UDP,
info.node.TCP,
))
n := enode.NewV4(info.publicKey, info.node.IP, int(info.node.TCP), int(info.node.UDP))
server.RemovePeer(n)
}
func (t *TopicPool) isStopped() bool {

View File

@ -1,14 +1,15 @@
package peers
import (
"net"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/t/helpers"
"github.com/status-im/whisper/whisperv6"
@ -27,6 +28,14 @@ func TestTopicPoolSuite(t *testing.T) {
suite.Run(t, new(TopicPoolSuite))
}
func (s *TopicPoolSuite) createDiscV5Node(ip net.IP, port uint16) (enode.ID, *discv5.Node) {
id, err := crypto.GenerateKey()
s.Require().NoError(err)
nodeID := enode.PubkeyToIDV4(&id.PublicKey)
nodeV5 := discv5.NewNode(discv5.PubkeyID(&id.PublicKey), ip, port, port)
return nodeID, nodeV5
}
func (s *TopicPoolSuite) SetupTest() {
maxCachedPeersMultiplier = 1
key, _ := crypto.GenerateKey()
@ -71,28 +80,35 @@ func (s *TopicPoolSuite) TestUsingCache() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.Equal([]*discv5.Node{peer1, peer2}, s.topicPool.cache.GetPeersRange(s.topicPool.topic, 10))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer2.ID))
s.Equal([]*discv5.Node{peer1, peer2}, s.topicPool.cache.GetPeersRange(s.topicPool.topic, 10))
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
cached := s.topicPool.cache.GetPeersRange(s.topicPool.topic, 10)
s.Contains(cached, peer1)
s.Contains(cached, peer2)
s.topicPool.ConfirmDropped(s.peer, nodeID2)
cached = s.topicPool.cache.GetPeersRange(s.topicPool.topic, 10)
s.Contains(cached, peer1)
s.Contains(cached, peer2)
// A peer that drops by itself, should be removed from the cache.
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmDropped(s.peer, nodeID1)
s.Equal([]*discv5.Node{peer2}, s.topicPool.cache.GetPeersRange(s.topicPool.topic, 10))
}
func (s *TopicPoolSuite) TestSyncSwitches() {
testPeer := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, testPeer)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(testPeer.ID))
nodeID, peer := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer))
s.topicPool.ConfirmAdded(s.peer, nodeID)
s.AssertConsumed(s.topicPool.period, s.topicPool.slowMode, time.Second)
s.NotNil(s.topicPool.connectedPeers[testPeer.ID])
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(testPeer.ID))
s.NotNil(s.topicPool.connectedPeers[nodeID])
s.topicPool.ConfirmDropped(s.peer, nodeID)
s.AssertConsumed(s.topicPool.period, s.topicPool.fastMode, time.Second)
}
@ -146,27 +162,28 @@ func (s *TopicPoolSuite) TestSetSyncMode() {
}
func (s *TopicPoolSuite) TestNewPeerSelectedOnDrop() {
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
peer3 := discv5.NewNode(discv5.NodeID{3}, s.peer.Self().IP, 32311, 32311)
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID3, peer3 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
// add 3 nodes and confirm connection for 1 and 2
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.processFoundNode(s.peer, peer3)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer3))
s.Len(s.topicPool.pendingPeers, 3)
s.Len(s.topicPool.discoveredPeersQueue, 0)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.Contains(s.topicPool.connectedPeers, peer1.ID)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.Contains(s.topicPool.connectedPeers, peer2.ID)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer3.ID))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer3.ID))
s.Contains(s.topicPool.pendingPeers, peer3.ID)
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.Contains(s.topicPool.connectedPeers, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.Contains(s.topicPool.connectedPeers, nodeID2)
s.topicPool.ConfirmAdded(s.peer, nodeID3)
s.topicPool.ConfirmDropped(s.peer, nodeID3)
s.Contains(s.topicPool.pendingPeers, nodeID3)
s.Len(s.topicPool.pendingPeers, 1)
s.Len(s.topicPool.discoveredPeersQueue, 1)
// drop peer1
s.True(s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer1.ID)))
s.NotContains(s.topicPool.connectedPeers, peer1.ID)
s.True(s.topicPool.ConfirmDropped(s.peer, nodeID1))
s.NotContains(s.topicPool.connectedPeers, nodeID1)
// add peer from the pool
s.Equal(peer3.ID, s.topicPool.AddPeerFromTable(s.peer).ID)
s.Len(s.topicPool.pendingPeers, 1)
@ -178,45 +195,47 @@ func (s *TopicPoolSuite) TestRequestedDoesntRemove() {
// when we request to drop it
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.False(s.topicPool.connectedPeers[peer1.ID].dismissed)
s.True(s.topicPool.connectedPeers[peer2.ID].dismissed)
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer2.ID))
s.Contains(s.topicPool.pendingPeers, peer2.ID)
s.NotContains(s.topicPool.connectedPeers, peer2.ID)
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer1.ID))
s.NotContains(s.topicPool.pendingPeers, peer1.ID)
s.NotContains(s.topicPool.connectedPeers, peer1.ID)
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.False(s.topicPool.connectedPeers[nodeID1].dismissed)
s.True(s.topicPool.connectedPeers[nodeID2].dismissed)
s.topicPool.ConfirmDropped(s.peer, nodeID2)
s.Contains(s.topicPool.pendingPeers, nodeID2)
s.NotContains(s.topicPool.connectedPeers, nodeID2)
s.topicPool.ConfirmDropped(s.peer, nodeID1)
s.NotContains(s.topicPool.pendingPeers, nodeID1)
s.NotContains(s.topicPool.connectedPeers, nodeID1)
}
func (s *TopicPoolSuite) TestTheMostRecentPeerIsSelected() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
peer3 := discv5.NewNode(discv5.NodeID{3}, s.peer.Self().IP, 32311, 32311)
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID3, peer3 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
// after these operations, peer1 is confirmed and peer3 and peer2
// was added to the pool; peer3 is the most recent one
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.processFoundNode(s.peer, peer3)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer3.ID))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer3))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.topicPool.ConfirmAdded(s.peer, nodeID3)
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer2.ID))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer3.ID))
s.topicPool.ConfirmDropped(s.peer, nodeID2)
s.topicPool.ConfirmDropped(s.peer, nodeID3)
// peer1 has dropped
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmDropped(s.peer, nodeID1)
// and peer3 is take from the pool as the most recent
s.True(s.topicPool.pendingPeers[peer2.ID].discoveredTime < s.topicPool.pendingPeers[peer3.ID].discoveredTime)
s.True(s.topicPool.pendingPeers[nodeID2].discoveredTime < s.topicPool.pendingPeers[nodeID3].discoveredTime)
s.Equal(peer3.ID, s.topicPool.AddPeerFromTable(s.peer).ID)
}
@ -224,20 +243,20 @@ func (s *TopicPoolSuite) TestSelectPeerAfterMaxLimit() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
peer3 := discv5.NewNode(discv5.NodeID{3}, s.peer.Self().IP, 32311, 32311)
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID3, peer3 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer2.ID))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.topicPool.ConfirmDropped(s.peer, nodeID2)
s.Len(s.topicPool.pendingPeers, 1)
s.Contains(s.topicPool.pendingPeers, peer2.ID)
s.topicPool.processFoundNode(s.peer, peer3)
s.Contains(s.topicPool.pendingPeers, nodeID2)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer3))
s.Len(s.topicPool.pendingPeers, 2)
s.Contains(s.topicPool.pendingPeers, peer3.ID)
s.Contains(s.topicPool.pendingPeers, nodeID3)
s.Equal(peer3, s.topicPool.AddPeerFromTable(s.peer))
}
@ -245,20 +264,20 @@ func (s *TopicPoolSuite) TestReplacementPeerIsCounted() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer2.ID))
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.topicPool.ConfirmDropped(s.peer, nodeID2)
s.topicPool.ConfirmDropped(s.peer, nodeID1)
s.NotContains(s.topicPool.pendingPeers, peer1.ID)
s.NotContains(s.topicPool.connectedPeers, peer1.ID)
s.Contains(s.topicPool.pendingPeers, peer2.ID)
s.topicPool.pendingPeers[peer2.ID].added = true
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.NotContains(s.topicPool.pendingPeers, nodeID1)
s.NotContains(s.topicPool.connectedPeers, nodeID1)
s.Contains(s.topicPool.pendingPeers, nodeID2)
s.topicPool.pendingPeers[nodeID2].added = true
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.True(s.topicPool.MaxReached())
}
@ -266,11 +285,11 @@ func (s *TopicPoolSuite) TestPeerDontAddTwice() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
_, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
// peer2 already added to p2p server no reason to add it again
s.Nil(s.topicPool.AddPeerFromTable(s.peer))
}
@ -278,36 +297,43 @@ func (s *TopicPoolSuite) TestPeerDontAddTwice() {
func (s *TopicPoolSuite) TestMaxCachedPeers() {
s.topicPool.limits = params.NewLimits(1, 1)
s.topicPool.maxCachedPeers = 3
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
peer2 := discv5.NewNode(discv5.NodeID{2}, s.peer.Self().IP, 32311, 32311)
peer3 := discv5.NewNode(discv5.NodeID{3}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.topicPool.processFoundNode(s.peer, peer2)
s.topicPool.processFoundNode(s.peer, peer3)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer2.ID))
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer3.ID))
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
nodeID3, peer3 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer2))
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer3))
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID2)
s.topicPool.ConfirmAdded(s.peer, nodeID3)
s.Equal(3, len(s.topicPool.connectedPeers))
s.False(s.topicPool.connectedPeers[peer1.ID].dismissed)
s.True(s.topicPool.connectedPeers[peer2.ID].dismissed)
s.True(s.topicPool.connectedPeers[peer3.ID].dismissed)
s.False(s.topicPool.connectedPeers[nodeID1].dismissed)
s.True(s.topicPool.connectedPeers[nodeID2].dismissed)
s.True(s.topicPool.connectedPeers[nodeID3].dismissed)
cached := s.topicPool.cache.GetPeersRange(s.topicPool.topic, 5)
s.Equal(3, len(cached))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer2.ID))
s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer3.ID))
cachedMap := make(map[discv5.NodeID]*discv5.Node)
for _, peer := range cached {
cachedMap[peer.ID] = peer
}
s.Equal(peer1.ID, cached[0].ID)
s.Equal(peer2.ID, cached[1].ID)
s.Equal(peer3.ID, cached[2].ID)
s.Contains(s.topicPool.connectedPeers, peer1.ID)
s.NotContains(s.topicPool.connectedPeers, peer2.ID)
s.NotContains(s.topicPool.connectedPeers, peer3.ID)
s.NotContains(s.topicPool.pendingPeers, peer1.ID)
s.Contains(s.topicPool.pendingPeers, peer2.ID)
s.Contains(s.topicPool.pendingPeers, peer3.ID)
s.topicPool.ConfirmDropped(s.peer, nodeID2)
s.topicPool.ConfirmDropped(s.peer, nodeID3)
s.Contains(cachedMap, peer1.ID)
s.Contains(cachedMap, peer2.ID)
s.Contains(cachedMap, peer3.ID)
s.Contains(s.topicPool.connectedPeers, nodeID1)
s.NotContains(s.topicPool.connectedPeers, nodeID2)
s.NotContains(s.topicPool.connectedPeers, nodeID3)
s.NotContains(s.topicPool.pendingPeers, nodeID1)
s.Contains(s.topicPool.pendingPeers, nodeID2)
s.Contains(s.topicPool.pendingPeers, nodeID3)
s.True(s.topicPool.maxCachedPeersReached())
cached = s.topicPool.cache.GetPeersRange(s.topicPool.topic, 5)
@ -331,25 +357,27 @@ func (s *TopicPoolSuite) TestNewTopicPoolInterface() {
func (s *TopicPoolSuite) TestIgnoreInboundConnection() {
s.topicPool.limits = params.NewLimits(0, 0)
s.topicPool.maxCachedPeers = 0
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.Contains(s.topicPool.pendingPeers, peer1.ID)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.Contains(s.topicPool.pendingPeers, peer1.ID)
s.False(s.topicPool.pendingPeers[peer1.ID].dismissed)
s.NotContains(s.topicPool.connectedPeers, peer1.ID)
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Contains(s.topicPool.pendingPeers, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.Contains(s.topicPool.pendingPeers, nodeID1)
s.False(s.topicPool.pendingPeers[nodeID1].dismissed)
s.NotContains(s.topicPool.connectedPeers, nodeID1)
}
func (s *TopicPoolSuite) TestConnectedButRemoved() {
s.topicPool.limits = params.NewLimits(0, 0)
s.topicPool.maxCachedPeers = 1
peer1 := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
s.topicPool.processFoundNode(s.peer, peer1)
s.Contains(s.topicPool.pendingPeers, peer1.ID)
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(peer1.ID))
s.Contains(s.topicPool.connectedPeers, peer1.ID)
s.False(s.topicPool.ConfirmDropped(s.peer, discover.NodeID(peer1.ID)))
s.False(s.topicPool.pendingPeers[peer1.ID].added)
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
s.Require().NoError(s.topicPool.processFoundNode(s.peer, peer1))
s.Contains(s.topicPool.pendingPeers, nodeID1)
s.topicPool.ConfirmAdded(s.peer, nodeID1)
s.Contains(s.topicPool.connectedPeers, nodeID1)
s.False(s.topicPool.ConfirmDropped(s.peer, nodeID1))
s.False(s.topicPool.pendingPeers[nodeID1].added)
}
func TestServerIgnoresInboundPeer(t *testing.T) {
@ -391,11 +419,14 @@ func TestServerIgnoresInboundPeer(t *testing.T) {
// add peer to topic pool, as if it was discovered.
// it will be ignored due to the limit and added to a table of pending peers.
clientID := discv5.NodeID(client.Self().ID)
topicPool.processFoundNode(server, discv5.NewNode(
clientID,
client.Self().IP,
client.Self().UDP, client.Self().TCP))
clientID := enode.PubkeyToIDV4(&clientkey.PublicKey)
clientNodeV5 := discv5.NewNode(
discv5.PubkeyID(&clientkey.PublicKey),
client.Self().IP(),
uint16(client.Self().UDP()),
uint16(client.Self().TCP()),
)
require.NoError(t, topicPool.processFoundNode(server, clientNodeV5))
require.Contains(t, topicPool.pendingPeers, clientID)
require.False(t, topicPool.pendingPeers[clientID].added)
@ -413,7 +444,7 @@ func TestServerIgnoresInboundPeer(t *testing.T) {
errch = helpers.WaitForPeerAsync(server, client.Self().String(), p2p.PeerEventTypeDrop, time.Second)
// simulate that event was received by a topic pool.
// topic pool will ignore this even because it sees that it is inbound connection.
topicPool.ConfirmAdded(server, client.Self().ID)
topicPool.ConfirmAdded(server, clientID)
require.Contains(t, topicPool.pendingPeers, clientID)
require.False(t, topicPool.pendingPeers[clientID].dismissed)

View File

@ -3,17 +3,17 @@ package verifier
import (
"context"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
)
// LocalVerifier verifies nodes based on a provided local list.
type LocalVerifier struct {
KnownPeers map[discover.NodeID]struct{}
KnownPeers map[enode.ID]struct{}
}
// NewLocalVerifier returns a new LocalVerifier instance.
func NewLocalVerifier(peers []discover.NodeID) *LocalVerifier {
knownPeers := make(map[discover.NodeID]struct{})
func NewLocalVerifier(peers []enode.ID) *LocalVerifier {
knownPeers := make(map[enode.ID]struct{})
for _, peer := range peers {
knownPeers[peer] = struct{}{}
}
@ -22,7 +22,7 @@ func NewLocalVerifier(peers []discover.NodeID) *LocalVerifier {
}
// VerifyNode checks if a given node is trusted using a local list.
func (v *LocalVerifier) VerifyNode(_ context.Context, nodeID discover.NodeID) bool {
func (v *LocalVerifier) VerifyNode(_ context.Context, nodeID enode.ID) bool {
if _, ok := v.KnownPeers[nodeID]; ok {
return true
}

View File

@ -4,14 +4,14 @@ import (
"context"
"testing"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/stretchr/testify/require"
)
func TestLocalVerifierForNodeIDTypes(t *testing.T) {
nodeID := discover.NodeID{1}
nodeID := enode.ID{1}
v := NewLocalVerifier([]discover.NodeID{{1}})
v := NewLocalVerifier([]enode.ID{{1}})
require.True(t, v.VerifyNode(context.TODO(), nodeID))
require.False(t, v.VerifyNode(context.TODO(), discover.NodeID{2}))
require.False(t, v.VerifyNode(context.TODO(), enode.ID{2}))
}

View File

@ -15,7 +15,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/services/shhext/chat"
whisper "github.com/status-im/whisper/whisperv6"
)
@ -163,7 +163,7 @@ func (api *PublicAPI) RequestMessages(_ context.Context, r MessagesRequest) (hex
var err error
mailServerNode, err := discover.ParseNode(r.MailServerPeer)
mailServerNode, err := enode.ParseV4(r.MailServerPeer)
if err != nil {
return nil, fmt.Errorf("%v: %v", ErrInvalidMailServerPeer, err)
}
@ -179,10 +179,7 @@ func (api *PublicAPI) RequestMessages(_ context.Context, r MessagesRequest) (hex
return nil, fmt.Errorf("%v: %v", ErrInvalidSymKeyID, err)
}
} else {
publicKey, err = mailServerNode.ID.Pubkey()
if err != nil {
return nil, fmt.Errorf("%v: %v", ErrInvalidPublicKey, err)
}
publicKey = mailServerNode.Pubkey()
}
payload, err := makePayload(r)
@ -203,7 +200,7 @@ func (api *PublicAPI) RequestMessages(_ context.Context, r MessagesRequest) (hex
}
hash := envelope.Hash()
if err := shh.RequestHistoricMessages(mailServerNode.ID[:], envelope); err != nil {
if err := shh.RequestHistoricMessages(mailServerNode.ID().Bytes(), envelope); err != nil {
return nil, err
}

View File

@ -3,7 +3,7 @@ package benchmarks
import (
"flag"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
)
var (
@ -18,10 +18,10 @@ var (
msgBatchSize = flag.Int64("msgbatchsize", int64(20), "Number of messages to send in a batch")
)
var peerEnode *discover.Node
var peerEnode *enode.Node
func init() {
flag.Parse()
peerEnode = discover.MustParseNode(*peerURL)
peerEnode = enode.MustParseV4(*peerURL)
}

View File

@ -6,7 +6,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
whisper "github.com/status-im/whisper/whisperv6"
)
@ -33,7 +33,7 @@ func createNode() (*node.Node, error) {
})
}
func addPeerWithConfirmation(server *p2p.Server, node *discover.Node) error {
func addPeerWithConfirmation(server *p2p.Server, node *enode.Node) error {
ch := make(chan *p2p.PeerEvent, server.MaxPeers)
subscription := server.SubscribeEvents(ch)
defer subscription.Unsubscribe()
@ -41,7 +41,7 @@ func addPeerWithConfirmation(server *p2p.Server, node *discover.Node) error {
server.AddPeer(node)
ev := <-ch
if ev.Type != p2p.PeerEventTypeAdd || ev.Peer != node.ID {
if ev.Type != p2p.PeerEventTypeAdd || ev.Peer == node.ID() {
return fmt.Errorf("got unexpected event: %+v", ev)
}

View File

@ -66,7 +66,7 @@ func (s *WhisperMailboxSuite) TestRequestMessageFromMailboxAsync() {
time.Sleep(time.Second)
// Mark mailbox node trusted.
err = senderWhisperService.AllowP2PMessagesFromPeer(mailboxNode.Server().Self().ID[:])
err = senderWhisperService.AllowP2PMessagesFromPeer(mailboxNode.Server().Self().ID().Bytes())
s.Require().NoError(err)
// Generate mailbox symkey.
@ -167,9 +167,9 @@ func (s *WhisperMailboxSuite) TestRequestMessagesInGroupChat() {
mailboxNode := mailboxBackend.StatusNode().GethNode()
mailboxEnode := mailboxNode.Server().NodeInfo().Enode
aliceErrCh := helpers.WaitForPeerAsync(aliceBackend.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, time.Second)
bobErrCh := helpers.WaitForPeerAsync(bobBackend.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, time.Second)
charlieErrCh := helpers.WaitForPeerAsync(charlieBackend.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, time.Second)
aliceErrCh := helpers.WaitForPeerAsync(aliceBackend.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, 5*time.Second)
bobErrCh := helpers.WaitForPeerAsync(bobBackend.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, 5*time.Second)
charlieErrCh := helpers.WaitForPeerAsync(charlieBackend.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, 5*time.Second)
s.Require().NoError(aliceBackend.StatusNode().AddPeer(mailboxEnode))
s.Require().NoError(bobBackend.StatusNode().AddPeer(mailboxEnode))
@ -345,7 +345,7 @@ func (s *WhisperMailboxSuite) TestRequestMessagesWithPagination() {
clientRPCClient := client.StatusNode().RPCPrivateClient()
// Add mailbox to client's peers
errCh := helpers.WaitForPeerAsync(client.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, time.Second)
errCh := helpers.WaitForPeerAsync(client.StatusNode().Server(), mailboxEnode, p2p.PeerEventTypeAdd, 5*time.Second)
s.Require().NoError(client.StatusNode().AddPeer(mailboxEnode))
s.Require().NoError(<-errCh)

View File

@ -5,7 +5,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
)
var (
@ -23,7 +23,7 @@ func waitForPeer(p *p2p.Server, u string, e p2p.PeerEventType, t time.Duration,
if u == "" {
return ErrEmptyPeerURL
}
parsedPeer, err := discover.ParseNode(u)
parsedPeer, err := enode.ParseV4(u)
if err != nil {
return err
}
@ -36,7 +36,7 @@ func waitForPeer(p *p2p.Server, u string, e p2p.PeerEventType, t time.Duration,
for {
select {
case ev := <-ch:
if ev.Type == e && ev.Peer == parsedPeer.ID {
if ev.Type == e && ev.Peer == parsedPeer.ID() {
return nil
}
case err := <-subscription.Err():

View File

@ -27,6 +27,6 @@ swarm/services @zelig
swarm/state @justelad
swarm/storage/encryption @gbalint @zelig @nagydani
swarm/storage/mock @janos
swarm/storage/mru @nolash
swarm/storage/feed @nolash @jpeletier
swarm/testutil @lmars
whisper/ @gballet @gluk256

View File

@ -1,16 +1,40 @@
# Contributing
Thank you for considering to help out with the source code! We welcome
contributions from anyone on the internet, and are grateful for even the
smallest of fixes!
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a
pull request for the maintainers to review and merge into the main code base. If
you wish to submit more complex changes though, please check up with the core
devs first on [our gitter channel](https://gitter.im/ethereum/go-ethereum) to
ensure those changes are in line with the general philosophy of the project
and/or get some early feedback which can make both your efforts much lighter as
well as our review and merge procedures quick and simple.
## Coding guidelines
Please make sure your contributions adhere to our coding guidelines:
* Code must adhere to the official Go
[formatting](https://golang.org/doc/effective_go.html#formatting) guidelines
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
* Code must be documented adhering to the official Go
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
* Pull requests need to be based on and opened against the `master` branch.
* Commit messages should be prefixed with the package(s) they modify.
* E.g. "eth, rpc: make trace configs optional"
## Can I have feature X
Before you do a feature request please check and make sure that it isn't possible
through some other means. The JavaScript enabled console is a powerful feature
in the right hands. Please check our [Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
Before you submit a feature request, please check and make sure that it isn't
possible through some other means. The JavaScript-enabled console is a powerful
feature in the right hands. Please check our
[Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
and help.
## Contributing
## Configuration, dependencies, and tests
If you'd like to contribute to go-ethereum please fork, fix, commit and
send a pull request. Commits which do not comply with the coding standards
are ignored (use gofmt!).
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, testing, and
dependency management.
Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, managing project dependencies
and testing procedures.

View File

@ -3,17 +3,6 @@ go_import_path: github.com/ethereum/go-ethereum
sudo: false
matrix:
include:
- os: linux
dist: trusty
sudo: required
go: 1.9.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 $TEST_PACKAGES
- os: linux
dist: trusty
sudo: required
@ -56,7 +45,8 @@ matrix:
- go run build/ci.go lint
# This builder does the Ubuntu PPA upload
- os: linux
- if: type = push
os: linux
dist: trusty
go: 1.11.x
env:
@ -74,7 +64,8 @@ matrix:
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
# This builder does the Linux Azure uploads
- os: linux
- if: type = push
os: linux
dist: trusty
sudo: required
go: 1.11.x
@ -107,7 +98,8 @@ matrix:
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Linux Azure MIPS xgo uploads
- os: linux
- if: type = push
os: linux
dist: trusty
services:
- docker
@ -134,7 +126,8 @@ matrix:
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Android Maven and Azure uploads
- os: linux
- if: type = push
os: linux
dist: trusty
addons:
apt:
@ -155,7 +148,7 @@ matrix:
git:
submodules: false # avoid cloning ethereum/tests
before_install:
- curl https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz | tar -xz
- curl https://storage.googleapis.com/golang/go1.11.1.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go
- export GOPATH=$HOME/go
@ -171,7 +164,8 @@ matrix:
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
- os: osx
- if: type = push
os: osx
go: 1.11.x
env:
- azure-osx
@ -199,7 +193,8 @@ matrix:
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
# This builder does the Azure archive purges to avoid accumulating junk
- os: linux
- if: type = cron
os: linux
dist: trusty
go: 1.11.x
env:
@ -208,10 +203,3 @@ matrix:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go purge -store gethstore/builds -days 14
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
on_success: change
on_failure: always

View File

@ -57,6 +57,9 @@ devtools:
@type "solc" 2> /dev/null || echo 'Please install solc'
@type "protoc" 2> /dev/null || echo 'Please install protoc'
swarm-devtools:
env GOBIN= go install ./cmd/swarm/mimegen
# Cross Compilation Targets (xgo)
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios

View File

@ -1,8 +1,8 @@
diff --git c/p2p/peer.go w/p2p/peer.go
index 73e33418e..322268b28 100644
--- c/p2p/peer.go
+++ w/p2p/peer.go
@@ -22,6 +22,7 @@ import (
diff --git a/p2p/peer.go b/p2p/peer.go
index af019d0..cfd63af 100644
--- a/p2p/peer.go
+++ b/p2p/peer.go
@@ -23,6 +23,7 @@ import (
"net"
"sort"
"sync"
@ -10,7 +10,7 @@ index 73e33418e..322268b28 100644
"time"
"github.com/ethereum/go-ethereum/common/mclock"
@@ -38,7 +39,10 @@ const (
@@ -44,7 +45,10 @@ const (
snappyProtocolVersion = 5
@ -22,7 +22,7 @@ index 73e33418e..322268b28 100644
)
const (
@@ -100,6 +104,7 @@ type Peer struct {
@@ -106,6 +110,7 @@ type Peer struct {
log log.Logger
created mclock.AbsTime
@ -30,7 +30,7 @@ index 73e33418e..322268b28 100644
wg sync.WaitGroup
protoErr chan error
closed chan struct{}
@@ -118,6 +123,11 @@ func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer {
@@ -125,6 +130,11 @@ func NewPeer(id enode.ID, name string, caps []Cap) *Peer {
return peer
}
@ -40,9 +40,9 @@ index 73e33418e..322268b28 100644
+}
+
// ID returns the node's public key.
func (p *Peer) ID() discover.NodeID {
return p.rw.id
@@ -188,8 +198,10 @@ func (p *Peer) run() (remoteRequested bool, err error) {
func (p *Peer) ID() enode.ID {
return p.rw.node.ID()
@@ -201,8 +211,10 @@ func (p *Peer) run() (remoteRequested bool, err error) {
readErr = make(chan error, 1)
reason DiscReason // sent to the peer
)
@ -55,7 +55,7 @@ index 73e33418e..322268b28 100644
go p.pingLoop()
// Start all protocol handlers.
@@ -248,7 +260,24 @@ func (p *Peer) pingLoop() {
@@ -262,7 +274,24 @@ func (p *Peer) pingLoop() {
}
}
@ -81,7 +81,7 @@ index 73e33418e..322268b28 100644
defer p.wg.Done()
for {
msg, err := p.rw.ReadMsg()
@@ -261,6 +290,7 @@ func (p *Peer) readLoop(errc chan<- error) {
@@ -275,6 +304,7 @@ func (p *Peer) readLoop(errc chan<- error) {
errc <- err
return
}
@ -89,11 +89,11 @@ index 73e33418e..322268b28 100644
}
}
diff --git c/p2p/server.go w/p2p/server.go
index c41d1dc15..04c6f7147 100644
--- c/p2p/server.go
+++ w/p2p/server.go
@@ -45,7 +45,7 @@ const (
diff --git a/p2p/server.go b/p2p/server.go
index 40db758..8546b02 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -49,7 +49,7 @@ const (
// Maximum time allowed for reading a complete message.
// This is effectively the amount of time a connection can be idle.
@ -102,11 +102,11 @@ index c41d1dc15..04c6f7147 100644
// Maximum amount of time allowed for writing a complete message.
frameWriteTimeout = 20 * time.Second
diff --git c/whisper/whisperv6/peer.go w/whisper/whisperv6/peer.go
index 427127290..c30e92d1c 100644
--- c/whisper/whisperv6/peer.go
+++ w/whisper/whisperv6/peer.go
@@ -187,6 +187,10 @@ func (peer *Peer) expire() {
diff --git a/whisper/whisperv6/peer.go b/whisper/whisperv6/peer.go
index eb17d2d..2b7687e 100644
--- a/whisper/whisperv6/peer.go
+++ b/whisper/whisperv6/peer.go
@@ -195,6 +195,10 @@ func (peer *Peer) expire() {
// broadcast iterates over the collection of envelopes and transmits yet unknown
// ones over the network.
func (peer *Peer) broadcast() error {

View File

@ -35,7 +35,7 @@ index e03ec9d..1665539 100644
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/p2p/discover"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/p2p/discover"
+ "github.com/ethereum/go-ethereum/p2p/enode"
)
// EventType used to define known envelope events.
@ -63,7 +63,7 @@ index e03ec9d..1665539 100644
- Peer discover.NodeID
+ Event EventType
+ Hash common.Hash
+ Peer discover.NodeID
+ Peer enode.ID
}
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 697f0ec..4a7b006 100644

View File

@ -20,7 +20,7 @@ index 1665539d6..fe7570ed5 100644
@@ -24,4 +28,5 @@ type EnvelopeEvent struct {
Event EventType
Hash common.Hash
Peer discover.NodeID
Peer enode.ID
+ Data interface{}
}
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
diff --git a/metrics/metrics.go b/metrics/metrics.go
index d4d703dfe..58f0dc765 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -8,6 +8,7 @@ package metrics
import (
"os"
"runtime"
+ "strconv"
"strings"
"time"
@@ -21,6 +22,10 @@ import (
// for less cluttered pprof profiles.
var Enabled bool = false
+// EnabledStr has the same function as Enabled but
+// it can be set during compilation (linking) time.
+var EnabledStr = "false"
+
// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections.
const MetricsEnabledFlag = "metrics"
const DashboardEnabledFlag = "dashboard"
@@ -35,6 +40,11 @@ func init() {
Enabled = true
}
}
+
+ if v, err := strconv.ParseBool(EnabledStr); err == nil && v {
+ log.Info("Enabling metrics collection")
+ Enabled = v
+ }
}
// CollectProcessMetrics periodically collects various metrics about the running

View File

@ -137,6 +137,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
// MethodById looks up a method by the 4-byte id
// returns nil if none found
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
if len(sigdata) < 4 {
return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata))
}
for _, method := range abi.Methods {
if bytes.Equal(method.Id(), sigdata[:4]) {
return &method, nil

View File

@ -208,7 +208,7 @@ func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Ad
}
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
// chain doens't have miners, we just return a gas price of 1 for any call.
// chain doesn't have miners, we just return a gas price of 1 for any call.
func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
return big.NewInt(1), nil
}

View File

@ -23,13 +23,13 @@ package bind
import (
"bytes"
"fmt"
"go/format"
"regexp"
"strings"
"text/template"
"unicode"
"github.com/ethereum/go-ethereum/accounts/abi"
"golang.org/x/tools/imports"
)
// Lang is a target programming language selector to generate bindings for.
@ -145,9 +145,9 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
if err := tmpl.Execute(buffer, data); err != nil {
return "", err
}
// For Go bindings pass the code through goimports to clean it up and double check
// For Go bindings pass the code through gofmt to clean it up
if lang == LangGo {
code, err := imports.Process(".", buffer.Bytes(), nil)
code, err := format.Source(buffer.Bytes())
if err != nil {
return "", fmt.Errorf("%v\n%s", err, buffer)
}

View File

@ -64,6 +64,30 @@ const tmplSourceGo = `
package {{.Package}}
import (
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.NotFound
_ = abi.U256
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
)
{{range $contract := .Contracts}}
// {{.Type}}ABI is the input ABI used to generate the binding from.
const {{.Type}}ABI = "{{.InputABI}}"

View File

@ -23,8 +23,8 @@ environment:
install:
- git submodule update --init
- rmdir C:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.windows-%GETH_ARCH%.zip
- 7z x go1.11.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.1.windows-%GETH_ARCH%.zip
- 7z x go1.11.1.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version
- gcc --version

View File

@ -320,9 +320,7 @@ func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd
// "tests" also includes static analysis tools such as vet.
func doTest(cmdline []string) {
var (
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
)
coverage := flag.Bool("coverage", false, "Whether to record code coverage")
flag.CommandLine.Parse(cmdline)
env := build.Env()
@ -332,14 +330,11 @@ func doTest(cmdline []string) {
}
packages = build.ExpandPackagesNoVendor(packages)
// Run analysis tools before the tests.
build.MustRun(goTool("vet", packages...))
// Run the actual tests.
gotest := goTool("test", buildFlags(env)...)
// Test a single package at a time. CI builders are slow
// and some tests run into timeouts under load.
gotest.Args = append(gotest.Args, "-p", "1")
gotest := goTool("test", buildFlags(env)...)
gotest.Args = append(gotest.Args, "-p", "1", "-timeout", "5m")
if *coverage {
gotest.Args = append(gotest.Args, "-covermode=atomic", "-cover")
}
@ -1040,7 +1035,7 @@ func xgoTool(args []string) *exec.Cmd {
func doPurge(cmdline []string) {
var (
store = flag.String("store", "", `Destination from where to purge archives (usually "gethstore/builds")`)
limit = flag.Int("days", 30, `Age threshold above which to delete unstalbe archives`)
limit = flag.Int("days", 30, `Age threshold above which to delete unstable archives`)
)
flag.CommandLine.Parse(cmdline)

View File

@ -75,7 +75,7 @@ func main() {
bins []string
types []string
)
if *solFlag != "" || *abiFlag == "-" {
if *solFlag != "" || (*abiFlag == "-" && *pkgFlag == "") {
// Generate the list of types to exclude from binding
exclude := make(map[string]bool)
for _, kind := range strings.Split(*excFlag, ",") {
@ -111,7 +111,13 @@ func main() {
}
} else {
// Otherwise load up the ABI, optional bytecode and type name from the parameters
abi, err := ioutil.ReadFile(*abiFlag)
var abi []byte
var err error
if *abiFlag == "-" {
abi, err = ioutil.ReadAll(os.Stdin)
} else {
abi, err = ioutil.ReadFile(*abiFlag)
}
if err != nil {
fmt.Printf("Failed to read input ABI: %v\n", err)
os.Exit(-1)
@ -155,6 +161,5 @@ func contractsFromStdin() (map[string]*compiler.Contract, error) {
if err != nil {
return nil, err
}
return compiler.ParseCombinedJSON(bytes, "", "", "", "")
}

View File

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
)
@ -85,7 +86,7 @@ func main() {
}
if *writeAddr {
fmt.Printf("%v\n", discover.PubkeyID(&nodeKey.PublicKey))
fmt.Printf("%v\n", enode.PubkeyToIDV4(&nodeKey.PublicKey))
os.Exit(0)
}

View File

@ -875,3 +875,4 @@ There are a couple of implementation for a UI. We'll try to keep this list up to
| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |
| Clef UI| https://github.com/kyokan/clef-ui| Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: | :+1: (approve tx only)|

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,6 +1,13 @@
### Changelog for external API
#### 4.0.0
* The external `account_Ecrecover`-method was removed.
* The external `account_Import`-method was removed.
#### 3.0.0
* The external `account_List`-method was changed to not expose `url`, which contained info about the local filesystem. It now returns only a list of addresses.
#### 2.0.0

View File

@ -1,5 +1,21 @@
### Changelog for internal API (ui-api)
### 2.1.0
* Add `OnInputRequired(info UserInputRequest)` to internal API. This method is used when Clef needs user input, e.g. passwords.
The following structures are used:
```golang
UserInputRequest struct {
Prompt string `json:"prompt"`
Title string `json:"title"`
IsPassword bool `json:"isPassword"`
}
UserInputResponse struct {
Text string `json:"text"`
}
```
### 2.0.0
* Modify how `call_info` on a transaction is conveyed. New format:

View File

@ -48,7 +48,7 @@ import (
)
// ExternalAPIVersion -- see extapi_changelog.md
const ExternalAPIVersion = "2.0.0"
const ExternalAPIVersion = "3.0.0"
// InternalAPIVersion -- see intapi_changelog.md
const InternalAPIVersion = "2.0.0"
@ -70,6 +70,10 @@ var (
Value: 4,
Usage: "log level to emit to the screen",
}
advancedMode = cli.BoolFlag{
Name: "advanced",
Usage: "If enabled, issues warnings instead of rejections for suspicious requests. Default off",
}
keystoreFlag = cli.StringFlag{
Name: "keystore",
Value: filepath.Join(node.DefaultDataDir(), "keystore"),
@ -191,6 +195,7 @@ func init() {
ruleFlag,
stdiouiFlag,
testFlag,
advancedMode,
}
app.Action = signer
app.Commands = []cli.Command{initCommand, attestCommand, addCredentialCommand}
@ -384,7 +389,8 @@ func signer(c *cli.Context) error {
c.String(keystoreFlag.Name),
c.Bool(utils.NoUSBFlag.Name),
ui, db,
c.Bool(utils.LightKDFFlag.Name))
c.Bool(utils.LightKDFFlag.Name),
c.Bool(advancedMode.Name))
api = apiImpl

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -31,43 +31,51 @@ NOTE: This file does not contain your accounts. Those need to be backed up separ
## Creating rules
Now, you can create a rule-file.
Now, you can create a rule-file. Note that it is not mandatory to use predefined rules, but it's really handy.
```javascript
function ApproveListing(){
return "Approve"
}
```
Get the `sha256` hash....
Get the `sha256` hash. If you have openssl, you can do `openssl sha256 rules.js`...
```text
#sha256sum rules.js
6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72 rules.js
```
...And then `attest` the file:
...now `attest` the file...
```text
#./signer attest 6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72
INFO [02-21|12:14:38] Ruleset attestation updated sha256=6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72
```
At this point, we then start the signer with the rule-file:
...and (this is required only for non-production versions) load a mock-up `4byte.json` by copying the file from the source to your current working directory:
```text
#./signer --rules rules.json
#cp $GOPATH/src/github.com/ethereum/go-ethereum/cmd/clef/4byte.json $PWD
```
INFO [02-21|12:15:18] Using CLI as UI-channel
INFO [02-21|12:15:18] Loaded 4byte db signatures=5509 file=./4byte.json
INFO [02-21|12:15:18] Could not load rulefile, rules not enabled file=rulefile
DEBUG[02-21|12:15:18] FS scan times list=35.335µs set=5.536µs diff=5.073µs
DEBUG[02-21|12:15:18] Ledger support enabled
DEBUG[02-21|12:15:18] Trezor support enabled
INFO [02-21|12:15:18] Audit logs configured file=audit.log
INFO [02-21|12:15:18] HTTP endpoint opened url=http://localhost:8550
At this point, we can start the signer with the rule-file:
```text
#./signer --rules rules.js --rpc
INFO [09-25|20:28:11.866] Using CLI as UI-channel
INFO [09-25|20:28:11.876] Loaded 4byte db signatures=5509 file=./4byte.json
INFO [09-25|20:28:11.877] Rule engine configured file=./rules.js
DEBUG[09-25|20:28:11.877] FS scan times list=100.781µs set=13.253µs diff=5.761µs
DEBUG[09-25|20:28:11.884] Ledger support enabled
DEBUG[09-25|20:28:11.888] Trezor support enabled
INFO [09-25|20:28:11.888] Audit logs configured file=audit.log
DEBUG[09-25|20:28:11.888] HTTP registered namespace=account
INFO [09-25|20:28:11.890] HTTP endpoint opened url=http://localhost:8550
DEBUG[09-25|20:28:11.890] IPC registered namespace=account
INFO [09-25|20:28:11.890] IPC endpoint opened url=<nil>
------- Signer info -------
* extapi_version : 2.0.0
* intapi_version : 2.0.0
* extapi_http : http://localhost:8550
* extapi_ipc : <nil>
* extapi_version : 2.0.0
* intapi_version : 1.2.0
```
Any list-requests will now be auto-approved by our rule-file.
@ -107,16 +115,16 @@ The `master_seed` was then used to derive a few other things:
## Adding credentials
In order to make more useful rules; sign transactions, the signer needs access to the passwords needed to unlock keystores.
In order to make more useful rules like signing transactions, the signer needs access to the passwords needed to unlock keystores.
```text
#./signer addpw 0x694267f14675d7e1b9494fd8d72fefe1755710fa test
#./signer addpw "0x694267f14675d7e1b9494fd8d72fefe1755710fa" "test_password"
INFO [02-21|13:43:21] Credential store updated key=0x694267f14675d7e1b9494fd8d72fefe1755710fa
```
## More advanced rules
Now let's update the rules to make use of credentials
Now let's update the rules to make use of credentials:
```javascript
function ApproveListing(){
@ -134,13 +142,15 @@ function ApproveSignData(r){
}
```
In this example,
* any requests to sign data with the account `0x694...` will be
* auto-approved if the message contains with `bazonk`,
* and auto-rejected if it does not.
* Any other signing-requests will be passed along for manual approve/reject.
In this example:
* Any requests to sign data with the account `0x694...` will be
* auto-approved if the message contains with `bazonk`
* auto-rejected if it does not.
* Any other signing-requests will be passed along for manual approve/reject.
..attest the new file
_Note: make sure that `0x694...` is an account you have access to. You can create it either via the clef or the traditional account cli tool. If the latter was chosen, make sure both clef and geth use the same keystore by specifing `--keystore path/to/your/keystore` when running clef._
Attest the new file...
```text
#sha256sum rules.js
2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f rules.js
@ -153,23 +163,26 @@ INFO [02-21|14:36:30] Ruleset attestation updated sha256=2a0cb661da
And start the signer:
```
#./signer --rules rules.js
#./signer --rules rules.js --rpc
INFO [02-21|14:41:56] Using CLI as UI-channel
INFO [02-21|14:41:56] Loaded 4byte db signatures=5509 file=./4byte.json
INFO [02-21|14:41:56] Rule engine configured file=rules.js
DEBUG[02-21|14:41:56] FS scan times list=34.607µs set=4.509µs diff=4.87µs
DEBUG[02-21|14:41:56] Ledger support enabled
DEBUG[02-21|14:41:56] Trezor support enabled
INFO [02-21|14:41:56] Audit logs configured file=audit.log
INFO [02-21|14:41:56] HTTP endpoint opened url=http://localhost:8550
INFO [09-25|21:02:16.450] Using CLI as UI-channel
INFO [09-25|21:02:16.466] Loaded 4byte db signatures=5509 file=./4byte.json
INFO [09-25|21:02:16.467] Rule engine configured file=./rules.js
DEBUG[09-25|21:02:16.468] FS scan times list=1.45262ms set=21.926µs diff=6.944µs
DEBUG[09-25|21:02:16.473] Ledger support enabled
DEBUG[09-25|21:02:16.475] Trezor support enabled
INFO [09-25|21:02:16.476] Audit logs configured file=audit.log
DEBUG[09-25|21:02:16.476] HTTP registered namespace=account
INFO [09-25|21:02:16.478] HTTP endpoint opened url=http://localhost:8550
DEBUG[09-25|21:02:16.478] IPC registered namespace=account
INFO [09-25|21:02:16.478] IPC endpoint opened url=<nil>
------- Signer info -------
* extapi_version : 2.0.0
* intapi_version : 1.2.0
* intapi_version : 2.0.0
* extapi_http : http://localhost:8550
* extapi_ipc : <nil>
INFO [02-21|14:41:56] error occurred during execution error="ReferenceError: 'OnSignerStartup' is not defined"
```
And then test signing, once with `bazonk` and once without:
```
@ -190,9 +203,9 @@ INFO [02-21|14:42:56] Op rejected
The signer also stores all traffic over the external API in a log file. The last 4 lines shows the two requests and their responses:
```text
#tail audit.log -n 4
#tail -n 4 audit.log
t=2018-02-21T14:42:41+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49706\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=202062617a6f6e6b2062617a2067617a0a
t=2018-02-21T14:42:42+0100 lvl=info msg=Sign api=signer type=response data=93e6161840c3ae1efc26dc68dedab6e8fc233bb3fefa1b4645dbf6609b93dace160572ea4ab33240256bb6d3dadb60dcd9c515d6374d3cf614ee897408d41d541c error=nil
t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49708\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=2020626f6e6b2062617a2067617a0a
t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=response data= error="Request denied"
```
```

View File

@ -97,6 +97,10 @@ func stateTestCmd(ctx *cli.Context) error {
// Run the test and aggregate the result
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
state, err := test.Run(st, cfg)
// print state root for evmlab tracing
if ctx.GlobalBool(MachineFlag.Name) && state != nil {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false))
}
if err != nil {
// Test failed, mark as so and dump any state to aid debugging
result.Pass, result.Error = false, err.Error()
@ -105,10 +109,6 @@ func stateTestCmd(ctx *cli.Context) error {
result.State = &dump
}
}
// print state root for evmlab tracing (already committed above, so no need to delete objects again
if ctx.GlobalBool(MachineFlag.Name) && state != nil {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false))
}
results = append(results, *result)

View File

@ -54,8 +54,8 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/net/websocket"
@ -255,8 +255,10 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
return nil, err
}
for _, boot := range enodes {
old, _ := discover.ParseNode(boot.String())
stack.Server().AddPeer(old)
old, err := enode.ParseV4(boot.String())
if err != nil {
stack.Server().AddPeer(old)
}
}
// Attach to the client and retrieve and interesting metadatas
api, err := stack.Attach()

View File

@ -47,7 +47,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc"
@ -285,7 +285,7 @@ func createNode(ctx *cli.Context) error {
if err != nil {
return err
}
config.ID = discover.PubkeyID(&privKey.PublicKey)
config.ID = enode.PubkeyToIDV4(&privKey.PublicKey)
config.PrivateKey = privKey
}
if services := ctx.String("services"); services != "" {

View File

@ -42,7 +42,7 @@ ADD genesis.json /genesis.json
RUN \
echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}}
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gastarget {{.GasTarget}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh
echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --nat extip:{{.IP}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gastarget {{.GasTarget}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh
ENTRYPOINT ["/bin/sh", "geth.sh"]
`
@ -99,6 +99,7 @@ func deployNode(client *sshClient, network string, bootnodes []string, config *n
template.Must(template.New("").Parse(nodeDockerfile)).Execute(dockerfile, map[string]interface{}{
"NetworkID": config.network,
"Port": config.port,
"IP": client.address,
"Peers": config.peersTotal,
"LightFlag": lightFlag,
"Bootnodes": strings.Join(bootnodes, ","),
@ -227,10 +228,10 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
// Container available, retrieve its node ID and its genesis json
var out []byte
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.id --cache=16 attach", network, kind)); err != nil {
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.enode --cache=16 attach", network, kind)); err != nil {
return nil, ErrServiceUnreachable
}
id := bytes.Trim(bytes.TrimSpace(out), "\"")
enode := bytes.Trim(bytes.TrimSpace(out), "\"")
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /genesis.json", network, kind)); err != nil {
return nil, ErrServiceUnreachable
@ -265,7 +266,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
gasLimit: gasLimit,
gasPrice: gasPrice,
}
stats.enode = fmt.Sprintf("enode://%s@%s:%d", id, client.address, stats.port)
stats.enode = string(enode)
return stats, nil
}

View File

@ -130,7 +130,7 @@ func accessNewACT(ctx *cli.Context) {
if err != nil {
utils.Fatalf("had an error reading the grantee public key list")
}
pkGrantees = strings.Split(string(bytes), "\n")
pkGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
}
if passGranteesFilename != "" {
@ -138,7 +138,7 @@ func accessNewACT(ctx *cli.Context) {
if err != nil {
utils.Fatalf("could not read password filename: %v", err)
}
passGrantees = strings.Split(string(bytes), "\n")
passGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
}
accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees)
if err != nil {

View File

@ -59,27 +59,28 @@ var (
//constants for environment variables
const (
SWARM_ENV_CHEQUEBOOK_ADDR = "SWARM_CHEQUEBOOK_ADDR"
SWARM_ENV_ACCOUNT = "SWARM_ACCOUNT"
SWARM_ENV_LISTEN_ADDR = "SWARM_LISTEN_ADDR"
SWARM_ENV_PORT = "SWARM_PORT"
SWARM_ENV_NETWORK_ID = "SWARM_NETWORK_ID"
SWARM_ENV_SWAP_ENABLE = "SWARM_SWAP_ENABLE"
SWARM_ENV_SWAP_API = "SWARM_SWAP_API"
SWARM_ENV_SYNC_DISABLE = "SWARM_SYNC_DISABLE"
SWARM_ENV_SYNC_UPDATE_DELAY = "SWARM_ENV_SYNC_UPDATE_DELAY"
SWARM_ENV_LIGHT_NODE_ENABLE = "SWARM_LIGHT_NODE_ENABLE"
SWARM_ENV_DELIVERY_SKIP_CHECK = "SWARM_DELIVERY_SKIP_CHECK"
SWARM_ENV_ENS_API = "SWARM_ENS_API"
SWARM_ENV_ENS_ADDR = "SWARM_ENS_ADDR"
SWARM_ENV_CORS = "SWARM_CORS"
SWARM_ENV_BOOTNODES = "SWARM_BOOTNODES"
SWARM_ENV_PSS_ENABLE = "SWARM_PSS_ENABLE"
SWARM_ENV_STORE_PATH = "SWARM_STORE_PATH"
SWARM_ENV_STORE_CAPACITY = "SWARM_STORE_CAPACITY"
SWARM_ENV_STORE_CACHE_CAPACITY = "SWARM_STORE_CACHE_CAPACITY"
SWARM_ACCESS_PASSWORD = "SWARM_ACCESS_PASSWORD"
GETH_ENV_DATADIR = "GETH_DATADIR"
SWARM_ENV_CHEQUEBOOK_ADDR = "SWARM_CHEQUEBOOK_ADDR"
SWARM_ENV_ACCOUNT = "SWARM_ACCOUNT"
SWARM_ENV_LISTEN_ADDR = "SWARM_LISTEN_ADDR"
SWARM_ENV_PORT = "SWARM_PORT"
SWARM_ENV_NETWORK_ID = "SWARM_NETWORK_ID"
SWARM_ENV_SWAP_ENABLE = "SWARM_SWAP_ENABLE"
SWARM_ENV_SWAP_API = "SWARM_SWAP_API"
SWARM_ENV_SYNC_DISABLE = "SWARM_SYNC_DISABLE"
SWARM_ENV_SYNC_UPDATE_DELAY = "SWARM_ENV_SYNC_UPDATE_DELAY"
SWARM_ENV_MAX_STREAM_PEER_SERVERS = "SWARM_ENV_MAX_STREAM_PEER_SERVERS"
SWARM_ENV_LIGHT_NODE_ENABLE = "SWARM_LIGHT_NODE_ENABLE"
SWARM_ENV_DELIVERY_SKIP_CHECK = "SWARM_DELIVERY_SKIP_CHECK"
SWARM_ENV_ENS_API = "SWARM_ENS_API"
SWARM_ENV_ENS_ADDR = "SWARM_ENS_ADDR"
SWARM_ENV_CORS = "SWARM_CORS"
SWARM_ENV_BOOTNODES = "SWARM_BOOTNODES"
SWARM_ENV_PSS_ENABLE = "SWARM_PSS_ENABLE"
SWARM_ENV_STORE_PATH = "SWARM_STORE_PATH"
SWARM_ENV_STORE_CAPACITY = "SWARM_STORE_CAPACITY"
SWARM_ENV_STORE_CACHE_CAPACITY = "SWARM_STORE_CACHE_CAPACITY"
SWARM_ACCESS_PASSWORD = "SWARM_ACCESS_PASSWORD"
GETH_ENV_DATADIR = "GETH_DATADIR"
)
// These settings ensure that TOML keys use the same names as Go struct fields.
@ -124,7 +125,7 @@ func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) {
//get the account for the provided swarm account
prvkey := getAccount(config.BzzAccount, ctx, stack)
//set the resolved config path (geth --datadir)
config.Path = stack.InstanceDir()
config.Path = expandPath(stack.InstanceDir())
//finally, initialize the configuration
config.Init(prvkey)
//configuration phase completed here
@ -175,14 +176,18 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
}
if networkid := ctx.GlobalString(SwarmNetworkIdFlag.Name); networkid != "" {
if id, _ := strconv.Atoi(networkid); id != 0 {
currentConfig.NetworkID = uint64(id)
id, err := strconv.ParseUint(networkid, 10, 64)
if err != nil {
utils.Fatalf("invalid cli flag %s: %v", SwarmNetworkIdFlag.Name, err)
}
if id != 0 {
currentConfig.NetworkID = id
}
}
if ctx.GlobalIsSet(utils.DataDirFlag.Name) {
if datadir := ctx.GlobalString(utils.DataDirFlag.Name); datadir != "" {
currentConfig.Path = datadir
currentConfig.Path = expandPath(datadir)
}
}
@ -207,6 +212,9 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
currentConfig.SyncUpdateDelay = d
}
// any value including 0 is acceptable
currentConfig.MaxStreamPeerServers = ctx.GlobalInt(SwarmMaxStreamPeerServersFlag.Name)
if ctx.GlobalIsSet(SwarmLightNodeEnabled.Name) {
currentConfig.LightNodeEnabled = true
}
@ -226,6 +234,10 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
if len(ensAPIs) == 1 && ensAPIs[0] == "" {
ensAPIs = nil
}
for i := range ensAPIs {
ensAPIs[i] = expandPath(ensAPIs[i])
}
currentConfig.EnsAPIs = ensAPIs
}
@ -262,13 +274,17 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
}
if networkid := os.Getenv(SWARM_ENV_NETWORK_ID); networkid != "" {
if id, _ := strconv.Atoi(networkid); id != 0 {
currentConfig.NetworkID = uint64(id)
id, err := strconv.ParseUint(networkid, 10, 64)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_NETWORK_ID, err)
}
if id != 0 {
currentConfig.NetworkID = id
}
}
if datadir := os.Getenv(GETH_ENV_DATADIR); datadir != "" {
currentConfig.Path = datadir
currentConfig.Path = expandPath(datadir)
}
bzzport := os.Getenv(SWARM_ENV_PORT)
@ -281,33 +297,50 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
}
if swapenable := os.Getenv(SWARM_ENV_SWAP_ENABLE); swapenable != "" {
if swap, err := strconv.ParseBool(swapenable); err != nil {
currentConfig.SwapEnabled = swap
swap, err := strconv.ParseBool(swapenable)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_SWAP_ENABLE, err)
}
currentConfig.SwapEnabled = swap
}
if syncdisable := os.Getenv(SWARM_ENV_SYNC_DISABLE); syncdisable != "" {
if sync, err := strconv.ParseBool(syncdisable); err != nil {
currentConfig.SyncEnabled = !sync
sync, err := strconv.ParseBool(syncdisable)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_SYNC_DISABLE, err)
}
currentConfig.SyncEnabled = !sync
}
if v := os.Getenv(SWARM_ENV_DELIVERY_SKIP_CHECK); v != "" {
if skipCheck, err := strconv.ParseBool(v); err != nil {
skipCheck, err := strconv.ParseBool(v)
if err != nil {
currentConfig.DeliverySkipCheck = skipCheck
}
}
if v := os.Getenv(SWARM_ENV_SYNC_UPDATE_DELAY); v != "" {
if d, err := time.ParseDuration(v); err != nil {
currentConfig.SyncUpdateDelay = d
d, err := time.ParseDuration(v)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_SYNC_UPDATE_DELAY, err)
}
currentConfig.SyncUpdateDelay = d
}
if max := os.Getenv(SWARM_ENV_MAX_STREAM_PEER_SERVERS); max != "" {
m, err := strconv.Atoi(max)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_MAX_STREAM_PEER_SERVERS, err)
}
currentConfig.MaxStreamPeerServers = m
}
if lne := os.Getenv(SWARM_ENV_LIGHT_NODE_ENABLE); lne != "" {
if lightnode, err := strconv.ParseBool(lne); err != nil {
currentConfig.LightNodeEnabled = lightnode
lightnode, err := strconv.ParseBool(lne)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_LIGHT_NODE_ENABLE, err)
}
currentConfig.LightNodeEnabled = lightnode
}
if swapapi := os.Getenv(SWARM_ENV_SWAP_API); swapapi != "" {

View File

@ -93,21 +93,6 @@ func dbImport(ctx *cli.Context) {
log.Info(fmt.Sprintf("successfully imported %d chunks", count))
}
func dbClean(ctx *cli.Context) {
args := ctx.Args()
if len(args) != 2 {
utils.Fatalf("invalid arguments, please specify <chunkdb> (path to a local chunk database) and the base key")
}
store, err := openLDBStore(args[0], common.Hex2Bytes(args[1]))
if err != nil {
utils.Fatalf("error opening local chunk database: %s", err)
}
defer store.Close()
store.Cleanup()
}
func openLDBStore(path string, basekey []byte) (*storage.LDBStore, error) {
if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil {
return nil, fmt.Errorf("invalid chunkdb path: %s", err)

View File

@ -0,0 +1,172 @@
// Copyright 2016 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/>.
// Command feed allows the user to create and update signed Swarm feeds
package main
import (
"fmt"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/cmd/utils"
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
"github.com/ethereum/go-ethereum/swarm/storage/feed"
"gopkg.in/urfave/cli.v1"
)
func NewGenericSigner(ctx *cli.Context) feed.Signer {
return feed.NewGenericSigner(getPrivKey(ctx))
}
func getTopic(ctx *cli.Context) (topic feed.Topic) {
var name = ctx.String(SwarmFeedNameFlag.Name)
var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name)
var relatedTopicBytes []byte
var err error
if relatedTopic != "" {
relatedTopicBytes, err = hexutil.Decode(relatedTopic)
if err != nil {
utils.Fatalf("Error parsing topic: %s", err)
}
}
topic, err = feed.NewTopic(name, relatedTopicBytes)
if err != nil {
utils.Fatalf("Error parsing topic: %s", err)
}
return topic
}
// swarm feed create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]]
// swarm feed update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false]
// swarm feed info <Manifest Address or ENS domain>
func feedCreateManifest(ctx *cli.Context) {
var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi)
)
newFeedUpdateRequest := feed.NewFirstRequest(getTopic(ctx))
newFeedUpdateRequest.Feed.User = feedGetUser(ctx)
manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest)
if err != nil {
utils.Fatalf("Error creating feed manifest: %s", err.Error())
return
}
fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up)
}
func feedUpdate(ctx *cli.Context) {
args := ctx.Args()
var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi)
manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
)
if len(args) < 1 {
fmt.Println("Incorrect number of arguments")
cli.ShowCommandHelpAndExit(ctx, "update", 1)
return
}
signer := NewGenericSigner(ctx)
data, err := hexutil.Decode(args[0])
if err != nil {
utils.Fatalf("Error parsing data: %s", err.Error())
return
}
var updateRequest *feed.Request
var query *feed.Query
if manifestAddressOrDomain == "" {
query = new(feed.Query)
query.User = signer.Address()
query.Topic = getTopic(ctx)
}
// Retrieve a feed update request
updateRequest, err = client.GetFeedRequest(query, manifestAddressOrDomain)
if err != nil {
utils.Fatalf("Error retrieving feed status: %s", err.Error())
}
// set the new data
updateRequest.SetData(data)
// sign update
if err = updateRequest.Sign(signer); err != nil {
utils.Fatalf("Error signing feed update: %s", err.Error())
}
// post update
err = client.UpdateFeed(updateRequest)
if err != nil {
utils.Fatalf("Error updating feed: %s", err.Error())
return
}
}
func feedInfo(ctx *cli.Context) {
var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi)
manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
)
var query *feed.Query
if manifestAddressOrDomain == "" {
query = new(feed.Query)
query.Topic = getTopic(ctx)
query.User = feedGetUser(ctx)
}
metadata, err := client.GetFeedRequest(query, manifestAddressOrDomain)
if err != nil {
utils.Fatalf("Error retrieving feed metadata: %s", err.Error())
return
}
encodedMetadata, err := metadata.MarshalJSON()
if err != nil {
utils.Fatalf("Error encoding metadata to JSON for display:%s", err)
}
fmt.Println(string(encodedMetadata))
}
func feedGetUser(ctx *cli.Context) common.Address {
var user = ctx.String(SwarmFeedUserFlag.Name)
if user != "" {
return common.HexToAddress(user)
}
pk := getPrivKey(ctx)
if pk == nil {
utils.Fatalf("Cannot read private key. Must specify --user or --bzzaccount")
}
return crypto.PubkeyToAddress(pk.PublicKey)
}

View File

@ -38,7 +38,7 @@ import (
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/swarm"
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
@ -116,6 +116,12 @@ var (
Usage: "Duration for sync subscriptions update after no new peers are added (default 15s)",
EnvVar: SWARM_ENV_SYNC_UPDATE_DELAY,
}
SwarmMaxStreamPeerServersFlag = cli.IntFlag{
Name: "max-stream-peer-servers",
Usage: "Limit of Stream peer servers, 0 denotes unlimited",
EnvVar: SWARM_ENV_MAX_STREAM_PEER_SERVERS,
Value: 10000, // A very large default value is possible as stream servers have very small memory footprint
}
SwarmLightNodeEnabled = cli.BoolFlag{
Name: "lightnode",
Usage: "Enable Swarm LightNode (default false)",
@ -197,22 +203,30 @@ var (
Usage: "Number of recent chunks cached in memory (default 5000)",
EnvVar: SWARM_ENV_STORE_CACHE_CAPACITY,
}
SwarmResourceMultihashFlag = cli.BoolFlag{
Name: "multihash",
Usage: "Determines how to interpret data for a resource update. If not present, data will be interpreted as raw, literal data that will be included in the resource",
}
SwarmResourceNameFlag = cli.StringFlag{
Name: "name",
Usage: "User-defined name for the new resource",
}
SwarmResourceDataOnCreateFlag = cli.StringFlag{
Name: "data",
Usage: "Initializes the resource with the given hex-encoded data. Data must be prefixed by 0x",
}
SwarmCompressedFlag = cli.BoolFlag{
Name: "compressed",
Usage: "Prints encryption keys in compressed form",
}
SwarmFeedNameFlag = cli.StringFlag{
Name: "name",
Usage: "User-defined name for the new feed, limited to 32 characters. If combined with topic, it will refer to a subtopic with this name",
}
SwarmFeedTopicFlag = cli.StringFlag{
Name: "topic",
Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters",
}
SwarmFeedDataOnCreateFlag = cli.StringFlag{
Name: "data",
Usage: "Initializes the feed with the given hex-encoded data. Data must be prefixed by 0x",
}
SwarmFeedManifestFlag = cli.StringFlag{
Name: "manifest",
Usage: "Refers to the feed through a manifest",
}
SwarmFeedUserFlag = cli.StringFlag{
Name: "user",
Usage: "Indicates the user who updates the feed",
}
)
//declare a few constant error messages, useful for later error check comparisons in test
@ -242,12 +256,12 @@ func init() {
utils.ListenPortFlag.Value = 30399
}
var app = utils.NewApp(gitCommit, "Ethereum Swarm")
var app = utils.NewApp("", "Ethereum Swarm")
// This init function creates the cli.App.
func init() {
app.Action = bzzd
app.HideVersion = true // we have a command to print the version
app.Version = sv.ArchiveVersion(gitCommit)
app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
app.Commands = []cli.Command{
{
@ -332,36 +346,62 @@ func init() {
},
{
CustomHelpTemplate: helpTemplate,
Name: "resource",
Usage: "(Advanced) Create and update Mutable Resources",
Name: "feed",
Usage: "(Advanced) Create and update Swarm Feeds",
ArgsUsage: "<create|update|info>",
Description: "Works with Mutable Resource Updates",
Description: "Works with Swarm Feeds",
Subcommands: []cli.Command{
{
Action: resourceCreate,
Action: feedCreateManifest,
CustomHelpTemplate: helpTemplate,
Name: "create",
Usage: "creates a new Mutable Resource",
ArgsUsage: "<frequency>",
Description: "creates a new Mutable Resource",
Flags: []cli.Flag{SwarmResourceNameFlag, SwarmResourceDataOnCreateFlag, SwarmResourceMultihashFlag},
Usage: "creates and publishes a new feed manifest",
Description: `creates and publishes a new feed manifest pointing to a specified user's updates about a particular topic.
The feed topic can be built in the following ways:
* use --topic to set the topic to an arbitrary binary hex string.
* use --name to set the topic to a human-readable name.
For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture.
* use both --topic and --name to create named subtopics.
For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning
this feed tracks a discussion about that contract.
The --user flag allows to have this manifest refer to a user other than yourself. If not specified,
it will then default to your local account (--bzzaccount)`,
Flags: []cli.Flag{SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag},
},
{
Action: resourceUpdate,
Action: feedUpdate,
CustomHelpTemplate: helpTemplate,
Name: "update",
Usage: "updates the content of an existing Mutable Resource",
ArgsUsage: "<Manifest Address or ENS domain> <0x Hex data>",
Description: "updates the content of an existing Mutable Resource",
Flags: []cli.Flag{SwarmResourceMultihashFlag},
Usage: "updates the content of an existing Swarm Feed",
ArgsUsage: "<0x Hex data>",
Description: `publishes a new update on the specified topic
The feed topic can be built in the following ways:
* use --topic to set the topic to an arbitrary binary hex string.
* use --name to set the topic to a human-readable name.
For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture.
* use both --topic and --name to create named subtopics.
For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning
this feed tracks a discussion about that contract.
If you have a manifest, you can specify it with --manifest to refer to the feed,
instead of using --topic / --name
`,
Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag},
},
{
Action: resourceInfo,
Action: feedInfo,
CustomHelpTemplate: helpTemplate,
Name: "info",
Usage: "obtains information about an existing Mutable Resource",
ArgsUsage: "<Manifest Address or ENS domain>",
Description: "obtains information about an existing Mutable Resource",
Usage: "obtains information about an existing Swarm feed",
Description: `obtains information about an existing Swarm feed
The topic can be specified directly with the --topic flag as an hex string
If no topic is specified, the default topic (zero) will be used
The --name flag can be used to specify subtopics with a specific name.
The --user flag allows to refer to a user other than yourself. If not specified,
it will then default to your local account (--bzzaccount)
If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user
to refer to the feed`,
Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag},
},
},
},
@ -497,14 +537,6 @@ pv(1) tool to get a progress bar:
pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks -`,
},
{
Action: dbClean,
CustomHelpTemplate: helpTemplate,
Name: "clean",
Usage: "remove corrupt entries from a local chunk database",
ArgsUsage: "<chunkdb>",
Description: "Remove corrupt entries from a local chunk database",
},
},
},
@ -542,6 +574,7 @@ pv(1) tool to get a progress bar:
SwarmSwapAPIFlag,
SwarmSyncDisabledFlag,
SwarmSyncUpdateDelay,
SwarmMaxStreamPeerServersFlag,
SwarmLightNodeEnabled,
SwarmDeliverySkipCheckFlag,
SwarmListenAddrFlag,
@ -697,7 +730,7 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr
}
// getPrivKey returns the private key of the specified bzzaccount
// Used only by client commands, such as `resource`
// Used only by client commands, such as `feed`
func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey {
// booting up the swarm node just as we do in bzzd action
bzzconfig, err := buildConfig(ctx)
@ -788,10 +821,10 @@ func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) {
return
}
cfg.P2P.BootstrapNodes = []*discover.Node{}
cfg.P2P.BootstrapNodes = []*enode.Node{}
for _, url := range SwarmBootnodes {
node, err := discover.ParseNode(url)
node, err := enode.ParseV4(url)
if err != nil {
log.Error("Bootstrap URL invalid", "enode", url, "err", err)
}

View File

@ -0,0 +1,124 @@
// Copyright 2018 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/>.
package main
// Standard "mime" package rely on system-settings, see mime.osInitMime
// Swarm will run on many OS/Platform/Docker and must behave similar
// This command generates code to add common mime types based on mime.types file
//
// mime.types file provided by mailcap, which follow https://www.iana.org/assignments/media-types/media-types.xhtml
//
// Get last version of mime.types file by:
// docker run --rm -v $(pwd):/tmp alpine:edge /bin/sh -c "apk add -U mailcap; mv /etc/mime.types /tmp"
import (
"bufio"
"bytes"
"flag"
"html/template"
"io/ioutil"
"strings"
"log"
)
var (
typesFlag = flag.String("types", "", "Input mime.types file")
packageFlag = flag.String("package", "", "Golang package in output file")
outFlag = flag.String("out", "", "Output file name for the generated mime types")
)
type mime struct {
Name string
Exts []string
}
type templateParams struct {
PackageName string
Mimes []mime
}
func main() {
// Parse and ensure all needed inputs are specified
flag.Parse()
if *typesFlag == "" {
log.Fatalf("--types is required")
}
if *packageFlag == "" {
log.Fatalf("--types is required")
}
if *outFlag == "" {
log.Fatalf("--out is required")
}
params := templateParams{
PackageName: *packageFlag,
}
types, err := ioutil.ReadFile(*typesFlag)
if err != nil {
log.Fatal(err)
}
scanner := bufio.NewScanner(bytes.NewReader(types))
for scanner.Scan() {
txt := scanner.Text()
if strings.HasPrefix(txt, "#") || len(txt) == 0 {
continue
}
parts := strings.Fields(txt)
if len(parts) == 1 {
continue
}
params.Mimes = append(params.Mimes, mime{parts[0], parts[1:]})
}
if err = scanner.Err(); err != nil {
log.Fatal(err)
}
result := bytes.NewBuffer([]byte{})
if err := template.Must(template.New("_").Parse(tpl)).Execute(result, params); err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile(*outFlag, result.Bytes(), 0600); err != nil {
log.Fatal(err)
}
}
var tpl = `// Code generated by github.com/ethereum/go-ethereum/cmd/swarm/mimegen. DO NOT EDIT.
package {{ .PackageName }}
import "mime"
func init() {
var mimeTypes = map[string]string{
{{- range .Mimes -}}
{{ $name := .Name -}}
{{- range .Exts }}
".{{ . }}": "{{ $name | html }}",
{{- end }}
{{- end }}
}
for ext, name := range mimeTypes {
if err := mime.AddExtensionType(ext, name); err != nil {
panic(err)
}
}
}
`

File diff suppressed because it is too large Load Diff

View File

@ -1,169 +0,0 @@
// Copyright 2016 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/>.
// Command resource allows the user to create and update signed mutable resource updates
package main
import (
"fmt"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/cmd/utils"
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
"github.com/ethereum/go-ethereum/swarm/storage/mru"
"gopkg.in/urfave/cli.v1"
)
func NewGenericSigner(ctx *cli.Context) mru.Signer {
return mru.NewGenericSigner(getPrivKey(ctx))
}
// swarm resource create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]]
// swarm resource update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false]
// swarm resource info <Manifest Address or ENS domain>
func resourceCreate(ctx *cli.Context) {
args := ctx.Args()
var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi)
multihash = ctx.Bool(SwarmResourceMultihashFlag.Name)
initialData = ctx.String(SwarmResourceDataOnCreateFlag.Name)
name = ctx.String(SwarmResourceNameFlag.Name)
)
if len(args) < 1 {
fmt.Println("Incorrect number of arguments")
cli.ShowCommandHelpAndExit(ctx, "create", 1)
return
}
signer := NewGenericSigner(ctx)
frequency, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
fmt.Printf("Frequency formatting error: %s\n", err.Error())
cli.ShowCommandHelpAndExit(ctx, "create", 1)
return
}
metadata := mru.ResourceMetadata{
Name: name,
Frequency: frequency,
Owner: signer.Address(),
}
var newResourceRequest *mru.Request
if initialData != "" {
initialDataBytes, err := hexutil.Decode(initialData)
if err != nil {
fmt.Printf("Error parsing data: %s\n", err.Error())
cli.ShowCommandHelpAndExit(ctx, "create", 1)
return
}
newResourceRequest, err = mru.NewCreateUpdateRequest(&metadata)
if err != nil {
utils.Fatalf("Error creating new resource request: %s", err)
}
newResourceRequest.SetData(initialDataBytes, multihash)
if err = newResourceRequest.Sign(signer); err != nil {
utils.Fatalf("Error signing resource update: %s", err.Error())
}
} else {
newResourceRequest, err = mru.NewCreateRequest(&metadata)
if err != nil {
utils.Fatalf("Error creating new resource request: %s", err)
}
}
manifestAddress, err := client.CreateResource(newResourceRequest)
if err != nil {
utils.Fatalf("Error creating resource: %s", err.Error())
return
}
fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up)
}
func resourceUpdate(ctx *cli.Context) {
args := ctx.Args()
var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi)
multihash = ctx.Bool(SwarmResourceMultihashFlag.Name)
)
if len(args) < 2 {
fmt.Println("Incorrect number of arguments")
cli.ShowCommandHelpAndExit(ctx, "update", 1)
return
}
signer := NewGenericSigner(ctx)
manifestAddressOrDomain := args[0]
data, err := hexutil.Decode(args[1])
if err != nil {
utils.Fatalf("Error parsing data: %s", err.Error())
return
}
// Retrieve resource status and metadata out of the manifest
updateRequest, err := client.GetResourceMetadata(manifestAddressOrDomain)
if err != nil {
utils.Fatalf("Error retrieving resource status: %s", err.Error())
}
// set the new data
updateRequest.SetData(data, multihash)
// sign update
if err = updateRequest.Sign(signer); err != nil {
utils.Fatalf("Error signing resource update: %s", err.Error())
}
// post update
err = client.UpdateResource(updateRequest)
if err != nil {
utils.Fatalf("Error updating resource: %s", err.Error())
return
}
}
func resourceInfo(ctx *cli.Context) {
var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi)
)
args := ctx.Args()
if len(args) < 1 {
fmt.Println("Incorrect number of arguments.")
cli.ShowCommandHelpAndExit(ctx, "info", 1)
return
}
manifestAddressOrDomain := args[0]
metadata, err := client.GetResourceMetadata(manifestAddressOrDomain)
if err != nil {
utils.Fatalf("Error retrieving resource metadata: %s", err.Error())
return
}
encodedMetadata, err := metadata.MarshalJSON()
if err != nil {
utils.Fatalf("Error encoding metadata to JSON for display:%s", err)
}
fmt.Println(string(encodedMetadata))
}

View File

@ -22,16 +22,15 @@ import (
"fmt"
"io"
"io/ioutil"
"mime"
"net/http"
"os"
"os/user"
"path"
"path/filepath"
"strings"
"github.com/ethereum/go-ethereum/cmd/utils"
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
"github.com/ethereum/go-ethereum/cmd/utils"
"gopkg.in/urfave/cli.v1"
)
@ -118,10 +117,9 @@ func upload(ctx *cli.Context) {
return "", fmt.Errorf("error opening file: %s", err)
}
defer f.Close()
if mimeType == "" {
mimeType = detectMimeType(file)
if mimeType != "" {
f.ContentType = mimeType
}
f.ContentType = mimeType
return client.Upload(f, "", toEncrypt)
}
}
@ -138,6 +136,12 @@ func upload(ctx *cli.Context) {
// 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 i := strings.Index(p, ":"); i > 0 {
return p
}
if i := strings.Index(p, "@"); i > 0 {
return p
}
if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
if home := homeDir(); home != "" {
p = home + p[1:]
@ -155,19 +159,3 @@ func homeDir() string {
}
return ""
}
func detectMimeType(file string) string {
if ext := filepath.Ext(file); ext != "" {
return mime.TypeByExtension(ext)
}
f, err := os.Open(file)
if err != nil {
return ""
}
defer f.Close()
buf := make([]byte, 512)
if n, _ := f.Read(buf); n > 0 {
return http.DetectContentType(buf)
}
return ""
}

View File

@ -52,8 +52,8 @@ import (
"github.com/ethereum/go-ethereum/metrics/influxdb"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
@ -710,9 +710,9 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
return // already set, don't apply defaults.
}
cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls))
cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
for _, url := range urls {
node, err := discover.ParseNode(url)
node, err := enode.ParseV4(url)
if err != nil {
log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
}
@ -1137,11 +1137,14 @@ func checkExclusive(ctx *cli.Context, args ...interface{}) {
if i+1 < len(args) {
switch option := args[i+1].(type) {
case string:
// Extended flag, expand the name and shift the arguments
// Extended flag check, make sure value set doesn't conflict with passed in option
if ctx.GlobalString(flag.GetName()) == option {
name += "=" + option
set = append(set, "--"+name)
}
// shift arguments and continue
i++
continue
case cli.Flag:
default:

View File

@ -41,7 +41,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/whisper/mailserver"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
@ -175,7 +175,7 @@ func initialize() {
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*argVerbosity), log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
done = make(chan struct{})
var peers []*discover.Node
var peers []*enode.Node
var err error
if *generateKey {
@ -203,7 +203,7 @@ func initialize() {
if len(*argEnode) == 0 {
argEnode = scanLineA("Please enter the peer's enode: ")
}
peer := discover.MustParseNode(*argEnode)
peer := enode.MustParseV4(*argEnode)
peers = append(peers, peer)
}
@ -747,11 +747,11 @@ func requestExpiredMessagesLoop() {
}
func extractIDFromEnode(s string) []byte {
n, err := discover.ParseNode(s)
n, err := enode.ParseV4(s)
if err != nil {
utils.Fatalf("Failed to parse enode: %s", err)
}
return n.ID[:]
return n.ID().Bytes()
}
// obfuscateBloom adds 16 random bits to the bloom

View File

@ -151,6 +151,38 @@ func (self *ENS) Resolve(name string) (common.Hash, error) {
return common.BytesToHash(ret[:]), nil
}
// Addr is a non-transactional call that returns the address associated with a name.
func (self *ENS) Addr(name string) (common.Address, error) {
node := EnsNode(name)
resolver, err := self.getResolver(node)
if err != nil {
return common.Address{}, err
}
ret, err := resolver.Addr(node)
if err != nil {
return common.Address{}, err
}
return common.BytesToAddress(ret[:]), nil
}
// SetAddress sets the address associated with a name. Only works if the caller
// owns the name, and the associated resolver implements a `setAddress` function.
func (self *ENS) SetAddr(name string, addr common.Address) (*types.Transaction, error) {
node := EnsNode(name)
resolver, err := self.getResolver(node)
if err != nil {
return nil, err
}
opts := self.TransactOpts
opts.GasLimit = 200000
return resolver.Contract.SetAddr(&opts, node, addr)
}
// Register registers a new domain name for the caller, making them the owner of the new name.
// Only works if the registrar for the parent domain implements the FIFS registrar protocol.
func (self *ENS) Register(name string) (*types.Transaction, error) {

View File

@ -109,9 +109,9 @@ func PrintDisassembled(code string) error {
it := NewInstructionIterator(script)
for it.Next() {
if it.Arg() != nil && 0 < len(it.Arg()) {
fmt.Printf("%06v: %v 0x%x\n", it.PC(), it.Op(), it.Arg())
fmt.Printf("%05x: %v 0x%x\n", it.PC(), it.Op(), it.Arg())
} else {
fmt.Printf("%06v: %v\n", it.PC(), it.Op())
fmt.Printf("%05x: %v\n", it.PC(), it.Op())
}
}
return it.Error()
@ -124,9 +124,9 @@ func Disassemble(script []byte) ([]string, error) {
it := NewInstructionIterator(script)
for it.Next() {
if it.Arg() != nil && 0 < len(it.Arg()) {
instrs = append(instrs, fmt.Sprintf("%06v: %v 0x%x\n", it.PC(), it.Op(), it.Arg()))
instrs = append(instrs, fmt.Sprintf("%05x: %v 0x%x\n", it.PC(), it.Op(), it.Arg()))
} else {
instrs = append(instrs, fmt.Sprintf("%06v: %v\n", it.PC(), it.Op()))
instrs = append(instrs, fmt.Sprintf("%05x: %v\n", it.PC(), it.Op()))
}
}
if err := it.Error(); err != nil {

View File

@ -55,6 +55,7 @@ var (
const (
bodyCacheLimit = 256
blockCacheLimit = 256
receiptsCacheLimit = 32
maxFutureBlocks = 256
maxTimeFutureBlocks = 30
badBlockLimit = 10
@ -111,11 +112,12 @@ type BlockChain struct {
currentBlock atomic.Value // Current head of the block chain
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
receiptsCache *lru.Cache // Cache for the most recent receipts per block
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
@ -144,6 +146,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
}
bodyCache, _ := lru.New(bodyCacheLimit)
bodyRLPCache, _ := lru.New(bodyCacheLimit)
receiptsCache, _ := lru.New(receiptsCacheLimit)
blockCache, _ := lru.New(blockCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit)
@ -158,6 +161,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
shouldPreserve: shouldPreserve,
bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache,
receiptsCache: receiptsCache,
blockCache: blockCache,
futureBlocks: futureBlocks,
engine: engine,
@ -280,6 +284,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
// Clear out any stale content from the caches
bc.bodyCache.Purge()
bc.bodyRLPCache.Purge()
bc.receiptsCache.Purge()
bc.blockCache.Purge()
bc.futureBlocks.Purge()
@ -603,11 +608,18 @@ func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {
// GetReceiptsByHash retrieves the receipts for all transactions in a given block.
func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
if receipts, ok := bc.receiptsCache.Get(hash); ok {
return receipts.(types.Receipts)
}
number := rawdb.ReadHeaderNumber(bc.db, hash)
if number == nil {
return nil
}
return rawdb.ReadReceipts(bc.db, hash, *number)
receipts := rawdb.ReadReceipts(bc.db, hash, *number)
bc.receiptsCache.Add(hash, receipts)
return receipts
}
// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors.

View File

@ -53,14 +53,14 @@ type ChainIndexerChain interface {
// CurrentHeader retrieves the latest locally known header.
CurrentHeader() *types.Header
// SubscribeChainEvent subscribes to new head header notifications.
SubscribeChainEvent(ch chan<- ChainEvent) event.Subscription
// SubscribeChainHeadEvent subscribes to new head header notifications.
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
}
// ChainIndexer does a post-processing job for equally sized sections of the
// canonical chain (like BlooomBits and CHT structures). A ChainIndexer is
// connected to the blockchain through the event system by starting a
// ChainEventLoop in a goroutine.
// ChainHeadEventLoop in a goroutine.
//
// Further child ChainIndexers can be added which use the output of the parent
// section indexer. These child indexers receive new head notifications only
@ -142,8 +142,8 @@ func (c *ChainIndexer) AddCheckpoint(section uint64, shead common.Hash) {
// cascading background processing. Children do not need to be started, they
// are notified about new events by their parents.
func (c *ChainIndexer) Start(chain ChainIndexerChain) {
events := make(chan ChainEvent, 10)
sub := chain.SubscribeChainEvent(events)
events := make(chan ChainHeadEvent, 10)
sub := chain.SubscribeChainHeadEvent(events)
go c.eventLoop(chain.CurrentHeader(), events, sub)
}
@ -190,7 +190,7 @@ func (c *ChainIndexer) Close() error {
// eventLoop is a secondary - optional - event loop of the indexer which is only
// started for the outermost indexer to push chain head events into a processing
// queue.
func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainEvent, sub event.Subscription) {
func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) {
// Mark the chain indexer as active, requiring an additional teardown
atomic.StoreUint32(&c.active, 1)
@ -219,13 +219,13 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainE
}
header := ev.Block.Header()
if header.ParentHash != prevHash {
// Reorg to the common ancestor (might not exist in light sync mode, skip reorg then)
// Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then)
// TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly?
// TODO(karalabe): This operation is expensive and might block, causing the event system to
// potentially also lock up. We need to do with on a different thread somehow.
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil {
c.newHead(h.Number.Uint64(), true)
if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash {
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil {
c.newHead(h.Number.Uint64(), true)
}
}
}
c.newHead(header.Number.Uint64(), false)

View File

@ -47,7 +47,7 @@ type Log struct {
TxIndex uint `json:"transactionIndex" gencodec:"required"`
// hash of the block in which the transaction was included
BlockHash common.Hash `json:"blockHash"`
// index of the log in the receipt
// index of the log in the block
Index uint `json:"logIndex" gencodec:"required"`
// The Removed field is true if this log was reverted due to a chain reorganisation.

View File

@ -153,16 +153,21 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
if err := dec.UnmarshalJSON(input); err != nil {
return err
}
var V byte
if isProtectedV(dec.V) {
chainID := deriveChainId(dec.V).Uint64()
V = byte(dec.V.Uint64() - 35 - 2*chainID)
} else {
V = byte(dec.V.Uint64() - 27)
}
if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
return ErrInvalidSig
withSignature := dec.V.Sign() != 0 || dec.R.Sign() != 0 || dec.S.Sign() != 0
if withSignature {
var V byte
if isProtectedV(dec.V) {
chainID := deriveChainId(dec.V).Uint64()
V = byte(dec.V.Uint64() - 35 - 2*chainID)
} else {
V = byte(dec.V.Uint64() - 27)
}
if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
return ErrInvalidSig
}
}
*tx = Transaction{data: dec}
return nil
}

View File

@ -227,13 +227,13 @@ func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (commo
if !crypto.ValidateSignatureValues(V, R, S, homestead) {
return common.Address{}, ErrInvalidSig
}
// encode the snature in uncompressed format
// encode the signature in uncompressed format
r, s := R.Bytes(), S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = V
// recover the public key from the snature
// recover the public key from the signature
pub, err := crypto.Ecrecover(sighash[:], sig)
if err != nil {
return common.Address{}, err

View File

@ -16,34 +16,6 @@
package vm
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// destinations stores one map per contract (keyed by hash of code).
// The maps contain an entry for each location of a JUMPDEST
// instruction.
type destinations map[common.Hash]bitvec
// has checks whether code has a JUMPDEST at dest.
func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool {
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
udest := dest.Uint64()
if dest.BitLen() >= 63 || udest >= uint64(len(code)) {
return false
}
m, analysed := d[codehash]
if !analysed {
m = codeBitmap(code)
d[codehash] = m
}
return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest)
}
// bitvec is a bit vector which maps bytes in a program.
// An unset bit means the byte is an opcode, a set bit means
// it's data (i.e. argument of PUSHxx).

View File

@ -49,7 +49,8 @@ type Contract struct {
caller ContractRef
self ContractRef
jumpdests destinations // result of JUMPDEST analysis.
jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis.
analysis bitvec // Locally cached result of JUMPDEST analysis
Code []byte
CodeHash common.Hash
@ -58,21 +59,17 @@ type Contract struct {
Gas uint64
value *big.Int
Args []byte
DelegateCall bool
}
// NewContract returns a new contract environment for the execution of EVM.
func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object}
if parent, ok := caller.(*Contract); ok {
// Reuse JUMPDEST analysis from parent context if available.
c.jumpdests = parent.jumpdests
} else {
c.jumpdests = make(destinations)
c.jumpdests = make(map[common.Hash]bitvec)
}
// Gas should be a pointer so it can safely be reduced through the run
@ -84,10 +81,42 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
return c
}
func (c *Contract) validJumpdest(dest *big.Int) bool {
udest := dest.Uint64()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
return false
}
// Only JUMPDESTs allowed for destinations
if OpCode(c.Code[udest]) != JUMPDEST {
return false
}
// Do we have a contract hash already?
if c.CodeHash != (common.Hash{}) {
// Does parent context have the analysis?
analysis, exist := c.jumpdests[c.CodeHash]
if !exist {
// Do the analysis and save in parent context
// We do not need to store it in c.analysis
analysis = codeBitmap(c.Code)
c.jumpdests[c.CodeHash] = analysis
}
return analysis.codeSegment(udest)
}
// We don't have the code hash, most likely a piece of initcode not already
// in state trie. In that case, we do an analysis, and save it locally, so
// we don't have to recalculate it for every JUMP instruction in the execution
// However, we don't save it within the parent context
if c.analysis == nil {
c.analysis = codeBitmap(c.Code)
}
return c.analysis.codeSegment(udest)
}
// AsDelegate sets the contract to be a delegate call and returns the current
// contract (for chaining calls)
func (c *Contract) AsDelegate() *Contract {
c.DelegateCall = true
// NOTE: caller must, at all times be a contract. It should never happen
// that caller is something other than a Contract.
parent := c.caller.(*Contract)
@ -138,12 +167,6 @@ func (c *Contract) Value() *big.Int {
return c.value
}
// SetCode sets the code to the contract
func (c *Contract) SetCode(hash common.Hash, code []byte) {
c.Code = code
c.CodeHash = hash
}
// SetCallCode sets the code of the contract and address of the backing data
// object
func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
@ -151,3 +174,11 @@ func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []by
c.CodeHash = hash
c.CodeAddr = addr
}
// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash.
// In case hash is not provided, the jumpdest analysis will not be saved to the parent context
func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) {
c.Code = codeAndHash.code
c.CodeHash = codeAndHash.hash
c.CodeAddr = addr
}

View File

@ -212,12 +212,12 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.StateDB.CreateAccount(addr)
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
// Even if the account has no code, we need to continue because it might be a precompile
start := time.Now()
// Capture the tracer start/end events in debug mode
@ -352,8 +352,20 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
return ret, contract.Gas, err
}
type codeAndHash struct {
code []byte
hash common.Hash
}
func (c *codeAndHash) Hash() common.Hash {
if c.hash == (common.Hash{}) {
c.hash = crypto.Keccak256Hash(c.code)
}
return c.hash
}
// create creates a new contract using code as deployment code.
func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth) {
@ -382,14 +394,14 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
// EVM. The contract is a scoped environment for this execution context
// only.
contract := NewContract(caller, AccountRef(address), value, gas)
contract.SetCallCode(&address, crypto.Keccak256Hash(code), code)
contract.SetCodeOptionalHash(&address, codeAndHash)
if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, address, gas, nil
}
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, code, gas, value)
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
}
start := time.Now()
@ -433,7 +445,7 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
// Create creates a new contract using code as deployment code.
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
return evm.create(caller, code, gas, value, contractAddr)
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr)
}
// Create2 creates a new contract using code as deployment code.
@ -441,8 +453,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), code)
return evm.create(caller, code, gas, endowment, contractAddr)
codeAndHash := &codeAndHash{code: code}
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes())
return evm.create(caller, codeAndHash, gas, endowment, contractAddr)
}
// ChainConfig returns the environment's chain configuration

View File

@ -347,6 +347,17 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack,
if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(2))
if overflow {
return 0, errGasUintOverflow
}
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}

View File

@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/params"
)
@ -373,13 +373,20 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
data := memory.Get(offset.Int64(), size.Int64())
hash := crypto.Keccak256(data)
evm := interpreter.evm
if evm.vmConfig.EnablePreimageRecording {
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
if interpreter.hasher == nil {
interpreter.hasher = sha3.NewKeccak256().(keccakState)
} else {
interpreter.hasher.Reset()
}
stack.push(interpreter.intPool.get().SetBytes(hash))
interpreter.hasher.Write(data)
interpreter.hasher.Read(interpreter.hasherBuf[:])
evm := interpreter.evm
if evm.vmConfig.EnablePreimageRecording {
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
}
stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:]))
interpreter.intPool.put(offset, size)
return nil, nil
@ -620,7 +627,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos := stack.pop()
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
if !contract.validJumpdest(pos) {
nop := contract.GetOp(pos.Uint64())
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
}
@ -633,7 +640,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos, cond := stack.pop(), stack.pop()
if cond.Sign() != 0 {
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
if !contract.validJumpdest(pos) {
nop := contract.GetOp(pos.Uint64())
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
}
@ -727,7 +734,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
}
func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// Pop gas. The actual gas in in interpreter.evm.callGasTemp.
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
interpreter.intPool.put(stack.pop())
gas := interpreter.evm.callGasTemp
// Pop other call parameters.

View File

@ -18,8 +18,10 @@ package vm
import (
"fmt"
"hash"
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
)
@ -68,12 +70,24 @@ type Interpreter interface {
CanRun([]byte) bool
}
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
type keccakState interface {
hash.Hash
Read([]byte) (int, error)
}
// EVMInterpreter represents an EVM interpreter
type EVMInterpreter struct {
evm *EVM
cfg Config
gasTable params.GasTable
intPool *intPool
intPool *intPool
hasher keccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes
readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse

View File

@ -29,7 +29,7 @@ type Memory struct {
lastGasCost uint64
}
// NewMemory returns a new memory memory model.
// NewMemory returns a new memory model.
func NewMemory() *Memory {
return &Memory{}
}

View File

@ -77,9 +77,9 @@ func CreateAddress(b common.Address, nonce uint64) common.Address {
}
// CreateAddress2 creates an ethereum address given the address bytes, initial
// contract code and a salt.
func CreateAddress2(b common.Address, salt [32]byte, code []byte) common.Address {
return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], Keccak256(code))[12:])
// contract code hash and a salt.
func CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address {
return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:])
}
// ToECDSA creates a private key with the given D value.

View File

@ -54,7 +54,7 @@ static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const se
even if r was negative. */
static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m);
/** Right-shift the passed number by bits bits. */
/** Right-shift the passed number by bits. */
static void secp256k1_num_shift(secp256k1_num *r, int bits);
/** Check whether a number is zero. */

View File

@ -67,6 +67,15 @@ func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
return hexutil.Uint64(api.e.Miner().HashRate())
}
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
func (api *PublicEthereumAPI) ChainId() hexutil.Uint64 {
chainID := new(big.Int)
if config := api.e.chainConfig; config.IsEIP155(api.e.blockchain.CurrentBlock().Number()) {
chainID = config.ChainID
}
return (hexutil.Uint64)(chainID.Uint64())
}
// PublicMinerAPI provides an API to control the miner.
// It offers only methods that operate on data that pose no security risk when it is publicly accessible.
type PublicMinerAPI struct {

View File

@ -25,7 +25,6 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@ -107,18 +106,11 @@ func (b *EthAPIBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.
}
func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return rawdb.ReadReceipts(b.eth.chainDb, hash, *number), nil
}
return nil, nil
return b.eth.blockchain.GetReceiptsByHash(hash), nil
}
func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash)
if number == nil {
return nil, nil
}
receipts := rawdb.ReadReceipts(b.eth.chainDb, hash, *number)
receipts := b.eth.blockchain.GetReceiptsByHash(hash)
if receipts == nil {
return nil, nil
}

View File

@ -391,6 +391,15 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string,
return api.TraceBlock(ctx, blob, config)
}
// TraceBadBlock returns the structured logs created during the execution of a block
// within the blockchain 'badblocks' cache
func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, index int, config *TraceConfig) ([]*txTraceResult, error) {
if blocks := api.eth.blockchain.BadBlocks(); index < len(blocks) {
return api.traceBlock(ctx, blocks[index], config)
}
return nil, fmt.Errorf("index out of range")
}
// traceBlock configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The return value will be one item
// per transaction, dependent on the requestd tracer.

View File

@ -60,6 +60,9 @@ var (
maxHeadersProcess = 2048 // Number of header download results to import at once into the chain
maxResultsProcess = 2048 // Number of content download results to import at once into the chain
reorgProtThreshold = 48 // Threshold number of recent blocks to disable mini reorg protection
reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs
fsHeaderCheckFrequency = 100 // Verification frequency of the downloaded headers during fast sync
fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected
fsHeaderForceVerify = 24 // Number of headers to verify before and after the pivot to accept it
@ -674,8 +677,10 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
continue
}
// Otherwise check if we already know the header or not
if (d.mode == FullSync && d.blockchain.HasBlock(headers[i].Hash(), headers[i].Number.Uint64())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash(), headers[i].Number.Uint64())) {
number, hash = headers[i].Number.Uint64(), headers[i].Hash()
h := headers[i].Hash()
n := headers[i].Number.Uint64()
if (d.mode == FullSync && d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && d.lightchain.HasHeader(h, n)) {
number, hash = n, h
// If every header is known, even future ones, the peer straight out lied about its head
if number > height && i == limit-1 {
@ -739,11 +744,13 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
arrived = true
// Modify the search interval based on the response
if (d.mode == FullSync && !d.blockchain.HasBlock(headers[0].Hash(), headers[0].Number.Uint64())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash(), headers[0].Number.Uint64())) {
h := headers[0].Hash()
n := headers[0].Number.Uint64()
if (d.mode == FullSync && !d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && !d.lightchain.HasHeader(h, n)) {
end = check
break
}
header := d.lightchain.GetHeaderByHash(headers[0].Hash()) // Independent of sync mode, header surely exists
header := d.lightchain.GetHeaderByHash(h) // Independent of sync mode, header surely exists
if header.Number.Uint64() != check {
p.log.Debug("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check)
return 0, errBadPeer
@ -859,6 +866,30 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64)
}
headers = filled[proced:]
from += uint64(proced)
} else {
// If we're closing in on the chain head, but haven't yet reached it, delay
// the last few headers so mini reorgs on the head don't cause invalid hash
// chain errors.
if n := len(headers); n > 0 {
// Retrieve the current head we're at
head := uint64(0)
if d.mode == LightSync {
head = d.lightchain.CurrentHeader().Number.Uint64()
} else {
head = d.blockchain.CurrentFastBlock().NumberU64()
if full := d.blockchain.CurrentBlock().NumberU64(); head < full {
head = full
}
}
// If the head is way older than this batch, delay the last few headers
if head+uint64(reorgProtThreshold) < headers[n-1].Number.Uint64() {
delay := reorgProtHeaderDelay
if delay > n {
delay = n
}
headers = headers[:n-delay]
}
}
}
// Insert all the new headers and fetch the next batch
if len(headers) > 0 {
@ -869,8 +900,18 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64)
return errCancelHeaderFetch
}
from += uint64(len(headers))
getHeaders(from)
} else {
// No headers delivered, or all of them being delayed, sleep a bit and retry
p.log.Trace("All headers delayed, waiting")
select {
case <-time.After(fsHeaderContCheck):
getHeaders(from)
continue
case <-d.cancelCh:
return errCancelHeaderFetch
}
}
getHeaders(from)
case <-timeout.C:
if d.dropPeer == nil {

View File

@ -53,6 +53,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.NoPruning = c.NoPruning
enc.LightServ = c.LightServ
enc.LightPeers = c.LightPeers
enc.OnlyAnnounce = c.OnlyAnnounce
enc.ULC = c.ULC
enc.SkipBcVersionCheck = c.SkipBcVersionCheck
enc.DatabaseHandles = c.DatabaseHandles
enc.DatabaseCache = c.DatabaseCache

View File

@ -37,7 +37,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
@ -49,6 +49,9 @@ const (
// txChanSize is the size of channel listening to NewTxsEvent.
// The number is referenced from the size of tx pool.
txChanSize = 4096
// minimim number of peers to broadcast new blocks to
minBroadcastPeers = 4
)
var (
@ -147,7 +150,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
NodeInfo: func() interface{} {
return manager.NodeInfo()
},
PeerInfo: func(id discover.NodeID) interface{} {
PeerInfo: func(id enode.ID) interface{} {
if p := manager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil {
return p.Info()
}
@ -708,7 +711,14 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
return
}
// Send the block to a subset of our peers
transfer := peers[:int(math.Sqrt(float64(len(peers))))]
transferLen := int(math.Sqrt(float64(len(peers))))
if transferLen < minBroadcastPeers {
transferLen = minBroadcastPeers
}
if transferLen > len(peers) {
transferLen = len(peers)
}
transfer := peers[:transferLen]
for _, peer := range transfer {
peer.AsyncSendNewBlock(block, td)
}

View File

@ -37,7 +37,7 @@ const (
// ProtocolName is the official short name of the protocol used during capability negotiation.
var ProtocolName = "eth"
// ProtocolVersions are the upported versions of the eth protocol (first is primary).
// ProtocolVersions are the supported versions of the eth protocol (first is primary).
var ProtocolVersions = []uint{eth63, eth62}
// ProtocolLengths are the number of implemented message corresponding to different protocol versions.

View File

@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
)
const (
@ -64,7 +64,7 @@ func (pm *ProtocolManager) syncTransactions(p *peer) {
// the transactions in small packs to one peer at a time.
func (pm *ProtocolManager) txsyncLoop() {
var (
pending = make(map[discover.NodeID]*txsync)
pending = make(map[enode.ID]*txsync)
sending = false // whether a send is active
pack = new(txsync) // the pack that is being sent
done = make(chan error, 1) // result of the send

View File

@ -25,11 +25,11 @@ import (
"runtime"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log/term"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/exp"
"github.com/fjl/memsize/memsizeui"
colorable "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
"gopkg.in/urfave/cli.v1"
)
@ -101,7 +101,7 @@ var (
)
func init() {
usecolor := term.IsTty(os.Stderr.Fd()) && os.Getenv("TERM") != "dumb"
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
output := io.Writer(os.Stderr)
if usecolor {
output = colorable.NewColorableStderr()

View File

@ -457,7 +457,7 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c
// addr = ecrecover(hash, signature)
//
// Note, the signature must conform to the secp256k1 curve R, S and V values, where
// the V value must be be 27 or 28 for legacy reasons.
// the V value must be 27 or 28 for legacy reasons.
//
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {

View File

@ -1021,7 +1021,7 @@ var formatOutputInt = function (param) {
var value = param.staticPart() || "0";
// check if it's negative number
// it it is, return two's complement
// it is, return two's complement
if (signedIsNegative(value)) {
return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
}
@ -2250,7 +2250,7 @@ var isAddress = function (address) {
// check if it has the basic requirements of an address
return false;
} else if (/^(0x)?[0-9a-f]{40}$/.test(address) || /^(0x)?[0-9A-F]{40}$/.test(address)) {
// If it's all small caps or all all caps, return true
// If it's all small caps or all caps, return true
return true;
} else {
// Otherwise check each case

View File

@ -378,6 +378,12 @@ web3._extend({
params: 2,
inputFormatter: [null, null]
}),
new web3._extend.Method({
name: 'traceBadBlock',
call: 'debug_traceBadBlock',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'traceBlockByNumber',
call: 'debug_traceBlockByNumber',
@ -433,6 +439,11 @@ const Eth_JS = `
web3._extend({
property: 'eth',
methods: [
new web3._extend.Method({
name: 'chainId',
call: 'eth_chainId',
params: 0
}),
new web3._extend.Method({
name: 'sign',
call: 'eth_sign',

View File

@ -20,6 +20,7 @@ package les
import (
"fmt"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
@ -161,6 +162,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
}
if leth.protocolManager.isULCEnabled() {
log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.protocolManager.ulc.trustedKeys), "minTrustedFraction", leth.protocolManager.ulc.minTrustedFraction)
leth.blockchain.DisableCheckFreq()
}
leth.ApiBackend = &LesApiBackend{leth, nil}
@ -279,6 +281,7 @@ func (s *LightEthereum) Stop() error {
s.eventMux.Stop()
time.Sleep(time.Millisecond * 200)
s.chainDb.Close()
close(s.shutdownChan)

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