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

Swati/internal function #329

Merged
merged 18 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ class FunctionBoilerplateGenerator {
: []),
...(newCommitments ? [`
// this seems silly (it is) but its the only way to get the event to emit properly
emit EncryptedBackupData(BackupData);`]
emit EncryptedBackupData(BackupData);
`]
: []),
];
},
Expand Down
7 changes: 7 additions & 0 deletions src/codeGenerators/circuit/zokrates/toCircuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,14 @@ function codeGenerator(node: any) {
case 'VariableDeclarationStatement': {
const declarations = node.declarations.map(codeGenerator).join(', ');
if (!node.initialValue) return `${declarations} = ${node.declarations.map(n => n.typeName.name === 'bool' ? 'false' : 0)}`;
if(node.initialValue?.nodeType === 'InternalFunctionCall'){
if(!declarations) return ;
if(node.initialValue?.expression?.nodeType === 'BinaryOperation')
return `${declarations} = ${codeGenerator(node.initialValue.expression)}`;
return `${declarations} = ${node.initialValue.name}`;
}
const initialValue = codeGenerator(node.initialValue);

return `${declarations} = ${initialValue}`;
}

Expand Down
5 changes: 5 additions & 0 deletions src/codeGenerators/contract/solidity/toContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ function codeGenerator(node: any) {
if(node.initialValue)
initialValue = codeGenerator(node.initialValue);
if (!initialValue || initialValue === '') return `${declarations};`;
if(node.initialValue.nodeType === 'InternalFunctionCall'){
if(node.interactsWithSecret) return ;
return `
${declarations} = ${initialValue.replace(/\s+/g,' ').trim()}`;
}
return `
${declarations} = ${initialValue};`;
}
Expand Down
5 changes: 5 additions & 0 deletions src/codeGenerators/orchestration/nodejs/toOrchestration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ export default function codeGenerator(node: any, options: any = {}): any {
if (!node.initialValue.nodeType) return `\nlet ${codeGenerator(node.declarations[0])};`
// local var dec
if (node.initialValue.nodeType === 'Literal' && node.isInitializationExpression) return `\nlet ${codeGenerator(node.declarations[0])} = ${codeGenerator(node.initialValue)};`;
if(node.initialValue.nodeType === 'InternalFunctionCall'){
if(node.initialValue?.expression?.nodeType === 'BinaryOperation')
return `\nlet ${codeGenerator(node.declarations[0])} = ${codeGenerator(node.initialValue.expression)};`;
return `\nlet ${codeGenerator(node.declarations[0])} = ${node.initialValue.name};`;
}
return `\nlet ${codeGenerator(node.declarations[0])} = generalise(${codeGenerator(node.initialValue)});`;
}
return `\nlet ${codeGenerator(node.initialValue)};`;
Expand Down
13 changes: 12 additions & 1 deletion src/transformers/visitors/circuitInternalFunctionCallVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import buildNode from '../../types/orchestration-types.js'
// We need to ensure that parameters appear in the same order as in the .mjs file if the same state variables are used in multiple function calls.
// All parameters relating to the same state variable should be grouped together.
const reorderParameters = (parameterList: any) => {
let deletedIndexes = [];
parameterList.forEach((param, index) => {
parameterList.forEach((newParam, newIndex) => {
if (param.name === newParam.name && param.bpType === 'nullification' && newParam.bpType === 'nullification') {
Expand All @@ -19,8 +20,13 @@ const reorderParameters = (parameterList: any) => {
parameterList[index] = newParam;
}
}
if(param.name === newParam.name && param.nodeType === 'VariableDeclaration' && newParam.nodeType === 'Boilerplate'){
!deletedIndexes.includes(index)? deletedIndexes.push(index) : deletedIndexes;
}

});
});
deletedIndexes.forEach(index => parameterList.splice(index, 1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to be careful here as well. Say we have indexes (2,5) stored in deleted indexes, and we delete index 2 first then the element from index 5 is now in index 4 so the wrong index gets deleted. We need to go through the indexes in reverse order from highest to lowest.

let newBPName: string;
let currentIndex: number;
let newCommitment = {};
Expand Down Expand Up @@ -59,6 +65,7 @@ const reorderParameters = (parameterList: any) => {
elementsToAdd.forEach((element) => {
parameterList.splice(element.NewIndex, 0, element.element);
});

}


Expand Down Expand Up @@ -288,7 +295,11 @@ const internalCallVisitor = {
if(file.fileName === callingFncName) {
file.nodes.forEach(childNode => {
if(childNode.nodeType === 'FunctionDefinition') {
childNode.body.statements.forEach(node => {
childNode.body.statements.forEach((node) => {
if(node.initialValue?.nodeType === 'InternalFunctionCall' && state.initNode) {
node.initialValue.expression = state.initNode[ node.initialValue.name ];
}

if(node.nodeType==='BoilerplateStatement'){
callingFncbpType = node.bpType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ const internalCallVisitor = {
state.currentIndex = index;
traverseNodesFast(node, adjustNamesVisitor, state);
}

});

if(state.expNode) state.newStatementList.push(state.expNode);
Copy link
Contributor

@lydiagarms lydiagarms Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this now obsolete?

state.newPostStatementList = cloneDeep(childNode.body.postStatements);
state.newPostStatementList.forEach(node => {
if(node.nodeType === 'MembershipWitness'){
Expand Down Expand Up @@ -213,6 +214,14 @@ const internalCallVisitor = {
file.nodes.forEach(childNode => {
if(childNode.nodeType === 'FunctionDefinition') {
childNode.parameters.modifiedStateVariables = joinWithoutDupes(childNode.parameters.modifiedStateVariables, state.newParametersList);
const modifiedNodes = childNode.parameters.modifiedStateVariables.map(node => node.name);
const decNode = childNode.body.preStatements.filter(node => node.nodeType === 'VariableDeclarationStatement');
!JSON.stringify(decNode).includes(JSON.stringify(state.decNode)) ?
state.decNode?.forEach((decNode, decIndex) => {
// if the function doesn't modifies the returned variable don't include it
if(state.decNode && !(modifiedNodes.includes(decNode.declarations[0].name)))
childNode.body.preStatements.splice(decIndex+1, 0, decNode);
}): '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name decNode is used twice here in the for loop and also declared on line 218, could we use a different name for one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed the name

if(childNode.decrementedSecretStates)
childNode.decrementedSecretStates = [...new Set([...childNode.decrementedSecretStates, ...newdecrementedSecretStates])];
childNode.body.preStatements.forEach(node => {
Expand Down Expand Up @@ -267,7 +276,8 @@ const internalCallVisitor = {
let newVarDecs = [];
childNode.body.statements.forEach((node1, index1)=> {
state.varNames = [];
if (!(node1.expression && node1.expression?.nodeType === 'InternalFunctionCall')){
// check the node except the InternalFunctionCall node and new created public node with id = 0 as we created it
if (!((node1.expression && node1.expression?.nodeType === 'InternalFunctionCall') || (node1.initialValue && node1.initialValue?.nodeType === 'InternalFunctionCall') || node1.id === 0)){
traverseNodesFast(node1, findVarVisitor, state);
}
state.varNames.forEach((varName) => {
Expand Down Expand Up @@ -306,22 +316,34 @@ const internalCallVisitor = {
childNode.body.statements[id-1] = statenode;
node.body.statements.forEach(kidNode =>{
if(kidNode.nodeType === 'ExpressionStatement'&& kidNode.expression.name === state.internalFncName[index]) {
kidNode.expression = Object.assign(kidNode.expression,statenode.initialValue);
//When Internal function is inside for-loop, it exit under Expression Statement, we replace the function call with expression from the called function
if (kidNode.expression.operator) {
const newExpressionNode = Object.assign(cloneDeep(kidNode.expression), statenode.initialValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still dont' get exactly what is happening here? What does kidNode.expression.operator correspond to? Isn't this normally defined? kidNode remains in node.body.statements so doesn't this lead to a duplicate?

node.body.statements.push(newExpressionNode);
} else {
Object.assign(kidNode.expression, statenode.initialValue);
}
}

});
childNode.body.statements[id-1].initialValue =undefined;
childNode.body.statements[id-1].initialValue = undefined;
} else{
node.body.statements.forEach(kidNode =>{
if(kidNode.nodeType === 'ExpressionStatement'&& kidNode.expression.name === state.internalFncName[index]) {
kidNode.expression = Object.assign(kidNode.expression,statenode.expression);
node.body.statements.forEach(kidNode => {
if(kidNode.nodeType === 'ExpressionStatement' && kidNode.expression.name === state.internalFncName[index]) {
if(kidNode.expression.operator) {
// If the internal function modifies the same state variable, we need to copy over the statements in the calling function
const newExpressionNode = Object.assign(cloneDeep(kidNode.expression), statenode.expression);
node.body.statements.push(newExpressionNode);
}
kidNode.expression = Object.assign(kidNode.expression, statenode.expression);
}
});
}
}
});
});
// remove multiple variable declarations
childNode.body.statements.forEach((node1, index1)=> {
childNode.body.statements.forEach((node1, index1) => {
let isDecDeleted = false;
if(node1.nodeType === 'VariableDeclarationStatement'){
childNode.body.statements.forEach((node2, index2)=> {
Expand All @@ -342,7 +364,7 @@ const internalCallVisitor = {
if(statenode.nodeType === 'VariableDeclarationStatement'){
childNode.body.statements[id-1] = statenode;
node.body.statements.forEach(kidNode =>{
if(kidNode.nodeType === 'ExpressionStatement'&& kidNode.expression.name === state.internalFncName[index]) {
if(kidNode.nodeType === 'ExpressionStatement' && kidNode.expression.name === state.internalFncName[index]) {
kidNode.expression = Object.assign(kidNode.expression,statenode.initialValue);
node.body.statements?.splice(node.body.statements.indexOf(kidNode)+1, 0, state.newStatementList[stateid+1]);
}
Expand Down Expand Up @@ -382,7 +404,7 @@ const internalCallVisitor = {
}
});
});
node.privateStates = Object.assign(node.privateStates,statenode.privateStates);
node.privateStates = Object.assign(node.privateStates, statenode.privateStates);
}
});
break;
Expand All @@ -397,15 +419,15 @@ const internalCallVisitor = {
}
});
});
node.privateStates = Object.assign(node.privateStates,statenode.privateStates);
node.privateStates = Object.assign(node.privateStates, statenode.privateStates);
}
});
break;
}
case 'CalculateCommitment': {
state.newPostStatementList.forEach(statenode => {
if(statenode.nodeType === 'CalculateCommitment'){
node.privateStates = Object.assign(node.privateStates,statenode.privateStates);
node.privateStates = Object.assign(node.privateStates, statenode.privateStates);
}
});
break;
Expand All @@ -422,6 +444,7 @@ const internalCallVisitor = {
});
node.privateStates = Object.assign(node.privateStates,generateProofNode.privateStates);
node.parameters = [...new Set([...node.parameters ,...generateProofNode.parameters])];
state.returnPara ? node.parameters = [...new Set([...node.parameters, ...state.returnPara])]: node.parameters;
break;
}
case 'SendTransaction': {
Expand Down Expand Up @@ -498,7 +521,7 @@ FunctionCall: {
}
}
else
isCircuit = true;
isCircuit = true;
}
}
});
Expand All @@ -507,10 +530,51 @@ FunctionCall: {
state.circuitImport.push('true');
else
state.circuitImport.push('false');
const newNode = buildNode('InternalFunctionCall', {
let newNode;
if(parent.nodeType === 'VariableDeclarationStatement') {
if(!functionReferncedNode.node.returnParameters.parameters[0]._newASTPointer.isSecret) {
const decNode = buildNode('VariableDeclarationStatement')
decNode.declarations.push(functionReferncedNode.node.returnParameters.parameters[0]._newASTPointer);
decNode.interactsWithSecret = true;
decNode.declarations[0].declarationType = 'state';
decNode.declarations[0].isAccessed = true;
decNode.declarations[0].interactsWithSecret = true;
state.decNode ??= [];
const decNodeNames = state.decNode.map(node => node.declarations[0].name);
decNodeNames.includes(decNode.declarations[0].name) ? state.decNode : state.decNode.push(decNode);
}
const returnPara = functionReferncedNode.node.returnParameters.parameters[0].name;
let includeExpressionNode = false;
// this functions checks if the parent node interact with secret in the calling function or not
callingfnDefIndicators[parent.declarations[0].id].interactsWith.forEach( node => {
if(node.key != 'arguments' && node.interactsWithSecret)
includeExpressionNode = true;
})
functionReferncedNode.node.body.statements.forEach(exp => {
// If the return para interacts with public only in the internal function but with secret in calling function we need this expression in calling function
if(exp?.expression.leftHandSide?.name === returnPara && !exp.expression.leftHandSide.interactsWithSecret){
state.initNode = buildNode('BinaryOperation', {
leftExpression: exp._newASTPointer.expression.rightHandSide.leftExpression,
operator: exp._newASTPointer.expression.rightHandSide.operator,
rightExpression: exp._newASTPointer.expression.rightHandSide.rightExpression,
});
}
newNode = buildNode('InternalFunctionCall', {
name: returnPara,
internalFunctionInteractsWithSecret: internalFunctionInteractsWithSecret,
});
if(includeExpressionNode && state.initNode) {
newNode.expression = state.initNode;
}

parent._newASTPointer.interactsWithSecret ? state.returnPara = returnPara : ' ';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have the same issue as elsewhere here with state.returnPara being overwritten?

})
} else {
newNode = buildNode('InternalFunctionCall', {
name: node.expression.name,
internalFunctionInteractsWithSecret: internalFunctionInteractsWithSecret,
});
}
node._newASTPointer = newNode ;
if (Array.isArray(parent._newASTPointer[path.containerName])) {
parent._newASTPointer[path.containerName].push(newNode);
Expand Down
Loading
Loading