Skip to content

Commit b7a030c

Browse files
committed
Fix name collision bugs
- Append an input index to all scripts / entities - Create new entities and unlock scripts per input - Revert back to 1 scenario per unlock script (/ input) - Remove P2PKH script merge (not sure why that was there) - Some name changes - Update 2 fixtures
1 parent ffa4008 commit b7a030c

File tree

2 files changed

+576
-117
lines changed

2 files changed

+576
-117
lines changed

packages/cashscript/src/advanced/LibauthTemplate.ts

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,20 @@ import { TransactionBuilder } from '../TransactionBuilder.js';
5151
*
5252
*/
5353
export const generateTemplateEntitiesP2PKH = (
54-
index: number,
54+
inputIndex: number,
5555
): WalletTemplate['entities'] => {
56-
const lockScriptName = `p2pkh_placeholder_lock_${index}`;
57-
const unlockScriptName = `p2pkh_placeholder_unlock_${index}`;
56+
const lockScriptName = `p2pkh_placeholder_lock_${inputIndex}`;
57+
const unlockScriptName = `p2pkh_placeholder_unlock_${inputIndex}`;
5858

5959
return {
60-
[`signer_${index}`]: {
60+
[`signer_${inputIndex}`]: {
6161
scripts: [lockScriptName, unlockScriptName],
62-
description: `placeholder_key_${index}`,
63-
name: `Signer ${index}`,
62+
description: `placeholder_key_${inputIndex}`,
63+
name: `P2PKH Signer (input #${inputIndex})`,
6464
variables: {
65-
[`placeholder_key_${index}`]: {
65+
[`placeholder_key_${inputIndex}`]: {
6666
description: '',
67-
name: `Placeholder Key ${index}`,
67+
name: `P2PKH Placeholder Key (input #${inputIndex})`,
6868
type: 'Key',
6969
},
7070
},
@@ -83,6 +83,7 @@ export const generateTemplateEntitiesP2SH = (
8383
artifact: Artifact,
8484
abiFunction: AbiFunction,
8585
encodedFunctionArgs: EncodedFunctionArgument[],
86+
inputIndex: number,
8687
): WalletTemplate['entities'] => {
8788
const functionParameters = Object.fromEntries<WalletTemplateVariable>(
8889
abiFunction.inputs.map((input, index) => ([
@@ -107,12 +108,12 @@ export const generateTemplateEntitiesP2SH = (
107108
);
108109

109110
const entities = {
110-
[snakeCase(artifact.contractName + 'Parameters')]: {
111+
[snakeCase(artifact.contractName + 'Parameters' + '_input' + inputIndex)]: {
111112
description: 'Contract creation and function parameters',
112-
name: titleCase(artifact.contractName),
113+
name: `${artifact.contractName} (input #${inputIndex})`,
113114
scripts: [
114115
snakeCase(artifact.contractName + '_lock'),
115-
snakeCase(artifact.contractName + '_' + abiFunction.name + '_unlock'),
116+
snakeCase(artifact.contractName + '_' + abiFunction.name + '_input' + inputIndex + '_unlock'),
116117
],
117118
variables: {
118119
...functionParameters,
@@ -123,7 +124,7 @@ export const generateTemplateEntitiesP2SH = (
123124

124125
// function_index is a special variable that indicates the function to execute
125126
if (artifact.abi.length > 1) {
126-
entities[snakeCase(artifact.contractName + 'Parameters')].variables.function_index = {
127+
entities[snakeCase(artifact.contractName + 'Parameters' + '_input' + inputIndex)].variables.function_index = {
127128
description: 'Script function index to execute',
128129
name: titleCase('function_index'),
129130
type: 'WalletData',
@@ -142,27 +143,27 @@ export const generateTemplateEntitiesP2SH = (
142143
*/
143144
export const generateTemplateScriptsP2PKH = (
144145
template: SignatureTemplate,
145-
index: number,
146+
inputIndex: number,
146147
): WalletTemplate['scripts'] => {
147148
const scripts: WalletTemplate['scripts'] = {};
148-
const lockScriptName = `p2pkh_placeholder_lock_${index}`;
149-
const unlockScriptName = `p2pkh_placeholder_unlock_${index}`;
150-
const placeholderKeyName = `placeholder_key_${index}`;
149+
const lockScriptName = `p2pkh_placeholder_lock_${inputIndex}`;
150+
const unlockScriptName = `p2pkh_placeholder_unlock_${inputIndex}`;
151+
const placeholderKeyName = `placeholder_key_${inputIndex}`;
151152

152153
const signatureAlgorithmName = getSignatureAlgorithmName(template.getSignatureAlgorithm());
153154
const hashtypeName = getHashTypeName(template.getHashType(false));
154155
const signatureString = `${placeholderKeyName}.${signatureAlgorithmName}.${hashtypeName}`;
155156
// add extra unlocking and locking script for P2PKH inputs spent alongside our contract
156157
// this is needed for correct cross-references in the template
157158
scripts[unlockScriptName] = {
158-
name: unlockScriptName,
159+
name: `P2PKH Unlock (input #${inputIndex})`,
159160
script:
160161
`<${signatureString}>\n<${placeholderKeyName}.public_key>`,
161162
unlocks: lockScriptName,
162163
};
163164
scripts[lockScriptName] = {
164165
lockingType: 'standard',
165-
name: lockScriptName,
166+
name: `P2PKH Lock (input #${inputIndex})`,
166167
script:
167168
`OP_DUP\nOP_HASH160 <$(<${placeholderKeyName}.public_key> OP_HASH160\n)> OP_EQUALVERIFY\nOP_CHECKSIG`,
168169
};
@@ -183,12 +184,16 @@ export const generateTemplateScriptsP2SH = (
183184
abiFunction: AbiFunction,
184185
encodedFunctionArgs: EncodedFunctionArgument[],
185186
encodedConstructorArgs: EncodedConstructorArgument[],
186-
scenarioIds: string[],
187+
scenarioId: string,
188+
inputIndex: number,
187189
): WalletTemplate['scripts'] => {
188190
// definition of locking scripts and unlocking scripts with their respective bytecode
191+
const unlockingScriptName = snakeCase(artifact.contractName + '_' + abiFunction.name + '_input' + inputIndex + '_unlock');
192+
const lockingScriptName = snakeCase(artifact.contractName + '_lock');
193+
189194
return {
190-
[snakeCase(artifact.contractName + '_' + abiFunction.name + '_unlock')]: generateTemplateUnlockScript(artifact, abiFunction, encodedFunctionArgs, scenarioIds),
191-
[snakeCase(artifact.contractName + '_lock')]: generateTemplateLockScript(artifact, addressType, encodedConstructorArgs),
195+
[unlockingScriptName]: generateTemplateUnlockScript(artifact, abiFunction, encodedFunctionArgs, scenarioId, inputIndex),
196+
[lockingScriptName]: generateTemplateLockScript(artifact, addressType, encodedConstructorArgs),
192197
};
193198
};
194199

@@ -228,7 +233,8 @@ const generateTemplateUnlockScript = (
228233
artifact: Artifact,
229234
abiFunction: AbiFunction,
230235
encodedFunctionArgs: EncodedFunctionArgument[],
231-
scenarioIds: string[],
236+
scenarioId: string,
237+
inputIndex: number,
232238
): WalletTemplateScriptUnlocking => {
233239
const functionIndex = artifact.abi.findIndex((func) => func.name === abiFunction.name);
234240

@@ -238,8 +244,8 @@ const generateTemplateUnlockScript = (
238244

239245
return {
240246
// this unlocking script must pass our only scenario
241-
passes: scenarioIds,
242-
name: abiFunction.name,
247+
passes: [scenarioId],
248+
name: `${abiFunction.name} (input #${inputIndex})`,
243249
script: [
244250
`// "${abiFunction.name}" function parameters`,
245251
formatParametersForDebugging(abiFunction.inputs, encodedFunctionArgs),
@@ -389,13 +395,13 @@ export const getLibauthTemplates = (
389395
const unlockingBytecodeToLockingBytecodeParams: Record<string, WalletTemplateScenarioBytecode> = {};
390396
const lockingBytecodeToLockingBytecodeParams: Record<string, WalletTemplateScenarioBytecode> = {};
391397

392-
for (const [idx, input] of txn.inputs.entries()) {
398+
for (const [inputIndex, input] of txn.inputs.entries()) {
393399
// If template exists on the input, it indicates this is a P2PKH (Pay to Public Key Hash) input
394400
if (input.unlocker?.template) {
395401
// @ts-ignore TODO: Remove UtxoP2PKH type and only use UnlockableUtxo in Libaith Template generation
396402
input.template = input.unlocker?.template; // Added to support P2PKH inputs in buildTemplate
397-
Object.assign(p2pkhEntities, generateTemplateEntitiesP2PKH(idx));
398-
Object.assign(p2pkhScripts, generateTemplateScriptsP2PKH(input.unlocker.template, idx));
403+
Object.assign(p2pkhEntities, generateTemplateEntitiesP2PKH(inputIndex));
404+
Object.assign(p2pkhScripts, generateTemplateScriptsP2PKH(input.unlocker.template, inputIndex));
399405

400406
continue;
401407
}
@@ -441,7 +447,7 @@ export const getLibauthTemplates = (
441447
csTransaction as any,
442448
abiFunction,
443449
encodedArgs,
444-
idx,
450+
inputIndex,
445451
),
446452
);
447453

@@ -450,6 +456,7 @@ export const getLibauthTemplates = (
450456
contract.artifact,
451457
abiFunction,
452458
encodedArgs,
459+
inputIndex,
453460
);
454461

455462
// Generate scripts for this contract input
@@ -459,15 +466,16 @@ export const getLibauthTemplates = (
459466
abiFunction,
460467
encodedArgs,
461468
contract.encodedConstructorArgs,
462-
scenarioIds,
469+
scenarioIdentifier,
470+
inputIndex,
463471
);
464472

465473
// Find the lock script name for this contract input
466474
const lockScriptName = Object.keys(script).find(scriptName => scriptName.includes('_lock'));
467475
if (lockScriptName) {
468476
// Generate bytecodes for this contract input
469-
const csInput = csTransaction.inputs[idx];
470-
const unlockingBytecode = binToHex(libauthTransaction.inputs[idx].unlockingBytecode);
477+
const csInput = csTransaction.inputs[inputIndex];
478+
const unlockingBytecode = binToHex(libauthTransaction.inputs[inputIndex].unlockingBytecode);
471479
const lockingScriptParams = generateLockingScriptParams(csInput.unlocker!.contract!, csInput, lockScriptName);
472480

473481
// Assign a name to the unlocking bytecode so later it can be used to replace the bytecode/slot in scenarios
@@ -482,11 +490,6 @@ export const getLibauthTemplates = (
482490
}
483491
}
484492

485-
// Merge P2PKH scripts
486-
for (const entity of Object.values(p2pkhEntities) as { scripts?: string[] }[]) {
487-
if (entity.scripts) { entity.scripts = [...Object.keys(scripts), ...entity.scripts]; }
488-
}
489-
490493
Object.assign(entities, p2pkhEntities);
491494
Object.assign(scripts, p2pkhScripts);
492495

0 commit comments

Comments
 (0)