fix(mev): stop the backrunme sender silently forcing HTTP/1.1 - #222
Merged
Conversation
NewBloxrouteBackrunmeSender built its Transport from scratch and gave it a TLSClientConfig for InsecureSkipVerify, mirroring the `curl --insecure` in bloxroute's docs. net/http only negotiates HTTP/2 when it may append "h2" to TLSClientConfig.NextProtos, and Transport.protocols refuses to touch a caller-supplied config unless ForceAttemptHTTP2 is set (Go issue 14275). That single field pinned every submit to HTTP/1.1, where the default MaxIdleConnsPerHost of 2 costs a fresh TCP+TLS handshake per concurrent submit past the second. Measured peak on this endpoint is 54 req/s. backrunme.blxrbdn.com serves h2 under normal certificate verification, so the skip bought nothing and cost both the protocol and MITM protection -- which matters here because the payload is a signed bundle. Cloning the stdlib default also restores IdleConnTimeout (a zero-value Transport never expires idle conns), Proxy, and the dial timeout and keepalive, none of which the hand-built Transport had. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QZ2nnbqg3wa9rTMFaPEZzm
thanhpp
approved these changes
Aug 27, 2026
vaigay
approved these changes
Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Vấn đề
NewBloxrouteBackrunmeSendertự dựngTransporttừ đầu và gán cho nó mộtTLSClientConfigđể bậtInsecureSkipVerify, chép theocurl --insecuretrong docs bloxroute:Đúng một field đó âm thầm ép mọi submit về HTTP/1.1. Luật nằm ở
Transport.protocols()trongnet/http:Lý do: để negotiate h2, Go phải sửa
tls.Configcủa bạn — chèn"h2"vàoNextProtos(xemhttp2configureTransports). Nó từ chối làm vậy với config do caller cung cấp, trừ khiForceAttemptHTTP2được set. Đây là quyết định có chủ đích của stdlib (Go issue 14275), không phải bug — nhưng hệ quả thì hoàn toàn im lặng.Vì sao đáng sửa: trên h2 một connection multiplex hàng trăm stream nên
MaxIdleConnsPerHostgần như vô nghĩa. Trên h1 thì mặc định của Go là 2 (field hiện0, map sang hằnghttp.DefaultMaxIdleConnsPerHost), nên mỗi request đồng thời từ thứ 3 trở đi phải bắt tay TCP+TLS lại. Peak đo được ở endpoint này là 54 req/s.Và
InsecureSkipVerifylà thừa —backrunme.blxrbdn.comphục vụ h2 bình thường với xác thực cert đầy đủ:Nên nó không mua được gì, mà mất cả giao thức lẫn chống MITM — đáng lưu ý vì payload ở đây là bundle đã ký.
Sửa
Clone default của stdlib thay vì dựng
Transporttừ đầu. Mộthttp.Transportzero-value còn mất thêm:ForceAttemptHTTP2IdleConnTimeoutMaxIdleConnsProxyProxyFromEnvironmentIdleConnTimeout = 0đáng ngại riêng: conn rảnh nằm mãi chờ server đóng, và Go chỉ phát hiện lúc dùng lại — thường biểu hiện thành lỗiEOFlác đác.Test
TestBackrunmeSenderNegotiatesHTTP2dựnghttptestserver cóEnableHTTP2, cho chính transport của sender gửi request, rồi assertr.Proto == "HTTP/2.0"ở phía server.Chi tiết quan trọng: test chỉ thêm
RootCAsđể tin cert tự ký, không thaysender.httpClientbằngsrv.Client(). Bản nháp đầu tôi làm thế và test thành vacuous — nó kiểm transport của httptest chứ không phải của constructor, nên pass bất kể constructor làm gì.Mutation-check: hoàn nguyên về transport cũ thì test fail đúng ở hành vi quan sát được, không phải ở proxy cấu trúc —
go build ./...sạch,go test ./pkg/mev/...pass.golangci-lint run ./pkg/mev/...trở về đúng baseline củamain(7 issue có sẵn: gosec 1, modernize 6) — thay đổi này không thêm issue nào.Phạm vi
Chỉ đụng
NewBloxrouteBackrunmeSender. Signature giữ nguyên vì tradinglib được nhiều repo dùng chung.NewMevShareSendercó vấn đề họ hàng — nó đi quamev-share-go/rpc.NewClient, cái này hardcode&http.Client{}và không có điểm inject. Nhưng nó không hỏng:&http.Client{}cóTransportnil nên rơi vềhttp.DefaultTransport, vốn đãForceAttemptHTTP2: true→ vẫn h2. Sửa nó cần đụng dependency ngoài mà không giải quyết bug nào đang tồn tại, nên để riêng.🤖 Generated with Claude Code