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:
@@ -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
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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++ {
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user