test(builder): close PR-9 review debt - datum-kind pin, empty-string datum/redeemer, boundary scans scripts/
This commit is contained in:
@@ -12,6 +12,7 @@ import { resolve, join, relative } from 'node:path';
|
||||
* non-custodial split; growing it should be impossible to do accidentally.
|
||||
*/
|
||||
const SRC_ROOT = resolve(import.meta.dirname!, '../src');
|
||||
const SCRIPTS_ROOT = resolve(import.meta.dirname!, '../scripts');
|
||||
const CUSTODIAL_UNTIL_LATER_PR = new Set([
|
||||
'vector/agent-network.ts', // family 2 — goes keyless in spec PR 7
|
||||
'vector/self-improvement.ts', // family 3 — goes keyless in spec PR 8
|
||||
@@ -46,6 +47,16 @@ describe('builder custody boundary', () => {
|
||||
if (FORBIDDEN.test(line)) offenders.push(`${rel}:${i + 1}: ${line.trim()}`);
|
||||
});
|
||||
}
|
||||
// scripts/ is dev-tooling, not shipped builder source - it has no
|
||||
// custodial carve-out, so nothing here is ever checked against the
|
||||
// allowlist (unlike SRC_ROOT files above).
|
||||
for (const file of sourceFiles(SCRIPTS_ROOT)) {
|
||||
const rel = relative(SCRIPTS_ROOT, file).replace(/\\/g, '/');
|
||||
const lines = readFileSync(file, 'utf-8').split('\n');
|
||||
lines.forEach((line, i) => {
|
||||
if (FORBIDDEN.test(line)) offenders.push(`scripts/${rel}:${i + 1}: ${line.trim()}`);
|
||||
});
|
||||
}
|
||||
assert.deepEqual(offenders, [], `key-material vocabulary found in keyless builder source:\n${offenders.join('\n')}`);
|
||||
});
|
||||
|
||||
|
||||
@@ -66,6 +66,14 @@ describe('buildDeployContract', () => {
|
||||
const vkeys = CML.Transaction.from_cbor_hex(r.txCbor).witness_set().vkeywitnesses();
|
||||
assert.ok(vkeys === undefined || vkeys.len() === 0);
|
||||
});
|
||||
|
||||
test("deploy with initialDatum '' fails loudly instead of silently voiding", async () => {
|
||||
// '' is falsy but caller-supplied; ?? must let it flow through and fail
|
||||
// loudly downstream rather than defaulting to Data.void().
|
||||
await assert.rejects(buildDeployContract(lucid, {
|
||||
scriptCbor: ALWAYS_SUCCEEDS_V2, scriptType: 'PlutusV2', initialDatum: '',
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildInteractContract', () => {
|
||||
@@ -89,6 +97,24 @@ describe('buildInteractContract', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
test('lock datum is inline (kind), not a hash reference', async () => {
|
||||
const r = await buildInteractContract(lucid, {
|
||||
scriptCbor: ALWAYS_SUCCEEDS_V2, scriptType: 'PlutusV2', action: 'lock',
|
||||
changeAddress: OWN_ADDRESS, lovelaceAmount: 2_000_000, datum: 'd87980',
|
||||
});
|
||||
const tx = CML.Transaction.from_cbor_hex(r.txCbor);
|
||||
const outs = tx.body().outputs();
|
||||
let inlineSeen = false;
|
||||
for (let i = 0; i < outs.len(); i++) {
|
||||
const d = outs.get(i).datum();
|
||||
// CML DatumOptionKind: Hash = 0, Datum = 1 (verified against the
|
||||
// package's own .d.ts) - kind() === 1 is an inline datum.
|
||||
if (d && d.kind() === 1) inlineSeen = true;
|
||||
if (d && d.kind() === 0) assert.fail('lock produced a datum HASH output - must be inline');
|
||||
}
|
||||
assert.ok(inlineSeen, 'no inline-datum output found on the lock tx');
|
||||
});
|
||||
|
||||
test('rejects an invalid action', async () => {
|
||||
await assert.rejects(
|
||||
() => buildInteractContract(lucid, {
|
||||
@@ -172,4 +198,19 @@ describe('buildInteractContract', () => {
|
||||
/not at script address/,
|
||||
);
|
||||
});
|
||||
|
||||
test("spend: rejects an empty-string redeemer instead of silently treating it as void", async () => {
|
||||
// '' is falsy but caller-supplied; ?? must let it flow through and fail
|
||||
// loudly downstream rather than defaulting to Data.void().
|
||||
const scriptUtxo: UTxO = {
|
||||
txHash: FIXTURE_TXHASH, outputIndex: 7, address: SCRIPT_ADDRESS,
|
||||
assets: { lovelace: 2_000_000n }, datum: 'd87980',
|
||||
};
|
||||
const withScript = new FixtureProvider([...FIXTURE_UTXOS, scriptUtxo]);
|
||||
const l = await lucidForAddress(withScript, OWN_ADDRESS);
|
||||
await assert.rejects(buildInteractContract(l, {
|
||||
scriptCbor: ALWAYS_SUCCEEDS_V2, scriptType: 'PlutusV2', action: 'spend',
|
||||
changeAddress: OWN_ADDRESS, redeemer: '',
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user