Skip to content

Commit

Permalink
Merge pull request #329 from EYBlockchain/swati/internalFunction
Browse files Browse the repository at this point in the history
Swati/internal function
  • Loading branch information
SwatiEY authored Sep 13, 2024
2 parents 4f45c0c + 5b5e461 commit 09ed671
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 36 deletions.
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
17 changes: 16 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,17 @@ 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;
}

});
});
// sort the array in descending array so that we delete the correct elements
deletedIndexes = deletedIndexes.slice().sort((a, b) => b - a);
deletedIndexes.forEach(index => {
parameterList.splice(index, 1)
});
let newBPName: string;
let currentIndex: number;
let newCommitment = {};
Expand Down Expand Up @@ -59,6 +69,7 @@ const reorderParameters = (parameterList: any) => {
elementsToAdd.forEach((element) => {
parameterList.splice(element.NewIndex, 0, element.element);
});

}


Expand Down Expand Up @@ -288,7 +299,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
122 changes: 107 additions & 15 deletions src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ const internalCallVisitor = {
state.currentIndex = index;
traverseNodesFast(node, adjustNamesVisitor, state);
}

});
});
state.newPostStatementList = cloneDeep(childNode.body.postStatements);
state.newPostStatementList.forEach(node => {
if(node.nodeType === 'MembershipWitness'){
Expand Down Expand Up @@ -213,6 +212,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 declarationNode = childNode.body.preStatements.filter(node => node.nodeType === 'VariableDeclarationStatement');
!JSON.stringify(declarationNode).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);
}): '';
if(childNode.decrementedSecretStates)
childNode.decrementedSecretStates = [...new Set([...childNode.decrementedSecretStates, ...newdecrementedSecretStates])];
childNode.body.preStatements.forEach(node => {
Expand Down Expand Up @@ -267,7 +274,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 +314,60 @@ 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) {
// for statement like
/*
for (statement) {
a += internalFuncCall();
} here, kidNode will look like
expression: {
nodeType: 'Assignment',
name: 'add',
internalFunctionInteractsWithSecret: true,
operator: '+=',
leftHandSide: { nodeType: 'Identifier', name: 'a', subType: 'uint256' },
}, and we need to get the other expression from the other function here.
*/
const newExpressionNode = Object.assign(cloneDeep(kidNode.expression), statenode.initialValue);
node.body.statements.push(newExpressionNode);
} else {
// for statement like
/*
for (statement) {
internalFuncCall();
} here, kidNode will look like
expression: {
expression: {
nodeType: 'InternalFunctionCall',
name: 'add',
internalFunctionInteractsWithSecret: true
},
and we need to get the other expression from the other function here.
*/
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 +388,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 +428,7 @@ const internalCallVisitor = {
}
});
});
node.privateStates = Object.assign(node.privateStates,statenode.privateStates);
node.privateStates = Object.assign(node.privateStates, statenode.privateStates);
}
});
break;
Expand All @@ -397,15 +443,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 +468,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 +545,7 @@ FunctionCall: {
}
}
else
isCircuit = true;
isCircuit = true;
}
}
});
Expand All @@ -507,10 +554,55 @@ 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;
}

if(parent._newASTPointer.interactsWithSecret && !(state.returnPara?.includes(returnPara))) {
state.returnPara ??= [];
state.returnPara.push(returnPara);
}
})
} 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

0 comments on commit 09ed671

Please sign in to comment.