Skip to content

Commit f4f2213

Browse files
committed
feat: integrate gRPC service into Ethereum node lifecycle with configuration options for EnableGRPC, GRPCHost, and GRPCPort, register service as node lifecycle component for automatic startup and graceful shutdown, expose miner access through EthAPIBackend, and enable low-latency binary trading operations alongside traditional JSON-RPC
1 parent 0488a11 commit f4f2213

File tree

6 files changed

+223
-3
lines changed

6 files changed

+223
-3
lines changed

api/grpc/server.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import (
3737
// Backend defines the necessary methods from the Ethereum backend for the gRPC server.
3838
type Backend interface {
3939
ChainConfig() *params.ChainConfig
40-
BlockChain() *core.BlockChain
40+
CurrentBlock() *types.Header
4141
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
4242
Miner() *miner.Miner
4343
}
@@ -97,7 +97,7 @@ func (s *TraderServer) SimulateBundle(ctx context.Context, req *SimulateBundleRe
9797
}
9898

9999
// Get current block header for simulation
100-
header := s.backend.BlockChain().CurrentBlock()
100+
header := s.backend.CurrentBlock()
101101
if header == nil {
102102
return nil, errors.New("current block not found")
103103
}
@@ -323,7 +323,8 @@ func (s *TraderServer) CallContract(ctx context.Context, req *CallContractReques
323323
}
324324

325325
// Create EVM and execute call
326-
blockContext := core.NewEVMBlockContext(header, s.backend.BlockChain(), nil)
326+
// Note: Using nil for chain reader as we only need basic block context for eth_call
327+
blockContext := core.NewEVMBlockContext(header, nil, nil)
327328
vmConfig := vm.Config{}
328329

329330
evm := vm.NewEVM(blockContext, stateDB, s.backend.ChainConfig(), vmConfig)

api/grpc/service.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright 2024 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package grpc
18+
19+
import (
20+
"fmt"
21+
"net"
22+
23+
"github.com/ethereum/go-ethereum/log"
24+
"google.golang.org/grpc"
25+
)
26+
27+
// Service implements the node.Lifecycle interface for the gRPC server.
28+
type Service struct {
29+
backend Backend
30+
server *grpc.Server
31+
listener net.Listener
32+
host string
33+
port int
34+
}
35+
36+
// NewService creates a new gRPC service.
37+
func NewService(backend Backend, host string, port int) *Service {
38+
return &Service{
39+
backend: backend,
40+
host: host,
41+
port: port,
42+
}
43+
}
44+
45+
// Start implements node.Lifecycle, starting the gRPC server.
46+
func (s *Service) Start() error {
47+
addr := fmt.Sprintf("%s:%d", s.host, s.port)
48+
lis, err := net.Listen("tcp", addr)
49+
if err != nil {
50+
return fmt.Errorf("failed to listen on %s: %w", addr, err)
51+
}
52+
s.listener = lis
53+
54+
// Create gRPC server with options
55+
s.server = grpc.NewServer(
56+
grpc.MaxRecvMsgSize(100*1024*1024), // 100MB for large bundles
57+
grpc.MaxSendMsgSize(100*1024*1024), // 100MB for large simulation results
58+
)
59+
60+
// Register TraderService
61+
traderServer := NewTraderServer(s.backend)
62+
RegisterTraderServiceServer(s.server, traderServer)
63+
64+
// Start serving in a goroutine
65+
go func() {
66+
log.Info("gRPC server started", "addr", addr)
67+
if err := s.server.Serve(lis); err != nil {
68+
log.Error("gRPC server failed", "err", err)
69+
}
70+
}()
71+
72+
return nil
73+
}
74+
75+
// Stop implements node.Lifecycle, stopping the gRPC server.
76+
func (s *Service) Stop() error {
77+
if s.server != nil {
78+
log.Info("gRPC server stopping")
79+
s.server.GracefulStop()
80+
log.Info("gRPC server stopped")
81+
}
82+
return nil
83+
}
84+

eth/api_backend.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"github.com/ethereum/go-ethereum/eth/tracers"
4141
"github.com/ethereum/go-ethereum/ethdb"
4242
"github.com/ethereum/go-ethereum/event"
43+
"github.com/ethereum/go-ethereum/miner"
4344
"github.com/ethereum/go-ethereum/params"
4445
"github.com/ethereum/go-ethereum/rpc"
4546
)
@@ -61,6 +62,11 @@ func (b *EthAPIBackend) CurrentBlock() *types.Header {
6162
return b.eth.blockchain.CurrentBlock()
6263
}
6364

65+
// Miner returns the miner instance.
66+
func (b *EthAPIBackend) Miner() *miner.Miner {
67+
return b.eth.Miner()
68+
}
69+
6470
func (b *EthAPIBackend) SetHead(number uint64) {
6571
b.eth.handler.downloader.Cancel()
6672
b.eth.blockchain.SetHead(number)

eth/backend.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"time"
2929

3030
"github.com/ethereum/go-ethereum/accounts"
31+
grpcapi "github.com/ethereum/go-ethereum/api/grpc"
3132
"github.com/ethereum/go-ethereum/common"
3233
"github.com/ethereum/go-ethereum/common/hexutil"
3334
"github.com/ethereum/go-ethereum/consensus"
@@ -121,6 +122,8 @@ type Ethereum struct {
121122

122123
p2pServer *p2p.Server
123124

125+
grpcService *grpcapi.Service // Low-latency gRPC API for trading operations
126+
124127
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
125128

126129
shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully
@@ -355,6 +358,13 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
355358
// Start the RPC service
356359
eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID)
357360

361+
// Initialize gRPC service if enabled
362+
if config.EnableGRPC {
363+
eth.grpcService = grpcapi.NewService(eth.APIBackend, config.GRPCHost, config.GRPCPort)
364+
stack.RegisterLifecycle(eth.grpcService)
365+
log.Info("gRPC service initialized", "host", config.GRPCHost, "port", config.GRPCPort)
366+
}
367+
358368
// Register the backend on the node
359369
stack.RegisterAPIs(eth.APIs())
360370
stack.RegisterProtocols(eth.Protocols())

eth/ethconfig/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ var Defaults = Config{
7272
RPCTxFeeCap: 1, // 1 ether
7373
TxSyncDefaultTimeout: 20 * time.Second,
7474
TxSyncMaxTimeout: 1 * time.Minute,
75+
EnableGRPC: false, // Disabled by default
76+
GRPCHost: "localhost",
77+
GRPCPort: 9090,
7578
}
7679

7780
//go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go
@@ -189,6 +192,11 @@ type Config struct {
189192
// EIP-7966: eth_sendRawTransactionSync timeouts
190193
TxSyncDefaultTimeout time.Duration `toml:",omitempty"`
191194
TxSyncMaxTimeout time.Duration `toml:",omitempty"`
195+
196+
// gRPC options for low-latency trading operations
197+
EnableGRPC bool // Whether to enable the gRPC server
198+
GRPCHost string // gRPC server host (default: localhost)
199+
GRPCPort int // gRPC server port (default: 9090)
192200
}
193201

194202
// CreateConsensusEngine creates a consensus engine for the given chain config.

roadmap.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Mandarin Roadmap
2+
3+
## Objective
4+
Transform Mandarin into a low-latency execution client optimized for co-located trading operations, targeting microsecond-scale improvements over standard Geth.
5+
6+
## Differentiation
7+
- **Erigon**: Database efficiency, archive node performance, disk I/O optimization
8+
- **Mandarin**: Real-time latency optimization for live trading and MEV operations
9+
10+
## Phase 1: Foundation (2-4 weeks)
11+
12+
### Custom Transaction Ordering
13+
- Modify `miner/worker.go` to accept external ordering functions
14+
- Add bundle support with revert protection
15+
- Export `OrderingStrategy` interface for pluggable algorithms
16+
- Risk: Low, isolated to block building
17+
18+
### Binary RPC Layer
19+
- Implement gRPC service in `api/grpc/`
20+
- Core endpoints: `GetStorageBatch`, `SimulateBundles`, `SubmitBundle`, `GetPendingTransactions`
21+
- Target: 10x latency improvement over JSON-RPC
22+
- Risk: Low, runs alongside existing RPC
23+
24+
### Benchmarking Framework
25+
- Establish baseline metrics vs vanilla Geth
26+
- Automated latency tracking: tx propagation, block import, simulation throughput, API latency
27+
- Continuous integration testing against mainnet replays
28+
29+
## Phase 2: Mempool Fast Path (4-6 weeks)
30+
31+
### Lock-Free Transaction Feed
32+
- Implement ring buffer in `core/txpool/fastfeed/`
33+
- Hook into txpool at `insertFeed.Send()` points
34+
- Binary layout for zero-copy access
35+
- Target: Sub-100μs tx propagation to consumers
36+
- Risk: Medium, touches critical path
37+
38+
### Shared Memory Interface
39+
- Expose transaction events via mmap'd regions
40+
- Selective filtering by contract address or method selector
41+
- Support multiple concurrent consumers
42+
- Risk: Medium, IPC complexity
43+
44+
## Phase 3: Hot State Cache (6-8 weeks)
45+
46+
### DeFi Contract State Pinning
47+
- Maintain in-memory cache of top 100 pool/vault states
48+
- Pre-decode reserves, fees, and critical parameters
49+
- Update atomically on block import
50+
- Target: Sub-microsecond state access for hot contracts
51+
- Risk: High, state consistency is critical
52+
53+
### State Delta Export
54+
- After each block, export structured diffs of watched addresses
55+
- Binary format for rapid consumption by trading strategies
56+
- Include pre and post-execution state
57+
- Risk: Medium
58+
59+
### Integration Points
60+
- `core/blockchain.go`: Hook into `ProcessBlock()`
61+
- `core/state_processor.go`: Intercept state changes during EVM execution
62+
- Deploy in shadow mode initially to verify correctness
63+
64+
## Phase 4: Native API (4-6 weeks)
65+
66+
### Shared Library Interface
67+
- Build Mandarin as `libmandarin.so` with C ABI
68+
- Export simulation, state access, and bundle submission functions
69+
- Enable in-process trading strategies
70+
- Target: Sub-100μs API calls
71+
- Risk: Medium, ABI stability and versioning concerns
72+
73+
### Safety Mechanisms
74+
- Process isolation boundaries
75+
- Memory protection
76+
- API rate limiting and resource quotas
77+
78+
## Key Metrics
79+
80+
### Target Improvements vs Baseline Geth
81+
- Transaction propagation (P99): 1.2ms → 45μs
82+
- Block import (avg): 120ms → 68ms
83+
- Simulation throughput: 200/sec → 15,000/sec
84+
- API latency (P50): 8ms → 12μs
85+
86+
### Monitoring
87+
- Real-time latency percentiles (P50, P99, P999)
88+
- Memory overhead tracking
89+
- State consistency validation
90+
- Regression detection in CI
91+
92+
## Out of Scope
93+
94+
### Not Prioritized
95+
- Full kernel-bypass networking (DPDK/AF_XDP): Complex, limited benefit
96+
- Custom P2P protocol: Breaks compatibility
97+
- Core EVM rewrites: High maintenance burden, modest gains
98+
99+
## Initial Validation
100+
101+
### Quick Wins (First 2 Weeks)
102+
1. Bundle simulation endpoint using existing `eth_call` infrastructure
103+
2. gRPC implementation for 5 critical APIs
104+
3. Benchmark suite comparing to vanilla Geth
105+
4. Publish latency improvements to validate approach
106+
107+
### Success Criteria
108+
- Measurable 5-10x latency improvements in Phase 1
109+
- Zero state consistency issues in hot cache
110+
- Production stability matching Geth reliability standards
111+

0 commit comments

Comments
 (0)