@@ -380,7 +380,7 @@ func (b *Backend) Forward(ctx context.Context, reqs []*RPCReq, isBatch bool) ([]
380380 "max_attempts" , b .maxRetries + 1 ,
381381 "method" , metricLabelMethod ,
382382 )
383- res , err := b .doForward (ctx , reqs , isBatch )
383+ res , err := b .doForward (ctx , reqs , isBatch , false )
384384 switch err {
385385 case nil : // do nothing
386386 case ErrBackendResponseTooLarge :
@@ -454,6 +454,10 @@ func (b *Backend) ProxyWS(clientConn *websocket.Conn, methodWhitelist *StringSet
454454
455455// ForwardRPC makes a call directly to a backend and populate the response into `res`
456456func (b * Backend ) ForwardRPC (ctx context.Context , res * RPCRes , id string , method string , params ... any ) error {
457+ return b .forwardRPC (ctx , false , res , id , method , params ... )
458+ }
459+
460+ func (b * Backend ) forwardRPC (ctx context.Context , isPoll bool , res * RPCRes , id string , method string , params ... any ) error {
457461 jsonParams , err := json .Marshal (params )
458462 if err != nil {
459463 return err
@@ -466,7 +470,7 @@ func (b *Backend) ForwardRPC(ctx context.Context, res *RPCRes, id string, method
466470 ID : []byte (id ),
467471 }
468472
469- slicedRes , err := b .doForward (ctx , []* RPCReq {& rpcReq }, false )
473+ slicedRes , err := b .doForward (ctx , []* RPCReq {& rpcReq }, false , isPoll )
470474 if err != nil {
471475 return err
472476 }
@@ -482,9 +486,19 @@ func (b *Backend) ForwardRPC(ctx context.Context, res *RPCRes, id string, method
482486 return nil
483487}
484488
485- func (b * Backend ) doForward (ctx context.Context , rpcReqs []* RPCReq , isBatch bool ) ([]* RPCRes , error ) {
489+ func (b * Backend ) doForward (ctx context.Context , rpcReqs []* RPCReq , isBatch , isPoll bool ) ([]* RPCRes , error ) {
486490 // we are concerned about network error rates, so we record 1 request independently of how many are in the batch
487- b .networkRequestsSlidingWindow .Incr ()
491+ // (we don't count polling towards error rates)
492+ if ! isPoll {
493+ b .networkRequestsSlidingWindow .Incr ()
494+ }
495+
496+ incrementError := func () {
497+ if ! isPoll {
498+ b .intermittentErrorsSlidingWindow .Incr ()
499+ }
500+ RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
501+ }
488502
489503 translatedReqs := make (map [string ]* RPCReq , len (rpcReqs ))
490504 // translate consensus_getReceipts to receipts target
@@ -552,8 +566,7 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
552566
553567 httpReq , err := http .NewRequestWithContext (ctx , "POST" , b .rpcURL , bytes .NewReader (body ))
554568 if err != nil {
555- b .intermittentErrorsSlidingWindow .Incr ()
556- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
569+ incrementError ()
557570 return nil , wrapErr (err , "error creating backend request" )
558571 }
559572
@@ -583,8 +596,7 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
583596 start := time .Now ()
584597 httpRes , err := b .client .DoLimited (httpReq )
585598 if err != nil {
586- b .intermittentErrorsSlidingWindow .Incr ()
587- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
599+ incrementError ()
588600 return nil , wrapErr (err , "error in backend request" )
589601 }
590602
@@ -602,8 +614,7 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
602614
603615 // Alchemy returns a 400 on bad JSONs, so handle that case
604616 if httpRes .StatusCode != 200 && httpRes .StatusCode != 400 {
605- b .intermittentErrorsSlidingWindow .Incr ()
606- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
617+ incrementError ()
607618 return nil , fmt .Errorf ("response code %d" , httpRes .StatusCode )
608619 }
609620
@@ -613,8 +624,7 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
613624 return nil , ErrBackendResponseTooLarge
614625 }
615626 if err != nil {
616- b .intermittentErrorsSlidingWindow .Incr ()
617- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
627+ incrementError ()
618628 return nil , wrapErr (err , "error reading response body" )
619629 }
620630
@@ -629,21 +639,17 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
629639 }
630640 } else {
631641 if err := json .Unmarshal (resB , & rpcRes ); err != nil {
642+ incrementError ()
632643 // Infura may return a single JSON-RPC response if, for example, the batch contains a request for an unsupported method
633644 if responseIsNotBatched (resB ) {
634- b .intermittentErrorsSlidingWindow .Incr ()
635- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
636645 return nil , ErrBackendUnexpectedJSONRPC
637646 }
638- b .intermittentErrorsSlidingWindow .Incr ()
639- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
640647 return nil , ErrBackendBadResponse
641648 }
642649 }
643650
644651 if len (rpcReqs ) != len (rpcRes ) {
645- b .intermittentErrorsSlidingWindow .Incr ()
646- RecordBackendNetworkErrorRateSlidingWindow (b , b .ErrorRate ())
652+ incrementError ()
647653 return nil , ErrBackendUnexpectedJSONRPC
648654 }
649655
0 commit comments