diff --git a/bench/rpc/run.js b/bench/rpc/run.js index 91fc5d432d..8a483f52b6 100644 --- a/bench/rpc/run.js +++ b/bench/rpc/run.js @@ -39,10 +39,15 @@ function isSuccess(res) { return Array.isArray(body) ? body.every(hasResult) : hasResult(body); } +// k6 sends no Accept-Encoding by default, so gzip must be opted into (-e GZIP=1). +// k6 transparently decompresses the response before isSuccess parses it. +const headers = { 'Content-Type': 'application/json' }; +if (__ENV.GZIP === '1') { + headers['Accept-Encoding'] = 'gzip'; +} + export default function measure() { const entry = corpus[exec.scenario.iterationInTest % corpus.length]; - const res = http.post(NODE_URL, JSON.stringify(entry), { - headers: { 'Content-Type': 'application/json' }, - }); + const res = http.post(NODE_URL, JSON.stringify(entry), { headers }); check(res, { 'rpc call ok': isSuccess }); } diff --git a/bench/rpc/throughput.js b/bench/rpc/throughput.js index 00b5f5fe82..c2013e94b7 100644 --- a/bench/rpc/throughput.js +++ b/bench/rpc/throughput.js @@ -2,12 +2,13 @@ import measure, { parseIntStrict } from './run.js'; const DURATION = __ENV.DURATION || '5s'; const RATES = (__ENV.RATES || '1000,2000,3000').split(',').map((r) => parseIntStrict(r.trim(), 'RATES')); +const VUS = __ENV.VUS ? parseIntStrict(__ENV.VUS, 'VUS') : Math.max(...RATES); export const options = { scenarios: { measure: { executor: 'ramping-arrival-rate', - preAllocatedVUs: Math.max(...RATES), + preAllocatedVUs: VUS, stages: RATES.map((target) => ({ target, duration: DURATION })), }, }, diff --git a/go.mod b/go.mod index 504f9835e5..fe5e1d805d 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/fxamacker/cbor/v2 v2.9.2 github.com/go-playground/validator/v10 v10.30.3 github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/klauspost/compress v1.19.1 github.com/klauspost/reedsolomon v1.14.1 github.com/libp2p/go-libp2p v0.48.0 github.com/libp2p/go-libp2p-kad-dht v0.42.1 @@ -100,7 +101,6 @@ require ( github.com/ipld/go-ipld-prime v0.24.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.19.1 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/koron/go-ssdp v0.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect diff --git a/jsonrpc/http.go b/jsonrpc/http.go index 9b0ea15fc4..4253d51ec0 100644 --- a/jsonrpc/http.go +++ b/jsonrpc/http.go @@ -124,7 +124,8 @@ func (h *HTTP) ServeHTTP(writer http.ResponseWriter, req *http.Request) { var ioWriter io.Writer = writer if strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") { writer.Header().Set("Content-Encoding", "gzip") - gw := compression.GzipWriter(writer) + // BestSpeed: ~10x faster than the default level for ~13% larger bodies. + gw := compression.GzipWriterLevel(writer, compression.BestSpeed) defer func() { closeErr := gw.Close() gw.Release() diff --git a/rpc/v10/transaction.go b/rpc/v10/transaction.go index 129995c452..76bca0e4b8 100644 --- a/rpc/v10/transaction.go +++ b/rpc/v10/transaction.go @@ -2,7 +2,6 @@ package rpcv10 import ( "bytes" - "compress/gzip" "context" "encoding/base64" "encoding/json" @@ -236,7 +235,7 @@ func ContractClassToGatewayPayload(class *ContractClass) ([]byte, error) { defer bufPool.Put(sierraBuf) b64 := base64.NewEncoder(base64.StdEncoding, sierraBuf) - gz := compression.GzipWriterLevel(b64, gzip.BestSpeed) + gz := compression.GzipWriterLevel(b64, compression.BestSpeed) defer gz.Release() enc := json.NewEncoder(gz) diff --git a/rpc/v10/transaction_test.go b/rpc/v10/transaction_test.go index 7724c2d659..99413af046 100644 --- a/rpc/v10/transaction_test.go +++ b/rpc/v10/transaction_test.go @@ -1332,7 +1332,7 @@ func TestAddTransaction(t *testing.T) { "account_deployment_data": [], "type": "DECLARE", "contract_class": { - "sierra_program": "H4sIAAAAAAAE/wADAPz/W10KAQAA//9E0mhwAwAAAA==", + "sierra_program": "H4sIAAAJbogE/wADAPz/W10KAwBE0mhwAwAAAA==", "contract_class_version": "0.1.0", "entry_points_by_type": { "CONSTRUCTOR": [], diff --git a/rpc/v8/transaction_test.go b/rpc/v8/transaction_test.go index 6258c45e97..b8e51eba7d 100644 --- a/rpc/v8/transaction_test.go +++ b/rpc/v8/transaction_test.go @@ -1120,7 +1120,7 @@ func TestAddTransaction(t *testing.T) { "nonce": "0x11", "class_hash": "0x7cb013a4139335cefce52adc2ac342c0110811353e7992baefbe547200223c7", "contract_class": { - "sierra_program": "H4sIAAAAAAAA/6quBQQAAP//Q7+mowIAAAA=" + "sierra_program": "H4sIAAAJbogA/wACAP3/e30DAEO/pqMCAAAA" }, "compiled_class_hash": "0x67f7deab53a3ba70500bdafe66fb3038bbbaadb36a6dd1a7a5fc5b094e9d724", "sender_address": "0x3bb81d22ecd0e0a6f3138bdc5c072ff5726c5add02bcfd5b81cd657a6ae10a8", @@ -1165,7 +1165,7 @@ func TestAddTransaction(t *testing.T) { "account_deployment_data": [], "type": "DECLARE", "contract_class": { - "sierra_program": "H4sIAAAAAAAA/6quBQQAAP//Q7+mowIAAAA=" + "sierra_program": "H4sIAAAJbogA/wACAP3/e30DAEO/pqMCAAAA" } }`, }, diff --git a/rpc/v9/transaction_test.go b/rpc/v9/transaction_test.go index 91421eb3ea..ccc632584e 100644 --- a/rpc/v9/transaction_test.go +++ b/rpc/v9/transaction_test.go @@ -1422,7 +1422,7 @@ func TestAddTransaction(t *testing.T) { "nonce": "0x11", "class_hash": "0x7cb013a4139335cefce52adc2ac342c0110811353e7992baefbe547200223c7", "contract_class": { - "sierra_program": "H4sIAAAAAAAA/6quBQQAAP//Q7+mowIAAAA=" + "sierra_program": "H4sIAAAJbogA/wACAP3/e30DAEO/pqMCAAAA" }, "compiled_class_hash": "0x67f7deab53a3ba70500bdafe66fb3038bbbaadb36a6dd1a7a5fc5b094e9d724", "sender_address": "0x3bb81d22ecd0e0a6f3138bdc5c072ff5726c5add02bcfd5b81cd657a6ae10a8", @@ -1469,7 +1469,7 @@ func TestAddTransaction(t *testing.T) { "account_deployment_data": [], "type": "DECLARE", "contract_class": { - "sierra_program": "H4sIAAAAAAAA/6quBQQAAP//Q7+mowIAAAA=" + "sierra_program": "H4sIAAAJbogA/wACAP3/e30DAEO/pqMCAAAA" } }`, }, diff --git a/utils/compression/compression.go b/utils/compression/compression.go index b2ddb182b5..6d6902bf2f 100644 --- a/utils/compression/compression.go +++ b/utils/compression/compression.go @@ -2,18 +2,28 @@ package compression import ( "bytes" - "compress/gzip" "encoding/base64" "errors" "fmt" "io" "sync" + + "github.com/klauspost/compress/gzip" +) + +// Gzip compression levels, re-exported so callers don't depend on the backing gzip implementation. +const ( + HuffmanOnly = gzip.HuffmanOnly + NoCompression = gzip.NoCompression + BestSpeed = gzip.BestSpeed + BestCompression = gzip.BestCompression + DefaultCompression = gzip.DefaultCompression ) // All gzip compression levels const ( - minLevel = gzip.HuffmanOnly - maxLevel = gzip.BestCompression + minLevel = HuffmanOnly + maxLevel = BestCompression levelCount = maxLevel - minLevel + 1 ) @@ -110,7 +120,7 @@ func (w *Writer) isAcquired() bool { // GzipWriter returns a gzip writer reset onto `dst`, compressing at the default // level. Once used, it should be sent back to the pool via `Release` func GzipWriter(dst io.Writer) *Writer { - return GzipWriterLevel(dst, gzip.DefaultCompression) + return GzipWriterLevel(dst, DefaultCompression) } // GzipWriterLevel returns a gzip writer reset onto `dst`, compressing at `level`. diff --git a/utils/compression/compression_test.go b/utils/compression/compression_test.go index d9d1d06671..4f865c07f4 100644 --- a/utils/compression/compression_test.go +++ b/utils/compression/compression_test.go @@ -2,7 +2,6 @@ package compression_test import ( "bytes" - "compress/gzip" "errors" "io" "runtime" @@ -12,13 +11,15 @@ import ( "weak" "github.com/NethermindEth/juno/utils/compression" + "github.com/klauspost/compress/gzip" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGzip64(t *testing.T) { bytes := []byte{0} - expectedComBytes := "H4sIAAAAAAAA/2IABAAA//+N7wLSAQAAAA==" + // klauspost writes uint32(zero time.Time) as MTIME, a fixed constant rather than 0. + expectedComBytes := "H4sIAAAJbogA/wABAP7/AAMAje8C0gEAAAA=" comBytes, err := compression.Gzip64Encode(bytes) require.NoError(t, err) assert.Equal(t, expectedComBytes, comBytes)