Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contract input fixes for stack too deep error #276

Merged
merged 6 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class ContractBoilerplateGenerator {
delete parameterList[ paramtype ];
}
const newList: string[] = [];

params?.forEach(circuitParamNode => {
switch (circuitParamNode.bpType) {
case 'nullification':
Expand All @@ -144,8 +145,9 @@ class ContractBoilerplateGenerator {
if (!newList.includes(circuitParamNode.bpType)) newList.push(circuitParamNode.bpType);
break;
case 'encryption':
returnpara['returnParameters'] ??= [];
returnpara['returnParameters'].push(circuitParamNode.bpType);

returnpara['encryptionParameters'] ??= [];
returnpara['encryptionParameters'].push(circuitParamNode.bpType);
break;
case undefined: {
if (
Expand Down Expand Up @@ -176,6 +178,7 @@ class ContractBoilerplateGenerator {
parameterList = {...parameterList, ...returnpara};
}
circuitParams[ functionName ] = parameterList;

}
const constructorContainsSecret = Object.values(this.scope.bindings).some((binding: any) => binding.node.kind === 'constructor')
return { nullifiersRequired, oldCommitmentAccessRequired, newCommitmentsRequired, containsAccessedOnlyState, encryptionRequired, constructorContainsSecret, circuitParams, isjoinSplitCommitmentsFunction};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ class ContractBoilerplateGenerator {
let verifyInput: string[] = [];

const verifyInputsMap = (type: string, input: string, counter: any) => {

if(type === 'parameters'){
switch (input) {
case 'nullifierRoot':
Expand All @@ -148,7 +147,7 @@ class ContractBoilerplateGenerator {
break;
}
}
else if(type === 'returnParameters') {
else if(type === 'returnParameters' || type === 'encryptionParameters') {
switch (input) {
case 'encryption':
verifyInput.push( `
Expand Down Expand Up @@ -220,13 +219,13 @@ class ContractBoilerplateGenerator {
encryption: 0,
};

_inputs.map(i => verifyInputsMap(type, i, counter));
_inputs?.map(i => verifyInputsMap(type, i, counter));



}

if(_params && !(Object.keys(_params).includes('returnParameters'))) verifyInput.push(`
if(_params && !(Object.keys(_params).includes('returnParameters')) &&!(Object.keys(_params).includes('encryptionParameters'))) verifyInput.push(`
inputs[k++] = 1;`)

verifyInputs.push(`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ class FunctionBoilerplateGenerator {
if (isConstructor && encryptionRequired) throw new Error(`There shouldn't be any secret states that require sharing encrypted data in the constructor.`)
const visibility = isConstructor ? 'memory' : 'calldata';
return [
...(newNullifiers ? [`uint256 nullifierRoot, uint256 latestNullifierRoot,uint256[] ${visibility} newNullifiers`] : []), // nullifiers and nullifier root exist together
...(commitmentRoot ? [`uint256 commitmentRoot`] : []),
...(newCommitments ? [`uint256[] ${visibility} newCommitments`] : []),
...(encryptionRequired ? [`uint256[][] calldata cipherText`] : []),
...(encryptionRequired ? [`uint256[2][] calldata ephPubKeys`] : []),
...(newCommitments || newNullifiers ? [`uint256[] ${visibility} proof`] : []),
// ...(newNullifiers ? [`uint256 nullifierRoot, uint256 latestNullifierRoot,uint256[] ${visibility} newNullifiers`] : []), // nullifiers and nullifier root exist together
// ...(commitmentRoot ? [`uint256 commitmentRoot`] : []),
// ...(newCommitments ? [`uint256[] ${visibility} newCommitments`] : []),
// ...(encryptionRequired ? [`uint256[][] calldata cipherText`] : []),
// ...(encryptionRequired ? [`uint256[2][] calldata ephPubKeys`] : []),
...(newCommitments || newNullifiers ? [`Inputs calldata inputs, uint256[] ${visibility} proof`] : []),
];
},

Expand Down Expand Up @@ -97,53 +97,55 @@ class FunctionBoilerplateGenerator {
let msgSigCheck = ([...(isConstructor ? [] : [`bytes4 sig = bytes4(keccak256("${functionName}(${parameter})")) ; \n \t \t \t if (sig == msg.sig)`])]);

customInputs = customInputs?.flat(Infinity).filter(p => p.inCircuit);

const addCustomInputs = customInputs?.length == 1 && customInputs[0].name == '1' ? false : true;
return [
`
Inputs memory inputs;`,

...(customInputs?.length ?
// `
// Inputs memory inputs;`,
...(addCustomInputs ?
[`
inputs.customInputs = new uint[](${customInputs.flat(Infinity).length});
Inputs memory updatedInputs = inputs;
updatedInputs.customInputs = new uint[](${customInputs.flat(Infinity).length});
${customInputs.flat(Infinity).map((input: any, i: number) => {
if (input.type === 'address') return `inputs.customInputs[${i}] = uint256(uint160(address(${input.name})));`;
if ((input.type === 'bool' || input.typeName?.name === 'bool' ) && !['0', '1'].includes(input.name)) return `inputs.customInputs[${i}] = ${input.name} == false ? 0 : 1;`;
return `inputs.customInputs[${i}] = ${input.name};`;
}).join('\n')}`]
: []),
if (input.type === 'address') return `updatedInputs.customInputs[${i}] = uint256(uint160(address(${input.name})));`;
if ((input.type === 'bool' || input.typeName?.name === 'bool' ) && !['0', '1'].includes(input.name)) return `updatedInputs.customInputs[${i}] = ${input.name} == false ? 0 : 1;`;
return `updatedInputs.customInputs[${i}] = ${input.name};`;
}).join('\n')}

verify(proof, uint(FunctionNames.${functionName}), updatedInputs);`]
: [`
verify(proof, uint(FunctionNames.${functionName}), inputs);`]),

...(newNullifiers ? [`
inputs.nullifierRoot = nullifierRoot; `] : []),
// ...(newNullifiers ? [`
// // inputs.nullifierRoot = nullifierRoot; `] : []),

...(newNullifiers ? [`
inputs.latestNullifierRoot = latestNullifierRoot; `] : []),
// ...(newNullifiers ? [`
// inputs.latestNullifierRoot = latestNullifierRoot; `] : []),


...(newNullifiers ? [`
inputs.newNullifiers = newNullifiers;
`] : []),
// ...(newNullifiers ? [`
// inputs.newNullifiers = newNullifiers;
// `] : []),

...(commitmentRoot ? [`
inputs.commitmentRoot = commitmentRoot;`] : []),
// ...(commitmentRoot ? [`
// inputs.commitmentRoot = commitmentRoot;`] : []),

...(newCommitments ? [`
inputs.newCommitments = newCommitments;`] : []),
// ...(newCommitments ? [`
// inputs.newCommitments = newCommitments;`] : []),

...(encryptionRequired ? [`
inputs.cipherText = cipherText;`] : []),

...(encryptionRequired ? [`
inputs.encKeys = ephPubKeys;`] : []),
`
${msgSigCheck.join('\n')}`,
`
verify(proof, uint(FunctionNames.${functionName}), inputs);`,
// ...(encryptionRequired ? [`
// inputs.cipherText = cipherText;`] : []),

// ...(encryptionRequired ? [`
// inputs.encKeys = ephPubKeys;`] : []),
// `
// ${msgSigCheck.join('\n')}`,

...(encryptionRequired ? [`
for (uint j; j < cipherText.length; j++) {
for (uint j; j < inputs.cipherText.length; j++) {
// this seems silly (it is) but its the only way to get the event to emit properly
uint256[2] memory ephKeyToEmit = ephPubKeys[j];
uint256[] memory cipherToEmit = cipherText[j];
uint256[2] memory ephKeyToEmit = inputs.encKeys[j];
uint256[] memory cipherToEmit = inputs.cipherText[j];
emit EncryptedData(cipherToEmit, ephKeyToEmit);
}`] : []),
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ export function buildBoilerplateNode(nodeType: string, fields: any = {}): any {
functionName,
contractName,
publicInputs = [],
returnInputs = [],
privateStates = {},
} = fields;
return {
Expand All @@ -292,6 +293,7 @@ export function buildBoilerplateNode(nodeType: string, fields: any = {}): any {
functionName,
contractName,
publicInputs,
returnInputs,
};
}
case 'SetupCommonFilesBoilerplate': {
Expand Down
34 changes: 23 additions & 11 deletions src/boilerplate/orchestration/javascript/raw/toOrchestration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => {
const params:any[] = [];
const states: string[] = [];
const rtnparams: string[] = [];
let returnInputs: string[] = [];
let stateName: string;
let stateNode: any;

Expand Down Expand Up @@ -823,35 +824,46 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => {
lines.push(`${input}.integer`);
}
});
lines[lines.length - 1] += `, `;
}
returnInputs = returnInputs.concat(lines);

if(node.returnInputs[0]) {
node.returnInputs.forEach((input: any) => {
input == 'true' ? returnInputs.push(`1`) : input == 'false' ? returnInputs.push(`0`) : returnInputs.push(input);

})
}

params[0] = sendTransactionBoilerplate(node);
if(!node.returnInputs[0] && !params[0][4][0]) returnInputs.push(`1`); // If there are no return, circuit's default return is true
// params[0] = arr of nullifier root(s)
// params[1] = arr of commitment root(s)
// params[2] = arr of nullifiers
// params[3] = arr of commitments


if (params[0][0][0]) params[0][0] = `${params[0][0][0]},${params[0][0][1]},`; // nullifierRoot - array
if (params[0][2][0]) params[0][2] = `${params[0][2][0]},`; // commitmentRoot - array
if (params[0][1][0]) params[0][1] = `[${params[0][1]}],`; // nullifiers - array
if (params[0][3][0]) params[0][3] = `[${params[0][3]}],`; // commitments - array
if (params[0][4][0]) params[0][4] = `[${params[0][4]}],`; // cipherText - array of arrays
if (params[0][5][0]) params[0][5] = `[${params[0][5]}],`; // cipherText - array of arrays
(params[0][0][0]) ? params[0][0][0] = ` ${params[0][0][0]}, ` : params[0][0][0] = ` 0 , ` ; // nullifierRoot - array // Default value for the struct
(params[0][0][1]) ? params[0][0][1] = ` ${params[0][0][1]}, ` : params[0][0][1] = ` 0, `;
(params[0][2][0]) ? params[0][2] = ` ${params[0][2][0]},` : params[0][2] = ` 0 , ` ; // commitmentRoot - array
(params[0][1][0]) ? params[0][1] = ` [${params[0][1]}],` : params[0][1] = ` [], `; // nullifiers - array
(params[0][3][0]) ? params[0][3] = `[${params[0][3]}],` : params[0][3] = ` [], `; // commitments - array
(params[0][4][0]) ? params[0][4] = `[${params[0][4]}],` : params[0][4] = ` [], `; // cipherText - array of arrays
(params[0][5][0]) ? params[0][5] = `[${params[0][5]}],`: params[0][5] = ` [], `;// cipherText - array of arrays



if (node.functionName === 'cnstrctr') return {
statements: [
`\n\n// Save transaction for the constructor:
\nconst tx = { proofInput: [${params[0][0]}${params[0][1]} ${params[0][2]} ${params[0][3]} proof], ${node.publicInputs?.map(input => `${input}: ${input}.integer,`)}};`
\nconst tx = { proofInput: [{nullifierRoot: ${params[0][0][0]} latestNullifierRoot:${params[0][0][1]} newNullifiers: ${params[0][1]} commitmentRoot:${params[0][2]} newCommitments: ${params[0][3]}}, proof], ${node.publicInputs?.map(input => `${input}: ${input}.integer,`)}};`
]
}



return {
statements: [
`\n\n// Send transaction to the blockchain:
\nconst txData = await instance.methods
.${node.functionName}(${lines}${params[0][0]} ${params[0][1]} ${params[0][2]} ${params[0][3]} ${params[0][4]} ${params[0][5]} proof).encodeABI();
.${node.functionName}(${lines.length > 0 ? `${lines},`: ``} {customInputs: [${returnInputs}], nullifierRoot: ${params[0][0][0]} latestNullifierRoot:${params[0][0][1]} newNullifiers: ${params[0][1]} commitmentRoot:${params[0][2]} newCommitments: ${params[0][3]} cipherText:${params[0][4]} encKeys: ${params[0][5]}}, proof).encodeABI();
\n let txParams = {
from: config.web3.options.defaultAccount,
to: contractAddr,
Expand Down
14 changes: 13 additions & 1 deletion src/codeGenerators/contract/solidity/toContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ function codeGenerator(node: any) {
case 'FunctionDefinition': {
// prettier-ignore
let functionType: string = ``;
let returnType: string[] = [];
let returnParams: string[] = [];
switch (node.kind)
{
case 'fallback':
Expand All @@ -82,7 +84,16 @@ function codeGenerator(node: any) {

}

const functionSignature = `${functionType} (${codeGenerator(node.parameters)}) ${node.visibility} ${node.stateMutability} {`;
// add any public return here,

node.returnParameters.parameters.forEach(params => {
if(!params.isSecret && params.typeDescriptions.typeString != 'bool') {
returnType.push(params.typeDescriptions.typeString);
returnParams.push(params.name);
}
})

const functionSignature = `${functionType} (${codeGenerator(node.parameters)}) ${node.visibility} ${node.stateMutability} ${returnType.length > 0 ? `returns (${returnType})`: ``}{`;
let body = codeGenerator(node.body);
let msgSigCheck = body.slice(body.indexOf('bytes4 sig'), body.indexOf('verify') )
if(!node.msgSigRequired)
Expand All @@ -91,6 +102,7 @@ function codeGenerator(node: any) {
${functionSignature}

${body}
${returnType.length == 1 ? `return ${returnParams};` : returnType.length > 1 ? `return (${returnParams});` : `` }
}`;
}

Expand Down
13 changes: 3 additions & 10 deletions src/transformers/visitors/toContractVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ export default {
path.traversePathsFast(findCustomInputsVisitor, state);
state.returnpara ??= {};
state.returnpara[state.functionName] ??= {};
state.returnpara[state.functionName].returnParameters = state.customInputs.map(n => n.name);
state.returnpara[state.functionName].returnParameters = state.customInputs?.map(n => n.name);
const newNode = buildNode(
node.nodeType,
{ value: node.expression.value });
Expand Down Expand Up @@ -896,15 +896,8 @@ DoWhileStatement: {
state.fnParameters.push(args[index]);

});
const params = [...(internalfnDefIndicators.nullifiersRequired? [`nullifierRoot`] : []),
...(internalfnDefIndicators.nullifiersRequired? [`latestNullifierRoot`] : []),
...(internalfnDefIndicators.nullifiersRequired? [`newNullifiers`] : []),
...(internalfnDefIndicators.oldCommitmentAccessRequired ? [`commitmentRoot`] : []),
...(internalfnDefIndicators.newCommitmentsRequired ? [`newCommitments`] : []),
...(internalfnDefIndicators.containsAccessedOnlyState ? [`checkNullifiers`] : []),
...(internalfnDefIndicators.encryptionRequired ? [`cipherText`] : []),
...(internalfnDefIndicators.encryptionRequired ? [`ephPubKeys`] : []),
`proof`,
const params = [
`inputs, proof`,
]

state.fnParameters = state.fnParameters.concat(params);
Expand Down
22 changes: 21 additions & 1 deletion src/transformers/visitors/toOrchestrationVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,27 @@ const visitor = {
} else newNodes.sendTransactionNode.publicInputs.push(param.name);
}
}

// this adds the return parameters which are marked as secret in the tx

let returnPara = node._newASTPointer.returnParameters.parameters.filter((paramnode: any) => (paramnode.isSecret || paramnode.typeName.name === 'bool')).map(paramnode => (paramnode.name)) || [];

let returnIsSecret: string[] = [];
const decStates = node._newASTPointer.decrementedSecretStates;
if( node._newASTPointer.returnParameters.parameters) {
node._newASTPointer.returnParameters.parameters.forEach( node => {
returnIsSecret.push(node.isSecret);
})
}
returnPara.forEach( (param, index) => {
if(decStates) {
if(decStates?.includes(param)){
returnPara[index] = returnPara[index]+'_2_newCommitment';
}
} else if(returnIsSecret[index])
returnPara[index] = returnPara[index] +'_newCommitment';
})
newNodes.sendTransactionNode.returnInputs = returnPara;

// the newNodes array is already ordered, however we need the initialisePreimageNode & InitialiseKeysNode before any copied over statements
// UNLESS they are public accessed states...
let earliestPublicAccessIndex = newFunctionDefinitionNode.body.preStatements.findIndex(
Expand Down
8 changes: 4 additions & 4 deletions test/contracts/Assign-Return.zol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ contract Assign {
secret uint256 private a;
uint256 private b;

function add( uint256 value) public returns (bool, uint256) {
unknown a += value;
return (true, 5);
function add( uint256 value) public returns (uint256, uint256) {
encrypt unknown a += value;
return (1, 5);
}

function remove(secret uint256 value, uint256 value1) public returns (uint256, uint256) {

b -= value1;
b += value1;
a -= value;
return (b, a);
}
Expand Down
Loading
Loading