Skip to content

Commit af8b5aa

Browse files
authored
Merge pull request #2576 from ledgerwatch/stable-2021-08-05-2
Stable 2021 08 04
2 parents be4d3f4 + b1f72ca commit af8b5aa

File tree

27 files changed

+310
-218
lines changed

27 files changed

+310
-218
lines changed

README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,42 @@ FAQ
257257

258258
Detailed explanation: [./docs/programmers_guide/db_faq.md](./docs/programmers_guide/db_faq.md)
259259

260+
### Default Ports and Protocols / Firewalls?
261+
262+
#### `erigon` ports
263+
| Port | Protocol | Purpose | Expose |
264+
|:-----:|:---------:|:----------------:|:-------:|
265+
| 30303 | TCP & UDP | eth/66 peering | Public |
266+
| 30304 | TCP & UDP | eth/65 peering | Public |
267+
| 9090 | TCP | gRPC Connections | Private |
268+
269+
Typically 30303 and 30304 are exposed to the internet to allow incoming peering connections. 9090 is exposed only internally for rpcdaemon or other connections, (e.g. rpcdaemon -> erigon)
270+
271+
#### `rpcdaemon` ports
272+
| Port | Protocol | Purpose | Expose |
273+
|:-----:|:---------:|:-----------------:|:-------:|
274+
| 8545 | TCP | HTTP & WebSockets | Private |
275+
276+
Typically 8545 is exposed only interally for JSON-RPC queries. Both HTTP and WebSocket connections are on the same port.
277+
278+
#### `sentry` ports
279+
| Port | Protocol | Purpose | Expose |
280+
|:-----:|:---------:|:----------------:|:-------:|
281+
| 30303 | TCP & UDP | Peering | Public |
282+
| 9091 | TCP | gRPC Connections | Private |
283+
284+
Typically a sentry process will run one eth/xx protocl (e.g. eth/66) and will be exposed to the internet on 30303. Port 9091 is for internal gRCP connections (e.g erigon -> sentry)
285+
286+
#### Other ports
287+
| Port | Protocol | Purpose | Expose |
288+
|:----:|:--------:|:-------:|:-------:|
289+
| 6060 | TCP | pprof | Private |
290+
| 6060 | TCP | metrics | Private |
291+
292+
Optional flags can be enabled that enable pprof or metrics (or both) - however, they both run on 6060 by default, so you'll have to change one if you want to run both at the same time. use `--help` with the binary for more info.
293+
294+
Also, ports 9092 and 9093 are reserved for future use of the consensus engine and shapshot downloader for gRPC (work in progress).
295+
260296
Getting in touch
261297
================
262298

@@ -346,4 +382,3 @@ non-batched way.
346382
### Filesystem's background features are expensive
347383

348384
For example: btrfs's autodefrag option - may increase write IO 100x times
349-

cmd/rpcdaemon/cli/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func RootCommand() (*cobra.Command, *Flags) {
8585
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpVirtualHost, "http.vhosts", node.DefaultConfig.HTTPVirtualHosts, "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.")
8686
rootCmd.PersistentFlags().BoolVar(&cfg.HttpCompression, "http.compression", true, "Disable http compression")
8787
rootCmd.PersistentFlags().StringSliceVar(&cfg.API, "http.api", []string{"eth", "erigon"}, "API's offered over the HTTP-RPC interface: eth,erigon,web3,net,debug,trace,txpool,shh,db. Supported methods: https://github.com/ledgerwatch/erigon/tree/devel/cmd/rpcdaemon")
88-
rootCmd.PersistentFlags().Uint64Var(&cfg.Gascap, "rpc.gascap", 25000000, "Sets a cap on gas that can be used in eth_call/estimateGas")
88+
rootCmd.PersistentFlags().Uint64Var(&cfg.Gascap, "rpc.gascap", 50000000, "Sets a cap on gas that can be used in eth_call/estimateGas")
8989
rootCmd.PersistentFlags().Uint64Var(&cfg.MaxTraces, "trace.maxtraces", 200, "Sets a limit on traces that can be returned in trace_filter")
9090
rootCmd.PersistentFlags().BoolVar(&cfg.WebsocketEnabled, "ws", false, "Enable Websockets")
9191
rootCmd.PersistentFlags().BoolVar(&cfg.WebsocketCompression, "ws.compression", false, "Enable Websocket compression (RFC 7692)")

cmd/rpcdaemon/commands/call_traces_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ func TestCallTraceOneByOne(t *testing.T) {
5151
t.Fatalf("inserting chain: %v", err)
5252
}
5353
}
54-
var buf bytes.Buffer
55-
stream := jsoniter.NewStream(jsoniter.ConfigDefault, &buf, 4096)
54+
stream := jsoniter.ConfigDefault.BorrowStream(nil)
55+
defer jsoniter.ConfigDefault.ReturnStream(stream)
5656
var fromBlock, toBlock uint64
5757
fromBlock = 1
5858
toBlock = 10
@@ -65,7 +65,7 @@ func TestCallTraceOneByOne(t *testing.T) {
6565
if err = api.Filter(context.Background(), traceReq1, stream); err != nil {
6666
t.Fatalf("trace_filter failed: %v", err)
6767
}
68-
assert.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, blockNumbersFromTraces(t, buf.Bytes()))
68+
assert.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, blockNumbersFromTraces(t, stream.Buffer()))
6969
}
7070

7171
func TestCallTraceUnwind(t *testing.T) {

cmd/rpcdaemon/commands/erigon_block.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ func (api *ErigonImpl) GetHeaderByNumber(ctx context.Context, blockNumber rpc.Bl
2727
}
2828
defer tx.Rollback()
2929

30-
header := rawdb.ReadHeaderByNumber(tx, uint64(blockNumber.Int64()))
30+
blockNum, err := getBlockNumber(blockNumber, tx)
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
header := rawdb.ReadHeaderByNumber(tx, blockNum)
3136
if header == nil {
32-
return nil, fmt.Errorf("block header not found: %d", blockNumber.Int64())
37+
return nil, fmt.Errorf("block header not found: %d", blockNum)
3338
}
3439

3540
return header, nil

cmd/rpcdaemon/commands/trace_filtering.go

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,10 @@ func (api *TraceAPIImpl) Filter(ctx context.Context, req TraceFilterRequest, str
265265
stream.WriteNil()
266266
return err
267267
}
268-
var json = jsoniter.ConfigCompatibleWithStandardLibrary
268+
269+
var stdlibCompatibleJson = jsoniter.ConfigCompatibleWithStandardLibrary.BorrowStream(stream)
270+
defer jsoniter.ConfigCompatibleWithStandardLibrary.ReturnStream(stdlibCompatibleJson)
271+
269272
stream.WriteArrayStart()
270273
first := true
271274
// Execute all transactions in picked blocks
@@ -321,18 +324,14 @@ func (api *TraceAPIImpl) Filter(ctx context.Context, req TraceFilterRequest, str
321324
pt.BlockNumber = &blockNumber
322325
pt.TransactionHash = &txHash
323326
pt.TransactionPosition = &txPosition
324-
b, err := json.Marshal(pt)
325-
if err != nil {
326-
stream.WriteNil()
327-
return err
328-
}
329327
if nSeen > after && nExported < count {
330328
if first {
331329
first = false
332330
} else {
333331
stream.WriteMore()
334332
}
335-
stream.Write(b)
333+
stdlibCompatibleJson.WriteVal(pt)
334+
stdlibCompatibleJson.Flush()
336335
nExported++
337336
}
338337
}
@@ -353,18 +352,14 @@ func (api *TraceAPIImpl) Filter(ctx context.Context, req TraceFilterRequest, str
353352
*tr.BlockNumber = block.NumberU64()
354353
tr.Type = "reward" // nolint: goconst
355354
tr.TraceAddress = []int{}
356-
b, err := json.Marshal(tr)
357-
if err != nil {
358-
stream.WriteNil()
359-
return err
360-
}
361355
if nSeen > after && nExported < count {
362356
if first {
363357
first = false
364358
} else {
365359
stream.WriteMore()
366360
}
367-
stream.Write(b)
361+
stdlibCompatibleJson.WriteVal(tr)
362+
stdlibCompatibleJson.Flush()
368363
nExported++
369364
}
370365
}
@@ -384,18 +379,14 @@ func (api *TraceAPIImpl) Filter(ctx context.Context, req TraceFilterRequest, str
384379
*tr.BlockNumber = block.NumberU64()
385380
tr.Type = "reward" // nolint: goconst
386381
tr.TraceAddress = []int{}
387-
b, err := json.Marshal(tr)
388-
if err != nil {
389-
stream.WriteNil()
390-
return err
391-
}
392382
if nSeen > after && nExported < count {
393383
if first {
394384
first = false
395385
} else {
396386
stream.WriteMore()
397387
}
398-
stream.Write(b)
388+
stdlibCompatibleJson.WriteVal(tr)
389+
stdlibCompatibleJson.Flush()
399390
nExported++
400391
}
401392
}

cmd/sentry/download/downloader.go

Lines changed: 110 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,99 @@ import (
3535
"google.golang.org/protobuf/types/known/emptypb"
3636
)
3737

38-
// Methods of Core called by sentry
38+
// 3 streams:
39+
// RecvMessage - processing incoming headers/bodies
40+
// RecvUploadHeadersMessage - sending headers - dedicated stream because headers propagation speed important for network health
41+
// RecvUploadMessage - sending bodies/receipts - may be heavy, it's ok to not process this messages enough fast, it's also ok to drop some of this messages if can't process.
3942

40-
func GrpcSentryClient(ctx context.Context, sentryAddr string) (*direct.SentryClientRemote, error) {
41-
// creating grpc client connection
42-
var dialOpts []grpc.DialOption
43+
func RecvUploadMessageLoop(ctx context.Context,
44+
sentry direct.SentryClient,
45+
cs *ControlServerImpl,
46+
wg *sync.WaitGroup,
47+
) {
48+
for {
49+
select {
50+
case <-ctx.Done():
51+
return
52+
default:
53+
}
4354

44-
backoffCfg := backoff.DefaultConfig
45-
backoffCfg.BaseDelay = 500 * time.Millisecond
46-
backoffCfg.MaxDelay = 10 * time.Second
47-
dialOpts = []grpc.DialOption{
48-
grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoffCfg, MinConnectTimeout: 10 * time.Minute}),
49-
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(16 * datasize.MB))),
50-
grpc.WithKeepaliveParams(keepalive.ClientParameters{}),
55+
if _, err := sentry.HandShake(ctx, &emptypb.Empty{}, grpc.WaitForReady(true)); err != nil {
56+
s, ok := status.FromError(err)
57+
doLog := !((ok && s.Code() == codes.Canceled) || errors.Is(err, io.EOF) || errors.Is(err, context.Canceled))
58+
if doLog {
59+
log.Warn("[RecvUploadMessage] sentry not ready yet", "err", err)
60+
}
61+
time.Sleep(time.Second)
62+
continue
63+
}
64+
if err := SentrySetStatus(ctx, sentry, cs); err != nil {
65+
s, ok := status.FromError(err)
66+
doLog := !((ok && s.Code() == codes.Canceled) || errors.Is(err, io.EOF) || errors.Is(err, context.Canceled))
67+
if doLog {
68+
log.Warn("[RecvUploadMessage] sentry not ready yet", "err", err)
69+
}
70+
time.Sleep(time.Second)
71+
continue
72+
}
73+
if err := RecvUploadMessage(ctx, sentry, cs.HandleInboundMessage, wg); err != nil {
74+
if isPeerNotFoundErr(err) {
75+
continue
76+
}
77+
s, ok := status.FromError(err)
78+
if (ok && s.Code() == codes.Canceled) || errors.Is(err, io.EOF) || errors.Is(err, context.Canceled) {
79+
time.Sleep(time.Second)
80+
continue
81+
}
82+
log.Warn("[RecvUploadMessage]", "err", err)
83+
continue
84+
}
5185
}
86+
}
5287

53-
dialOpts = append(dialOpts, grpc.WithInsecure())
54-
conn, err := grpc.DialContext(ctx, sentryAddr, dialOpts...)
88+
func RecvUploadMessage(ctx context.Context,
89+
sentry direct.SentryClient,
90+
handleInboundMessage func(ctx context.Context, inreq *proto_sentry.InboundMessage, sentry direct.SentryClient) error,
91+
wg *sync.WaitGroup,
92+
) (err error) {
93+
defer func() { err = debug2.ReportPanicAndRecover(err) }() // avoid crash because Erigon's core does many things
94+
streamCtx, cancel := context.WithCancel(ctx)
95+
defer cancel()
96+
97+
stream, err := sentry.Messages(streamCtx, &proto_sentry.MessagesRequest{Ids: []proto_sentry.MessageId{
98+
eth.ToProto[eth.ETH65][eth.GetBlockBodiesMsg],
99+
eth.ToProto[eth.ETH65][eth.GetReceiptsMsg],
100+
101+
eth.ToProto[eth.ETH66][eth.GetBlockBodiesMsg],
102+
eth.ToProto[eth.ETH66][eth.GetReceiptsMsg],
103+
}}, grpc.WaitForReady(true))
55104
if err != nil {
56-
return nil, fmt.Errorf("creating client connection to sentry P2P: %w", err)
105+
return err
106+
}
107+
var req *proto_sentry.InboundMessage
108+
for req, err = stream.Recv(); ; req, err = stream.Recv() {
109+
if err != nil {
110+
select {
111+
case <-ctx.Done():
112+
return
113+
default:
114+
}
115+
return err
116+
}
117+
if req == nil {
118+
return
119+
}
120+
if err = handleInboundMessage(ctx, req, sentry); err != nil {
121+
log.Error("RecvUploadMessage: Handling incoming message", "error", err)
122+
}
123+
if wg != nil {
124+
wg.Done()
125+
}
126+
57127
}
58-
return direct.NewSentryClientRemote(proto_sentry.NewSentryClient(conn)), nil
59128
}
60129

61-
func RecvUploadMessageLoop(ctx context.Context,
130+
func RecvUploadHeadersMessageLoop(ctx context.Context,
62131
sentry direct.SentryClient,
63132
cs *ControlServerImpl,
64133
wg *sync.WaitGroup,
@@ -88,7 +157,7 @@ func RecvUploadMessageLoop(ctx context.Context,
88157
time.Sleep(time.Second)
89158
continue
90159
}
91-
if err := RecvUploadMessage(ctx, sentry, cs.HandleInboundMessage, wg); err != nil {
160+
if err := RecvUploadHeadersMessage(ctx, sentry, cs.HandleInboundMessage, wg); err != nil {
92161
if isPeerNotFoundErr(err) {
93162
continue
94163
}
@@ -103,7 +172,7 @@ func RecvUploadMessageLoop(ctx context.Context,
103172
}
104173
}
105174

106-
func RecvUploadMessage(ctx context.Context,
175+
func RecvUploadHeadersMessage(ctx context.Context,
107176
sentry direct.SentryClient,
108177
handleInboundMessage func(ctx context.Context, inreq *proto_sentry.InboundMessage, sentry direct.SentryClient) error,
109178
wg *sync.WaitGroup,
@@ -114,12 +183,8 @@ func RecvUploadMessage(ctx context.Context,
114183

115184
stream, err := sentry.Messages(streamCtx, &proto_sentry.MessagesRequest{Ids: []proto_sentry.MessageId{
116185
eth.ToProto[eth.ETH65][eth.GetBlockHeadersMsg],
117-
eth.ToProto[eth.ETH65][eth.GetBlockBodiesMsg],
118-
eth.ToProto[eth.ETH65][eth.GetReceiptsMsg],
119186

120187
eth.ToProto[eth.ETH66][eth.GetBlockHeadersMsg],
121-
eth.ToProto[eth.ETH66][eth.GetBlockBodiesMsg],
122-
eth.ToProto[eth.ETH66][eth.GetReceiptsMsg],
123188
}}, grpc.WaitForReady(true))
124189
if err != nil {
125190
return err
@@ -910,3 +975,26 @@ func makeStatusData(s *ControlServerImpl) *proto_sentry.StatusData {
910975
},
911976
}
912977
}
978+
979+
// Methods of Core called by sentry
980+
981+
func GrpcSentryClient(ctx context.Context, sentryAddr string) (*direct.SentryClientRemote, error) {
982+
// creating grpc client connection
983+
var dialOpts []grpc.DialOption
984+
985+
backoffCfg := backoff.DefaultConfig
986+
backoffCfg.BaseDelay = 500 * time.Millisecond
987+
backoffCfg.MaxDelay = 10 * time.Second
988+
dialOpts = []grpc.DialOption{
989+
grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoffCfg, MinConnectTimeout: 10 * time.Minute}),
990+
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(16 * datasize.MB))),
991+
grpc.WithKeepaliveParams(keepalive.ClientParameters{}),
992+
}
993+
994+
dialOpts = append(dialOpts, grpc.WithInsecure())
995+
conn, err := grpc.DialContext(ctx, sentryAddr, dialOpts...)
996+
if err != nil {
997+
return nil, fmt.Errorf("creating client connection to sentry P2P: %w", err)
998+
}
999+
return direct.NewSentryClientRemote(proto_sentry.NewSentryClient(conn)), nil
1000+
}

0 commit comments

Comments
 (0)