1313import org .bouncycastle .crypto .params .ECPrivateKeyParameters ;
1414import org .bouncycastle .crypto .params .ECPublicKeyParameters ;
1515import org .bouncycastle .crypto .signers .ECDSASigner ;
16+ import org .junit .Assume ;
17+ import org .junit .Before ;
1618import org .junit .Test ;
1719import org .tron .common .crypto .ECKey ;
1820import org .tron .common .crypto .ECKey .ECDSASignature ;
2224/**
2325 * Manual microbenchmarks comparing the ECRecover (3000 gas) precompile
2426 * against the new P256VERIFY (6900 gas) precompile from TIP-7951. Not part
25- * of the regular test suite — invoke explicitly :
27+ * of the regular test suite. It is opt-in behind a system property :
2628 *
27- * ./gradlew :framework:test --tests \
29+ * ./gradlew :framework:test -DrunPrecompileBenchmark=true - -tests \
2830 * org.tron.common.runtime.vm.PrecompileBenchmark -i
2931 *
3032 * Four @Test methods, each independent:
3335 * returns short-circuit before ECDSA math.
3436 * - compareDiverseInputs: rotates over N distinct keypairs to defeat
3537 * any per-key caching and branch-predictor bias.
36- * - coldNoWarmup: no warmup, distinct input each call, first
38+ * - coldNoWarmup: no execute() warmup, distinct input each call, first
3739 * 100 calls bucketed — closer to the mainnet
3840 * case where P256VERIFY is invoked rarely and
3941 * the JVM has not JIT-compiled the path yet.
4042 *
4143 * Single-threaded, pure-Java BouncyCastle path. The first three tests use a
42- * 5000-iteration JIT warmup; coldNoWarmup deliberately skips it.
44+ * 5000-iteration execute() warmup; coldNoWarmup deliberately skips it. Test
45+ * input generation happens before timing and may load cryptographic helper code.
4346 */
4447public class PrecompileBenchmark {
4548
49+ private static final String RUN_PROPERTY = "runPrecompileBenchmark" ;
4650 private static final int WARMUP_ITERS = 5_000 ;
4751 private static final int MEASURE_ITERS = 5_000 ;
4852 private static final int ROUNDS = 5 ;
@@ -53,6 +57,12 @@ public class PrecompileBenchmark {
5357 private static final PrecompiledContracts .P256Verify P256_VERIFY =
5458 new PrecompiledContracts .P256Verify ();
5559
60+ @ Before
61+ public void requireExplicitOptIn () {
62+ Assume .assumeTrue ("set -D" + RUN_PROPERTY + "=true to run manual benchmarks" ,
63+ Boolean .getBoolean (RUN_PROPERTY ));
64+ }
65+
5666 // First entry from go-ethereum's EIP-7951 conformance vectors — known-valid.
5767 private static final String VALID_P256_INPUT =
5868 "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4d"
@@ -358,19 +368,20 @@ private static byte[] deterministicHash(int seed) {
358368 /** ============================== TEST 4 ============================== */
359369
360370 /**
361- * Cold no-warmup measurement. Skips the {@code WARMUP_ITERS} prelude so the
362- * first call pays full JIT/classloading tax — closer to the TRON mainnet
363- * scenario where P256VERIFY is invoked at low frequency and the precompile
364- * path rarely reaches C2 steady state.
371+ * Cold no-warmup measurement. Skips the {@code WARMUP_ITERS} execute()
372+ * prelude so the first measured precompile call sees an unprimed execute path
373+ * — closer to the TRON mainnet scenario where P256VERIFY is invoked at low
374+ * frequency and the precompile path rarely reaches C2 steady state.
365375 *
366376 * <p>Reports the first call alone plus bucketed averages over the first 100
367377 * calls so the JIT promotion curve is visible. Each call uses a distinct
368- * input (fresh keypair / signature) to defeat any per-input caching. P256 is
369- * timed first so the precompile path is genuinely cold.
378+ * input (fresh keypair / signature) to defeat any per-input caching. Inputs
379+ * are generated before timing, so this does not measure cryptographic helper
380+ * classloading performed by key generation.
370381 *
371- * <p>For a fully cold measurement, run this test alone in a fresh JVM:
382+ * <p>For the coldest execute() measurement, run this test alone in a fresh JVM:
372383 *
373- * ./gradlew :framework:test --no-daemon --tests \
384+ * ./gradlew :framework:test --no-daemon -DrunPrecompileBenchmark=true - -tests \
374385 * 'org.tron.common.runtime.vm.PrecompileBenchmark.coldNoWarmup' -i
375386 *
376387 * Otherwise the other @Test methods running first will already have
0 commit comments