Skip to content

Commit c0c0161

Browse files
authored
node: refactor package node (ethereum#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.
1 parent b2b14e6 commit c0c0161

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2558
-2839
lines changed

cmd/faucet/faucet.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -235,23 +235,20 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
235235
if err != nil {
236236
return nil, err
237237
}
238+
238239
// Assemble the Ethereum light client protocol
239-
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
240-
cfg := eth.DefaultConfig
241-
cfg.SyncMode = downloader.LightSync
242-
cfg.NetworkId = network
243-
cfg.Genesis = genesis
244-
return les.New(ctx, &cfg)
245-
}); err != nil {
246-
return nil, err
240+
cfg := eth.DefaultConfig
241+
cfg.SyncMode = downloader.LightSync
242+
cfg.NetworkId = network
243+
cfg.Genesis = genesis
244+
lesBackend, err := les.New(stack, &cfg)
245+
if err != nil {
246+
return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
247247
}
248+
248249
// Assemble the ethstats monitoring and reporting service'
249250
if stats != "" {
250-
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
251-
var serv *les.LightEthereum
252-
ctx.Service(&serv)
253-
return ethstats.New(stats, nil, serv)
254-
}); err != nil {
251+
if err := ethstats.New(stack, lesBackend.ApiBackend, lesBackend.Engine(), stats); err != nil {
255252
return nil, err
256253
}
257254
}
@@ -268,7 +265,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
268265
// Attach to the client and retrieve and interesting metadatas
269266
api, err := stack.Attach()
270267
if err != nil {
271-
stack.Stop()
268+
stack.Close()
272269
return nil, err
273270
}
274271
client := ethclient.NewClient(api)

cmd/geth/chaincmd.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,9 @@ func initGenesis(ctx *cli.Context) error {
239239
if err := json.NewDecoder(file).Decode(genesis); err != nil {
240240
utils.Fatalf("invalid genesis file: %v", err)
241241
}
242+
242243
// Open an initialise both full and light databases
243-
stack := makeFullNode(ctx)
244+
stack, _ := makeConfigNode(ctx)
244245
defer stack.Close()
245246

246247
for _, name := range []string{"chaindata", "lightchaindata"} {
@@ -277,7 +278,7 @@ func importChain(ctx *cli.Context) error {
277278
utils.SetupMetrics(ctx)
278279
// Start system runtime metrics collection
279280
go metrics.CollectProcessMetrics(3 * time.Second)
280-
stack := makeFullNode(ctx)
281+
stack, _ := makeFullNode(ctx)
281282
defer stack.Close()
282283

283284
chain, db := utils.MakeChain(ctx, stack, false)
@@ -371,7 +372,7 @@ func exportChain(ctx *cli.Context) error {
371372
if len(ctx.Args()) < 1 {
372373
utils.Fatalf("This command requires an argument.")
373374
}
374-
stack := makeFullNode(ctx)
375+
stack, _ := makeFullNode(ctx)
375376
defer stack.Close()
376377

377378
chain, _ := utils.MakeChain(ctx, stack, true)
@@ -406,7 +407,7 @@ func importPreimages(ctx *cli.Context) error {
406407
if len(ctx.Args()) < 1 {
407408
utils.Fatalf("This command requires an argument.")
408409
}
409-
stack := makeFullNode(ctx)
410+
stack, _ := makeFullNode(ctx)
410411
defer stack.Close()
411412

412413
db := utils.MakeChainDatabase(ctx, stack)
@@ -424,7 +425,7 @@ func exportPreimages(ctx *cli.Context) error {
424425
if len(ctx.Args()) < 1 {
425426
utils.Fatalf("This command requires an argument.")
426427
}
427-
stack := makeFullNode(ctx)
428+
stack, _ := makeFullNode(ctx)
428429
defer stack.Close()
429430

430431
db := utils.MakeChainDatabase(ctx, stack)
@@ -446,7 +447,7 @@ func copyDb(ctx *cli.Context) error {
446447
utils.Fatalf("Source ancient chain directory path argument missing")
447448
}
448449
// Initialize a new chain for the running node to sync into
449-
stack := makeFullNode(ctx)
450+
stack, _ := makeFullNode(ctx)
450451
defer stack.Close()
451452

452453
chain, chainDb := utils.MakeChain(ctx, stack, false)
@@ -554,7 +555,7 @@ func confirmAndRemoveDB(database string, kind string) {
554555
}
555556

556557
func dump(ctx *cli.Context) error {
557-
stack := makeFullNode(ctx)
558+
stack, _ := makeFullNode(ctx)
558559
defer stack.Close()
559560

560561
chain, chainDb := utils.MakeChain(ctx, stack, true)

cmd/geth/config.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828

2929
"github.com/ethereum/go-ethereum/cmd/utils"
3030
"github.com/ethereum/go-ethereum/eth"
31+
"github.com/ethereum/go-ethereum/internal/ethapi"
3132
"github.com/ethereum/go-ethereum/node"
3233
"github.com/ethereum/go-ethereum/params"
3334
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
@@ -144,9 +145,10 @@ func enableWhisper(ctx *cli.Context) bool {
144145
return false
145146
}
146147

147-
func makeFullNode(ctx *cli.Context) *node.Node {
148+
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
148149
stack, cfg := makeConfigNode(ctx)
149-
utils.RegisterEthService(stack, &cfg.Eth)
150+
151+
backend := utils.RegisterEthService(stack, &cfg.Eth)
150152

151153
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
152154
shhEnabled := enableWhisper(ctx)
@@ -165,13 +167,13 @@ func makeFullNode(ctx *cli.Context) *node.Node {
165167
}
166168
// Configure GraphQL if requested
167169
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
168-
utils.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
170+
utils.RegisterGraphQLService(stack, backend, cfg.Node)
169171
}
170172
// Add the Ethereum Stats daemon if requested.
171173
if cfg.Ethstats.URL != "" {
172-
utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
174+
utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL)
173175
}
174-
return stack
176+
return stack, backend
175177
}
176178

177179
// dumpConfig is the dumpconfig command.

cmd/geth/consolecmd.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
7878
func localConsole(ctx *cli.Context) error {
7979
// Create and start the node based on the CLI flags
8080
prepare(ctx)
81-
node := makeFullNode(ctx)
82-
startNode(ctx, node)
83-
defer node.Close()
81+
stack, backend := makeFullNode(ctx)
82+
startNode(ctx, stack, backend)
83+
defer stack.Close()
8484

8585
// Attach to the newly started node and start the JavaScript console
86-
client, err := node.Attach()
86+
client, err := stack.Attach()
8787
if err != nil {
8888
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
8989
}
@@ -190,12 +190,12 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
190190
// everything down.
191191
func ephemeralConsole(ctx *cli.Context) error {
192192
// Create and start the node based on the CLI flags
193-
node := makeFullNode(ctx)
194-
startNode(ctx, node)
195-
defer node.Close()
193+
stack, backend := makeFullNode(ctx)
194+
startNode(ctx, stack, backend)
195+
defer stack.Close()
196196

197197
// Attach to the newly started node and start the JavaScript console
198-
client, err := node.Attach()
198+
client, err := stack.Attach()
199199
if err != nil {
200200
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
201201
}

cmd/geth/dao_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
119119
} else {
120120
// Force chain initialization
121121
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
122-
geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
123-
geth.WaitExit()
122+
runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...).WaitExit()
124123
}
125124
// Retrieve the DAO config flag from the database
126125
path := filepath.Join(datadir, "geth", "chaindata")

cmd/geth/main.go

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ import (
3636
"github.com/ethereum/go-ethereum/eth/downloader"
3737
"github.com/ethereum/go-ethereum/ethclient"
3838
"github.com/ethereum/go-ethereum/internal/debug"
39+
"github.com/ethereum/go-ethereum/internal/ethapi"
3940
"github.com/ethereum/go-ethereum/internal/flags"
40-
"github.com/ethereum/go-ethereum/les"
4141
"github.com/ethereum/go-ethereum/log"
4242
"github.com/ethereum/go-ethereum/metrics"
4343
"github.com/ethereum/go-ethereum/node"
@@ -171,8 +171,6 @@ var (
171171
utils.LegacyRPCCORSDomainFlag,
172172
utils.LegacyRPCVirtualHostsFlag,
173173
utils.GraphQLEnabledFlag,
174-
utils.GraphQLListenAddrFlag,
175-
utils.GraphQLPortFlag,
176174
utils.GraphQLCORSDomainFlag,
177175
utils.GraphQLVirtualHostsFlag,
178176
utils.HTTPApiFlag,
@@ -350,18 +348,20 @@ func geth(ctx *cli.Context) error {
350348
if args := ctx.Args(); len(args) > 0 {
351349
return fmt.Errorf("invalid command: %q", args[0])
352350
}
351+
353352
prepare(ctx)
354-
node := makeFullNode(ctx)
355-
defer node.Close()
356-
startNode(ctx, node)
357-
node.Wait()
353+
stack, backend := makeFullNode(ctx)
354+
defer stack.Close()
355+
356+
startNode(ctx, stack, backend)
357+
stack.Wait()
358358
return nil
359359
}
360360

361361
// startNode boots up the system node and all registered protocols, after which
362362
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
363363
// miner.
364-
func startNode(ctx *cli.Context, stack *node.Node) {
364+
func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
365365
debug.Memsize.Add("node", stack)
366366

367367
// Start up the node itself
@@ -381,25 +381,6 @@ func startNode(ctx *cli.Context, stack *node.Node) {
381381
}
382382
ethClient := ethclient.NewClient(rpcClient)
383383

384-
// Set contract backend for ethereum service if local node
385-
// is serving LES requests.
386-
if ctx.GlobalInt(utils.LegacyLightServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 {
387-
var ethService *eth.Ethereum
388-
if err := stack.Service(&ethService); err != nil {
389-
utils.Fatalf("Failed to retrieve ethereum service: %v", err)
390-
}
391-
ethService.SetContractBackend(ethClient)
392-
}
393-
// Set contract backend for les service if local node is
394-
// running as a light client.
395-
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
396-
var lesService *les.LightEthereum
397-
if err := stack.Service(&lesService); err != nil {
398-
utils.Fatalf("Failed to retrieve light ethereum service: %v", err)
399-
}
400-
lesService.SetContractBackend(ethClient)
401-
}
402-
403384
go func() {
404385
// Open any wallets already attached
405386
for _, wallet := range stack.AccountManager().Wallets() {
@@ -451,7 +432,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
451432
if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute {
452433
log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(),
453434
"age", common.PrettyAge(timestamp))
454-
stack.Stop()
435+
stack.Close()
455436
}
456437
}
457438
}()
@@ -463,24 +444,24 @@ func startNode(ctx *cli.Context, stack *node.Node) {
463444
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
464445
utils.Fatalf("Light clients do not support mining")
465446
}
466-
var ethereum *eth.Ethereum
467-
if err := stack.Service(&ethereum); err != nil {
447+
ethBackend, ok := backend.(*eth.EthAPIBackend)
448+
if !ok {
468449
utils.Fatalf("Ethereum service not running: %v", err)
469450
}
451+
470452
// Set the gas price to the limits from the CLI and start mining
471453
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
472454
if ctx.GlobalIsSet(utils.LegacyMinerGasPriceFlag.Name) && !ctx.GlobalIsSet(utils.MinerGasPriceFlag.Name) {
473455
gasprice = utils.GlobalBig(ctx, utils.LegacyMinerGasPriceFlag.Name)
474456
}
475-
ethereum.TxPool().SetGasPrice(gasprice)
476-
457+
ethBackend.TxPool().SetGasPrice(gasprice)
458+
// start mining
477459
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
478460
if ctx.GlobalIsSet(utils.LegacyMinerThreadsFlag.Name) && !ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
479461
threads = ctx.GlobalInt(utils.LegacyMinerThreadsFlag.Name)
480462
log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads")
481463
}
482-
483-
if err := ethereum.StartMining(threads); err != nil {
464+
if err := ethBackend.StartMining(threads); err != nil {
484465
utils.Fatalf("Failed to start mining: %v", err)
485466
}
486467
}

cmd/geth/usage.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,6 @@ var AppHelpFlagGroups = []flags.FlagGroup{
142142
utils.WSApiFlag,
143143
utils.WSAllowedOriginsFlag,
144144
utils.GraphQLEnabledFlag,
145-
utils.GraphQLListenAddrFlag,
146-
utils.GraphQLPortFlag,
147145
utils.GraphQLCORSDomainFlag,
148146
utils.GraphQLVirtualHostsFlag,
149147
utils.RPCGlobalGasCap,
@@ -231,6 +229,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{
231229
utils.LegacyWSApiFlag,
232230
utils.LegacyGpoBlocksFlag,
233231
utils.LegacyGpoPercentileFlag,
232+
utils.LegacyGraphQLListenAddrFlag,
233+
utils.LegacyGraphQLPortFlag,
234234
}, debug.DeprecatedFlags...),
235235
},
236236
{

cmd/p2psim/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ func createNode(ctx *cli.Context) error {
289289
config.PrivateKey = privKey
290290
}
291291
if services := ctx.String("services"); services != "" {
292-
config.Services = strings.Split(services, ",")
292+
config.Lifecycles = strings.Split(services, ",")
293293
}
294294
node, err := client.CreateNode(config)
295295
if err != nil {

cmd/utils/cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func StartNode(stack *node.Node) {
7373
defer signal.Stop(sigc)
7474
<-sigc
7575
log.Info("Got interrupt, shutting down...")
76-
go stack.Stop()
76+
go stack.Close()
7777
for i := 10; i > 0; i-- {
7878
<-sigc
7979
if i > 1 {

0 commit comments

Comments
 (0)