@@ -46,7 +46,7 @@ export class Connector<
4646{
4747 #provider: EthereumProvider ;
4848
49- static BUFFERIFY_THRESHOLD : number = 100000 ;
49+ static BUFFERIFY_THRESHOLD : number = 30000 ;
5050
5151 get provider ( ) {
5252 return this . #provider;
@@ -130,29 +130,50 @@ export class Connector<
130130 if (
131131 payload . method === "debug_traceTransaction" &&
132132 typeof results === "object" &&
133- Array . isArray ( results . structLogs ) &&
134- // for "large" debug_traceTransaction results we convert to individual
135- // parts of the response to Buffers, yielded via a Generator function,
136- // instead of using JSON.stringify. This is necessary because we:
137- // * avoid V8's maximum string length limit of 1GB
138- // * avoid and the max Buffer length limit of ~2GB (on 64bit
139- // architectures).
140- // * avoid heap allocation failures due to trying to hold too much
141- // data in memory (which can happen if we don't immediately consume
142- // the `format` result -- by buffering everything into one array,
143- // for example)
144- //
145- // We don't do this for everything because the bufferfication is so very
146- // very slow.
147- //
148- // TODO(perf): an even better way of solving this would be to convert
149- // `debug_traceTransaction` to a generator that yields chunks (of
150- // Buffer) as soon as they're available. We could then `write` these
151- // individual chunks immediately and our memory use would stay
152- // relatively low and constant.
153- results . structLogs . length > this . BUFFERIFY_THRESHOLD
133+ Array . isArray ( results . structLogs )
154134 ) {
155- return bufferify ( json , "" ) ;
135+ if (
136+ // for "large" debug_traceTransaction results we convert to individual
137+ // parts of the response to Buffers, yielded via a Generator function,
138+ // instead of using JSON.stringify. This is necessary because we:
139+ // * avoid V8's maximum string length limit of 1GB
140+ // * avoid and the max Buffer length limit of ~2GB (on 64bit
141+ // architectures).
142+ // * avoid heap allocation failures due to trying to hold too much
143+ // data in memory (which can happen if we don't immediately consume
144+ // the `format` result -- by buffering everything into one array,
145+ // for example)
146+ //
147+ // We don't do this for everything because the bufferfication is so very
148+ // very slow.
149+ //
150+ // TODO(perf): an even better way of solving this would be to convert
151+ // `debug_traceTransaction` to a generator that yields chunks (of
152+ // Buffer) as soon as they're available. We could then `write` these
153+ // individual chunks immediately and our memory use would stay
154+ // relatively low and constant.
155+ results . structLogs . length > this . BUFFERIFY_THRESHOLD
156+ ) {
157+ return bufferify ( json , "" ) ;
158+ } else {
159+ try {
160+ // struct logs that are under the BUFFERIFY_THRESHOLD can still
161+ // cause stringification to fail, so we need to try/catch this
162+ // and fall back to `bufferify` if it does.
163+ // We don't go straight to `bufferify` because it's much slower than
164+ // `JSON.stringify`.
165+ return JSON . stringify ( json ) ;
166+ } catch ( e ) {
167+ if (
168+ e instanceof RangeError &&
169+ e . message === "Invalid string length"
170+ ) {
171+ return bufferify ( json , "" ) ;
172+ } else {
173+ throw e ;
174+ }
175+ }
176+ }
156177 } else {
157178 return JSON . stringify ( json ) ;
158179 }
0 commit comments