When starting up, the Geth client begins by parsing the command line parameters. This process kicks off with the geth function: func geth(ctx *cli.Context) error at cmd/geth/main.go:326 where the geth prepares the metric if enabled. Subsequently, the makeFullNode function takes over. It reads the provided configuration file or command line flags. As a result, it returns two key components: the protocol stack and the backend API.
It’s worth noting the importance of the Backend API. It establishes a myriad of interfaces, facilitating interaction with nodes and handling external RPC call limits.
// Backend interface provides the common API services (that are provided by // both full and light clients) with access to necessary functions. type Backend interface { // General Ethereum API SyncProgress() ethereum.SyncProgress
SuggestGasTipCap(ctx context.Context) (*big.Int, error) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) ChainDb() ethdb.Database AccountManager() *accounts.Manager ExtRPCEnabled() bool RPCGasCap() uint64// global gas cap for eth_call over rpc: DoS protection RPCEVMTimeout() time.Duration // global timeout for eth_call over rpc: DoS protection RPCTxFeeCap() float64// global tx fee cap for all transaction related APIs UnprotectedAllowed() bool// allows only for EIP155 transactions.
// This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by // it must also be included here. GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) }
For instance, the SyncProgress() method captures the node’s status as it synchronizes with the Ethereum network.
type SyncProgress struct { StartingBlock uint64// Block number where sync began CurrentBlock uint64// Current block number where sync is at HighestBlock uint64// Highest alleged block number in the chain
// "fast sync" fields. These used to be sent by geth, but are no longer used // since version v1.10. PulledStates uint64// Number of state trie entries already downloaded KnownStates uint64// Total number of state trie entries known about
// "snap sync" fields. SyncedAccounts uint64// Number of accounts downloaded SyncedAccountBytes uint64// Number of account trie bytes persisted to disk SyncedBytecodes uint64// Number of bytecodes downloaded SyncedBytecodeBytes uint64// Number of bytecode bytes downloaded SyncedStorage uint64// Number of storage slots downloaded SyncedStorageBytes uint64// Number of storage trie bytes persisted to disk
HealedTrienodes uint64// Number of state trie nodes downloaded HealedTrienodeBytes uint64// Number of state trie bytes persisted to disk HealedBytecodes uint64// Number of bytecodes downloaded HealedBytecodeBytes uint64// Number of bytecodes persisted to disk
HealingTrienodes uint64// Number of state trie nodes pending HealingBytecode uint64// Number of bytecodes pending }
Regarding the protocol stack, it’s represented by the Node structure, which comprises numerous fields. Among these, the stop field plays a pivotal role as it signals the termination of the server.
// Node is a container on which services can be registered. type Node struct { eventmux *event.TypeMux config *Config accman *accounts.Manager log log.Logger keyDir string// key store directory keyDirTemp bool// If true, key directory will be removed by Stop dirLock *flock.Flock // prevents concurrent use of instance directory stop chanstruct{} // Channel to wait for termination notifications server *p2p.Server // Currently running P2P networking layer startStopLock sync.Mutex // Start/Stop are protected by an additional lock state int// Tracks state of node lifecycle
lock sync.Mutex lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle rpcAPIs []rpc.API // List of APIs currently provided by the node http *httpServer // ws *httpServer // httpAuth *httpServer // wsAuth *httpServer // ipc *ipcServer // Stores information about the ipc http server inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
databases map[*closeTrackingDB]struct{} // All open databases }
Once all configurations are in place and prior to the server’s actual launch, you should observe the following output:
INFO [09-13|12:46:39.391] Starting Geth on Ethereum mainnet... INFO [09-13|12:46:39.392] Bumping default cache on mainnet provided=1024 updated=4096 INFO [09-13|12:46:39.396] Maximum peer count ETH=50 LES=0 total=50 INFO [09-13|12:46:39.400] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory" INFO [09-13|12:46:39.408] Set global gas cap cap=50,000,000 INFO [09-13|12:46:39.408] Initializing the KZG library backend=gokzg INFO [09-13|12:46:39.611] Allocated trie memory caches clean=614.00MiB dirty=1024.00MiB INFO [09-13|12:46:39.611] Using pebble as the backing database INFO [09-13|12:46:39.611] Allocated cache and file handles database=/home/username/.ethereum/geth/chaindata cache=2.00GiB handles=32767 INFO [09-13|12:46:39.677] Opened ancient database database=/home/username/.ethereum/geth/chaindata/ancient/chain readonly=false INFO [09-13|12:46:39.681] Initialising Ethereum protocol network=1 dbversion=8 INFO [09-13|12:46:39.681] INFO [09-13|12:46:39.681] --------------------------------------------------------------------------------------------------------------------------------------------------------- INFO [09-13|12:46:39.683] Chain ID: 1 (mainnet) INFO [09-13|12:46:39.683] Consensus: Beacon (proof-of-stake), merged from Ethash (proof-of-work) INFO [09-13|12:46:39.683] INFO [09-13|12:46:39.683] Pre-Merge hard forks (block based): INFO [09-13|12:46:39.683] - Homestead: #1150000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md) INFO [09-13|12:46:39.683] - DAO Fork: #1920000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md) INFO [09-13|12:46:39.683] - Tangerine Whistle (EIP 150): #2463000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md) INFO [09-13|12:46:39.683] - Spurious Dragon/1 (EIP 155): #2675000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md) INFO [09-13|12:46:39.683] - Spurious Dragon/2 (EIP 158): #2675000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md) INFO [09-13|12:46:39.683] - Byzantium: #4370000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md) INFO [09-13|12:46:39.683] - Constantinople: #7280000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md) INFO [09-13|12:46:39.683] - Petersburg: #7280000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md) INFO [09-13|12:46:39.683] - Istanbul: #9069000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md) INFO [09-13|12:46:39.683] - Muir Glacier: #9200000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md) INFO [09-13|12:46:39.683] - Berlin: #12244000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md) INFO [09-13|12:46:39.683] - London: #12965000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md) INFO [09-13|12:46:39.683] - Arrow Glacier: #13773000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md) INFO [09-13|12:46:39.683] - Gray Glacier: #15050000 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md) INFO [09-13|12:46:39.683] INFO [09-13|12:46:39.683] Merge configurationd: INFO [09-13|12:46:39.683] - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md INFO [09-13|12:46:39.683] - Network known to be merged: true INFO [09-13|12:46:39.683] - Total terminal difficulty: 58750000000000000000000 INFO [09-13|12:46:39.683] INFO [09-13|12:46:39.683] Post-Merge hard forks (timestamp based): INFO [09-13|12:46:39.684] - Shanghai: @1681338455 (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md) INFO [09-13|12:46:39.684] INFO [09-13|12:46:39.684] --------------------------------------------------------------------------------------------------------------------------------------------------------- INFO [09-13|12:46:39.684] INFO [09-13|12:46:39.686] Loaded most recent local block number=0 hash=d4e567..cb8fa3 td=17,179,869,184 age=54y5mo3w WARN [09-13|12:46:39.688] Loaded snapshot journal diffs=missing INFO [09-13|12:46:39.688] Resuming state snapshot generation root=d7f897..0f0544 accounts=0 slots=0 storage=0.00B dangling=0 elapsed="34.181µs" INFO [09-13|12:46:39.688] Loaded local transaction journal transactions=0 dropped=0 INFO [09-13|12:46:39.689] Regenerated local transaction journal transactions=0 accounts=0 INFO [09-13|12:46:39.729] Chain post-merge, sync via beacon client INFO [09-13|12:46:39.730] Gasprice oracle is ignoring threshold set threshold=2 WARN [09-13|12:46:39.738] Unclean shutdown detected booted=2023-09-12T15:07:35+0000 age=21h39m4s WARN [09-13|12:46:39.738] Unclean shutdown detected booted=2023-09-13T08:02:05+0000 age=4h44m34s WARN [09-13|12:46:39.739] Engine API enabled protocol=eth
Following this, the startNode function executes, paving the way for StartNode, which is responsible for actually initiating the server. The method stack.Start() found in cmd/utils/cmd.go:72 will launch the node. Once the server is up and running, the Geth client keeps tabs on the disk space and monitors system signals to determine when to terminate the server.
Within the Start() method, the line err := n.openEndpoints() is responsible to open networking and RPC endpoint. Meanwhile, the n.server.Start() method, located at node/node.go:269 initiates the p2p discovery and handshake processes. Concurrently, the line err := n.startRPC() located at node/node.go:273 brings the RPC endpoint to life. The output should resemble the following:
1 2 3 4 5 6 7 8 9
INFO [09-13|13:56:00.514] Starting peer-to-peer node instance=Geth/v1.12.1-unstable-60ce4e8d-20230810/linux-amd64/go1.20.6 INFO [09-13|13:56:04.989] New local node record seq=1,694,613,193,948 id=72f98ebcedb92640 ip=127.0.0.1 udp=35555 tcp=35555 INFO [09-13|13:56:05.083] Started P2P networking self=enode://9fc6b61a19d99e8a78ae8f8dbd12f27d208ce9b01dd52177fbfee1812a37467b3c3bab49c181b26b240f52bf1ac8afe64915f9b89465a540a74fdcb5e37f2abd@127.0.0.1:35555 INFO [09-13|13:56:05.325] Generating state snapshot root=d7f897..0f0544 at=9a53a5..ad4ba5 accounts=5375 slots=0 storage=247.62KiB dangling=0 elapsed=8.003s eta=28.97s INFO [09-13|13:56:10.187] IPC endpoint opened url=/home/username/.ethereum/geth.ipc INFO [09-13|13:56:10.200] Loaded JWT secret file path=/home/username/.ethereum/geth/jwtsecret crc32=0x3392b636 INFO [09-13|13:56:11.116] WebSocket enabled url=ws://127.0.0.1:8553 INFO [09-13|13:56:11.121] HTTP server started endpoint=127.0.0.1:8553 auth=true prefix= cors=localhost vhosts=localhost
Once the p2p network layer has been executed successfully, the crucial Ethereum protocol initiates and remains active. Two essential components stand out:
txPool: This manages transactions according to a specified strategy.
blockchain: This encompasses the EVM (Ethereum Virtual Machine) and upholds the chain structure of the blockchain.
The rationale for defining the subprotocol as a slice of lifecycle is that Geth also supports other protocols layered over the Devp2p protocol.
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully }
To summarize, the steps for starting a Geth client are as follows:
Command Line Parsing: The parser breaks down flags, subcommands, or the configuration file into a context.
Process Context: The command line context is processed, establishing memory cache allowances and, if enabled, metrics that monitor the runtime environment.
Protocol Stack Assembly: Based on the provided configuration, the protocol stack is assembled into a node struct. Concurrently, interaction methods are incorporated into ethapi.Backend.
Node Initialization:
P2P Network Layer: Initiates the p2p network layer for node discovery and facilitates basic pre-subprotocol (devp2p) message exchange.
RPC Endpoint: This step starts the RPC endpoint.
Subprotocols Activation: All the specified subprotocols in the lifecycles of the local node are initiated.
Monitoring: Upon successful initialization, the system begins monitoring disk space and awaits system signals for termination.