node: refactor package node (#21105)

This PR significantly changes the APIs for instantiating Ethereum nodes in
a Go program. The new APIs are not backwards-compatible, but we feel that
this is made up for by the much simpler way of registering services on
node.Node. You can find more information and rationale in the design
document: https://gist.github.com/renaynay/5bec2de19fde66f4d04c535fd24f0775.

There is also a new feature in Node's Go API: it is now possible to
register arbitrary handlers on the user-facing HTTP server. In geth, this
facility is used to enable GraphQL.

There is a single minor change relevant for geth users in this PR: The
GraphQL API is no longer available separately from the JSON-RPC HTTP
server. If you want GraphQL, you need to enable it using the
./geth --http --graphql flag combination.

The --graphql.port and --graphql.addr flags are no longer available.
This commit is contained in:
rene
2020-08-03 19:40:46 +02:00
committed by GitHub
parent b2b14e6ce3
commit c0c01612e9
63 changed files with 2606 additions and 2887 deletions

View File

@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/node"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
)
@@ -89,7 +90,11 @@ func TestMailServer(t *testing.T) {
}
var server WMailServer
shh = whisper.New(&whisper.DefaultConfig)
stack, w := newNode(t)
defer stack.Close()
shh = w
shh.RegisterServer(&server)
err = server.Init(shh, dir, password, powRequirement)
@@ -210,3 +215,21 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
}
return env
}
// newNode creates a new node using a default config and
// creates and registers a new Whisper service on it.
func newNode(t *testing.T) (*node.Node, *whisper.Whisper) {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("could not create new node: %v", err)
}
w, err := whisper.New(stack, &whisper.DefaultConfig)
if err != nil {
t.Fatalf("could not create new whisper service: %v", err)
}
err = stack.Start()
if err != nil {
t.Fatalf("could not start node: %v", err)
}
return stack, w
}

View File

@@ -23,7 +23,8 @@ import (
)
func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) {
w := New(nil)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
keyID, err := w.GenerateSymKey()
if err != nil {

View File

@@ -92,7 +92,10 @@ func TestInstallFilters(t *testing.T) {
InitSingleTest()
const SizeTestFilters = 256
w := New(&Config{})
stack, w := newNodeWithWhisper(t)
defer stack.Close()
filters := NewFilters(w)
tst := generateTestCases(t, SizeTestFilters)
@@ -130,7 +133,9 @@ func TestInstallFilters(t *testing.T) {
func TestInstallSymKeyGeneratesHash(t *testing.T) {
InitSingleTest()
w := New(&Config{})
stack, w := newNodeWithWhisper(t)
defer stack.Close()
filters := NewFilters(w)
filter, _ := generateFilter(t, true)
@@ -157,7 +162,9 @@ func TestInstallSymKeyGeneratesHash(t *testing.T) {
func TestInstallIdenticalFilters(t *testing.T) {
InitSingleTest()
w := New(&Config{})
stack, w := newNodeWithWhisper(t)
defer stack.Close()
filters := NewFilters(w)
filter1, _ := generateFilter(t, true)
@@ -227,7 +234,9 @@ func TestInstallIdenticalFilters(t *testing.T) {
func TestInstallFilterWithSymAndAsymKeys(t *testing.T) {
InitSingleTest()
w := New(&Config{})
stack, w := newNodeWithWhisper(t)
defer stack.Close()
filters := NewFilters(w)
filter1, _ := generateFilter(t, true)
@@ -641,7 +650,9 @@ func TestWatchers(t *testing.T) {
var x, firstID string
var err error
w := New(&Config{})
stack, w := newNodeWithWhisper(t)
defer stack.Close()
filters := NewFilters(w)
tst := generateTestCases(t, NumFilters)
for i = 0; i < NumFilters; i++ {

View File

@@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
@@ -93,7 +94,7 @@ type Whisper struct {
}
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
func New(cfg *Config) *Whisper {
func New(stack *node.Node, cfg *Config) (*Whisper, error) {
if cfg == nil {
cfg = &DefaultConfig
}
@@ -132,7 +133,10 @@ func New(cfg *Config) *Whisper {
},
}
return whisper
stack.RegisterAPIs(whisper.APIs())
stack.RegisterProtocols(whisper.Protocols())
stack.RegisterLifecycle(whisper)
return whisper, nil
}
// MinPow returns the PoW value required by this node.
@@ -634,9 +638,9 @@ func (whisper *Whisper) Send(envelope *Envelope) error {
return err
}
// Start implements node.Service, starting the background data propagation thread
// Start implements node.Lifecycle, starting the background data propagation thread
// of the Whisper protocol.
func (whisper *Whisper) Start(*p2p.Server) error {
func (whisper *Whisper) Start() error {
log.Info("started whisper v." + ProtocolVersionStr)
whisper.wg.Add(1)
go whisper.update()
@@ -650,7 +654,7 @@ func (whisper *Whisper) Start(*p2p.Server) error {
return nil
}
// Stop implements node.Service, stopping the background data propagation thread
// Stop implements node.Lifecycle, stopping the background data propagation thread
// of the Whisper protocol.
func (whisper *Whisper) Stop() error {
close(whisper.quit)
@@ -1092,3 +1096,45 @@ func addBloom(a, b []byte) []byte {
}
return c
}
func StandaloneWhisperService(cfg *Config) *Whisper {
if cfg == nil {
cfg = &DefaultConfig
}
whisper := &Whisper{
privateKeys: make(map[string]*ecdsa.PrivateKey),
symKeys: make(map[string][]byte),
envelopes: make(map[common.Hash]*Envelope),
expirations: make(map[uint32]mapset.Set),
peers: make(map[*Peer]struct{}),
messageQueue: make(chan *Envelope, messageQueueLimit),
p2pMsgQueue: make(chan *Envelope, messageQueueLimit),
quit: make(chan struct{}),
syncAllowance: DefaultSyncAllowance,
}
whisper.filters = NewFilters(whisper)
whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW)
whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize)
whisper.settings.Store(overflowIdx, false)
whisper.settings.Store(restrictConnectionBetweenLightClientsIdx, cfg.RestrictConnectionBetweenLightClients)
// p2p whisper sub protocol handler
whisper.protocol = p2p.Protocol{
Name: ProtocolName,
Version: uint(ProtocolVersion),
Length: NumberOfMessageCodes,
Run: whisper.HandlePeer,
NodeInfo: func() interface{} {
return map[string]interface{}{
"version": ProtocolVersionStr,
"maxMessageSize": whisper.MaxMessageSize(),
"minimumPoW": whisper.MinPow(),
}
},
}
return whisper
}

View File

@@ -25,13 +25,15 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/node"
"golang.org/x/crypto/pbkdf2"
)
func TestWhisperBasic(t *testing.T) {
w := New(&DefaultConfig)
p := w.Protocols()
shh := p[0]
stack, w := newNodeWithWhisper(t)
defer stack.Close()
shh := w.Protocols()[0]
if shh.Name != ProtocolName {
t.Fatalf("failed Protocol Name: %v.", shh.Name)
}
@@ -111,11 +113,10 @@ func TestWhisperBasic(t *testing.T) {
}
func TestWhisperAsymmetricKeyImport(t *testing.T) {
var (
w = New(&DefaultConfig)
privateKeys []*ecdsa.PrivateKey
)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
var privateKeys []*ecdsa.PrivateKey
for i := 0; i < 50; i++ {
id, err := w.NewKeyPair()
if err != nil {
@@ -142,7 +143,9 @@ func TestWhisperAsymmetricKeyImport(t *testing.T) {
}
func TestWhisperIdentityManagement(t *testing.T) {
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
id1, err := w.NewKeyPair()
if err != nil {
t.Fatalf("failed to generate new key pair: %s.", err)
@@ -261,12 +264,14 @@ func TestWhisperIdentityManagement(t *testing.T) {
func TestWhisperSymKeyManagement(t *testing.T) {
InitSingleTest()
var (
k1, k2 []byte
w = New(&DefaultConfig)
id2 = string("arbitrary-string-2")
)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
id1, err := w.GenerateSymKey()
if err != nil {
t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err)
@@ -365,7 +370,7 @@ func TestWhisperSymKeyManagement(t *testing.T) {
w.DeleteSymKey(id1)
k1, err = w.GetSymKey(id1)
if err == nil {
t.Fatalf("failed w.GetSymKey(id1): false positive.")
t.Fatal("failed w.GetSymKey(id1): false positive.")
}
if k1 != nil {
t.Fatalf("failed GetSymKey(id1): false positive. key=%v", k1)
@@ -451,11 +456,12 @@ func TestWhisperSymKeyManagement(t *testing.T) {
func TestExpiry(t *testing.T) {
InitSingleTest()
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
w.SetMinimumPowTest(0.0000001)
defer w.SetMinimumPowTest(DefaultMinimumPoW)
w.Start(nil)
defer w.Stop()
w.Start()
params, err := generateMessageParams()
if err != nil {
@@ -517,11 +523,12 @@ func TestExpiry(t *testing.T) {
func TestCustomization(t *testing.T) {
InitSingleTest()
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start(nil)
defer w.Stop()
w.Start()
const smallPoW = 0.00001
@@ -610,11 +617,12 @@ func TestCustomization(t *testing.T) {
func TestSymmetricSendCycle(t *testing.T) {
InitSingleTest()
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start(nil)
defer w.Stop()
w.Start()
filter1, err := generateFilter(t, true)
if err != nil {
@@ -701,11 +709,12 @@ func TestSymmetricSendCycle(t *testing.T) {
func TestSymmetricSendWithoutAKey(t *testing.T) {
InitSingleTest()
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start(nil)
defer w.Stop()
w.Start()
filter, err := generateFilter(t, true)
if err != nil {
@@ -771,11 +780,12 @@ func TestSymmetricSendWithoutAKey(t *testing.T) {
func TestSymmetricSendKeyMismatch(t *testing.T) {
InitSingleTest()
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start(nil)
defer w.Stop()
w.Start()
filter, err := generateFilter(t, true)
if err != nil {
@@ -882,17 +892,37 @@ func TestBloom(t *testing.T) {
t.Fatal("bloomFilterMatch false negative")
}
w := New(&DefaultConfig)
stack, w := newNodeWithWhisper(t)
defer stack.Close()
f := w.BloomFilter()
if f != nil {
t.Fatal("wrong bloom on creation")
}
err = w.SetBloomFilter(x)
if err != nil {
t.Fatalf("failed to set bloom filter: %s", err)
t.Fatalf("failed to set bloom filter: %v", err)
}
f = w.BloomFilter()
if !BloomFilterMatch(f, x) || !BloomFilterMatch(x, f) {
t.Fatal("retireved wrong bloom filter")
}
}
// newNodeWithWhisper creates a new node using a default config and
// creates and registers a new Whisper service on it.
func newNodeWithWhisper(t *testing.T) (*node.Node, *Whisper) {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("could not create new node: %v", err)
}
w, err := New(stack, &DefaultConfig)
if err != nil {
t.Fatalf("could not create new whisper service: %v", err)
}
err = stack.Start()
if err != nil {
t.Fatalf("could not start node: %v", err)
}
return stack, w
}