//Construct Memory Maps for Arrays for Mapping and ArrayTypeName types. private void ConstructMappingMemoryArray(Mapping mapping, HashSet <KeyValuePair <BoogieType, BoogieType> > generatedTypes) { BoogieType boogieKeyType = Conversion_Utility_Tool.GetBoogieTypeFromSolidityTypeName(mapping.KeyType); BoogieType boogieValueType = null; if (mapping.ValueType is Mapping submapping) { boogieValueType = BoogieType.Ref; ConstructMappingMemoryArray(submapping, generatedTypes); } else if (mapping.ValueType is ArrayTypeName array) { boogieValueType = BoogieType.Ref; ConstructArrayMemoryMap(array, generatedTypes); } else { boogieValueType = Conversion_Utility_Tool.GetBoogieTypeFromSolidityTypeName(mapping.ValueType); } KeyValuePair <BoogieType, BoogieType> pair = new KeyValuePair <BoogieType, BoogieType>(boogieKeyType, boogieValueType); if (!generatedTypes.Contains(pair)) { generatedTypes.Add(pair); BuildSingleMapMemoryName(boogieKeyType, boogieValueType); } }
//Build Memory Map for Array types, private void ConstructArrayMemoryMap(ArrayTypeName array, HashSet <KeyValuePair <BoogieType, BoogieType> > generatedTypes) { BoogieType boogieKeyType = BoogieType.Int; BoogieType boogieValueType = null; if (array.BaseType is ArrayTypeName subarray) { boogieValueType = BoogieType.Ref; ConstructArrayMemoryMap(subarray, generatedTypes); //construct array memory map with sub array } else if (array.BaseType is Mapping mapping) { boogieValueType = BoogieType.Ref; ConstructMappingMemoryArray(mapping, generatedTypes); // construct array memory map using mapping type } else { boogieValueType = Conversion_Utility_Tool.GetBoogieTypeFromSolidityTypeName(array.BaseType); //type cannot be resolve, request type declaration } KeyValuePair <BoogieType, BoogieType> pair = new KeyValuePair <BoogieType, BoogieType>(boogieKeyType, boogieValueType); if (generatedTypes.Contains(pair) == false) { generatedTypes.Add(pair); BuildSingleMapMemoryName(boogieKeyType, boogieValueType); } }
//Create a contract boogie harness for each respective contract parsed through here. private void createContractBoogieHarness(ContractDefinition contract) { //create the contract harness name string contractHarnessName = "BoogieEntry_" + contract.Name; //input boogie variables List <BoogieVariable> inputParameters = new List <BoogieVariable>(); //output boogie variables List <BoogieVariable> outputParameters = new List <BoogieVariable>(); //Generate the harness procedure declaration. BoogieProcedure harnessProcedureDeclaration = new BoogieProcedure(contractHarnessName, inputParameters, outputParameters); classTranslatorContext.getProgram.AddBoogieDeclaration(harnessProcedureDeclaration); List <BoogieVariable> localVariables = Conversion_Utility_Tool.CollectLocalVars(new List <ContractDefinition>() { contract }, classTranslatorContext); BoogieStmtList harnessBody = new BoogieStmtList(); //add dynamic type assumptions to harness body and generate constructor call fallback. harnessBody.AddStatement(BuildDynamicTypeAssumptions(contract)); GenerateConstructorCall(contract).ForEach(x => harnessBody.AddStatement(x)); //create a boogie implementation type that represents a harness with the above parameters BoogieImplementation harnessImpl = new BoogieImplementation(contractHarnessName, inputParameters, outputParameters, localVariables, harnessBody); //add the implementation as a declaration to the Boogie Program classTranslatorContext.getProgram.AddBoogieDeclaration(harnessImpl); }
/** * Iterates through contract set, filters functions and events from base contracts and adds them to AST_Handler instance */ public void filterFunctionsAndEvents() { List <ContractDefinition> contractSet = new List <ContractDefinition>(classTranslatorContext.ContractDefinitionsMap); foreach (ContractDefinition indexContract in contractSet) { // create a localised list of integer values containi List <int> baseContractSet = new List <int>(indexContract.LinearBaseContracts); //for each base contract, return its respective function and event definitiosn and add them to the Handler context. foreach (int i in baseContractSet) { //return the base contract at index i ContractDefinition baseContract = classTranslatorContext.retrieveASTNodethroughID(i) as ContractDefinition; if (baseContract != null) { //loop through function defs hashset and for each functionDefinition, compute //the function signature and add the function to the AST_Handler instance. foreach (FunctionDefinition function in classTranslatorContext.returnFunctionDefs(baseContract)) { string functionSignature = Conversion_Utility_Tool.ComputeFunctionSignature(function); if (classTranslatorContext != null) { classTranslatorContext.AddFunctionToDynamicType( Conversion_Utility_Tool.ComputeFunctionSignature(function), //Computed signature of function indexContract, //contract for which function will be added function); //Function be added } } foreach (EventDefinition singleEvent in classTranslatorContext.retrieveEventDefinitionsUsingContract(baseContract)) { //if the translator context is not null then add the single event to the contract via addEventToContract if (classTranslatorContext != null) { classTranslatorContext.InsertEventInContract(indexContract, singleEvent); } } //Compute Visible functions in existing function declaration foreach (string funcSig in classTranslatorContext.SignatureFunctionMap.Keys) { foreach (ContractDefinition tempContract in classTranslatorContext.SignatureFunctionMap[funcSig].Keys) { FunctionDefinition funcDef = classTranslatorContext.SignatureFunctionMap[funcSig][tempContract]; classTranslatorContext.AddVisibleFunctionToContract(funcDef, tempContract); } } } } } }
private void GenerateStructConstructors(ContractDefinition contract, StructDefinition structDefn) { // generate the internal one without base constructors string procName = structDefn.CanonicalName + "_ctor"; List <BoogieVariable> inParams = new List <BoogieVariable>(); inParams.AddRange(Conversion_Utility_Tool.GetDefaultInParams()); foreach (var member in structDefn.Members) { Debug.Assert(!member.TypeDescriptions.IsStruct(), "Do no handle nested structs yet!"); var formalType = Conversion_Utility_Tool.GetBoogieTypeFromSolidityTypeName(member.TypeName); var formalName = member.Name; inParams.Add(new BoogieFormalParam(new BoogieTypedIdent(formalName, formalType))); } List <BoogieVariable> outParams = new List <BoogieVariable>(); List <BoogieAttribute> attributes = new List <BoogieAttribute>(); if (Flags_HelperClass.GenerateInlineAttributes) { attributes.Add(new BoogieAttribute("inline", 1)); } ; BoogieProcedure procedure = new BoogieProcedure(procName, inParams, outParams, attributes); context.getProgram.AddBoogieDeclaration(procedure); List <BoogieVariable> localVars = new List <BoogieVariable>(); BoogieStmtList procBody = new BoogieStmtList(); foreach (var member in structDefn.Members) { Debug.Assert(!member.TypeDescriptions.IsStruct(), "Do no handle nested structs yet!"); var mapName = member.Name + "_" + structDefn.CanonicalName; var formalName = member.Name; var mapSelectExpr = new BoogieMapSelect(new BoogieIdentifierExpr(mapName), new BoogieIdentifierExpr("this")); procBody.AddStatement(new BoogieAssignCmd(mapSelectExpr, new BoogieIdentifierExpr(member.Name))); } BoogieImplementation implementation = new BoogieImplementation(procName, inParams, outParams, localVars, procBody); context.getProgram.AddBoogieDeclaration(implementation); }
//Function to insert a function into the specified contract. public void InsertFunctionInContract(ContractDefinition contract, FunctionDefinition funcDef) { if (FunctionMapping.ContainsKey(contract) == false) { Debug.Assert(!FunctionSignatureMapping.ContainsKey(contract)); FunctionMapping[contract] = new HashSet <FunctionDefinition>(); FunctionSignatureMapping[contract] = new HashSet <string>(); } Debug.Assert(!FunctionMapping[contract].Contains(funcDef), $"Repeated function warning: {funcDef.Name}"); FunctionMapping[contract].Add(funcDef); string signature = Conversion_Utility_Tool.ComputeFunctionSignature(funcDef); FunctionSignatureMapping[contract].Add(signature); Debug.Assert(!FunctionToContractMap.ContainsKey(funcDef), $" Repeated function warning: {funcDef.Name}"); FunctionToContractMap[funcDef] = contract; }
//Function to generate constructor call and add IdentifierExpressions from contract users. private List <BoogieCmd> GenerateConstructorCall(ContractDefinition contract) { List <BoogieCmd> localStmtList = new List <BoogieCmd>(); string callee = Conversion_Utility_Tool.GetCanonicalConstructorName(contract); //Identify third part users of the conttract. //sender refers external party call. List <BoogieExpr> constructorCallInputs = new List <BoogieExpr>(); constructorCallInputs.Add(new BoogieIdentifierExpr("this")); constructorCallInputs.Add(new BoogieIdentifierExpr("msgsender_MSG")); constructorCallInputs.Add(new BoogieIdentifierExpr("msgvalue_MSG")); if (classTranslatorContext.checkConstructorExists(contract) == true) { FunctionDefinition constructor = classTranslatorContext.retrieveConstructor(contract); foreach (VariableDeclaration param in constructor.Parameters.Parameters) { string name = Conversion_Utility_Tool.GetCanonicalLocalVariableName(param, classTranslatorContext); constructorCallInputs.Add(new BoogieIdentifierExpr(name)); if (param.TypeName is ArrayTypeName) { localStmtList.Add(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } } } if (Flags_HelperClass.InstrumentGas) { Conversion_Utility_Tool.havocGas(localStmtList); } localStmtList.Add(new BoogieCallCmd(callee, constructorCallInputs, null)); return(localStmtList); }
/// <summary> /// generate a non-deterministic choice block to call every public visible functions except constructors /// /// </summary> /// <param name="contracts"></param> /// <param name="context"></param> /// <param name="callBackTarget">If non-null, this will be the msg.sender for calling back into the contracts</param> /// <returns></returns> public static BoogieIfCmd GenerateChoiceBlock(List <ContractDefinition> contracts, AST_Handler context, Tuple <string, string> callBackTarget = null) { BoogieIfCmd ifCmd = null; int j = 0; foreach (var contract in contracts) { if (contract.ContractKind != EnumContractKind.CONTRACT) { continue; } HashSet <FunctionDefinition> funcDefs = context.RetrieveVisibleFunctions(contract); List <FunctionDefinition> publicFuncDefs = new List <FunctionDefinition>(); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.ofConstructorType) { continue; } if (funcDef.ofFallBackType) { continue; //let us not call fallback directly in harness } if (funcDef.Visibility == EnumVisibility.PUBLIC || funcDef.Visibility == EnumVisibility.EXTERNAL) { publicFuncDefs.Add(funcDef); } } for (int i = publicFuncDefs.Count - 1; i >= 0; --i) { j++; BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("choice"), new BoogieLiteralExpr(j)); BoogieStmtList thenBody = new BoogieStmtList(); FunctionDefinition funcDef = publicFuncDefs[i]; string callee = Conversion_Utility_Tool.GetCanonicalFunctionName(funcDef, context); List <BoogieExpr> inputs = new List <BoogieExpr>() { // let us just call back into the calling contract callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item1) : new BoogieIdentifierExpr("this"), callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item2) : new BoogieIdentifierExpr("msgsender_MSG"), new BoogieIdentifierExpr("msgvalue_MSG"), }; var inpParamCount = 0; foreach (VariableDeclaration param in funcDef.Parameters.Parameters) { string name = $"__arg_{inpParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = Conversion_Utility_Tool.GetCanonicalLocalVariableName(param, context); } inputs.Add(new BoogieIdentifierExpr(name)); if (param.TypeName is ArrayTypeName array) { thenBody.AddStatement(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } } List <BoogieIdentifierExpr> outputs = new List <BoogieIdentifierExpr>(); var retParamCount = 0; foreach (VariableDeclaration param in funcDef.ReturnParameters.Parameters) { string name = $"__ret_{retParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = Conversion_Utility_Tool.GetCanonicalLocalVariableName(param, context); } outputs.Add(new BoogieIdentifierExpr(name)); } if (Flags_HelperClass.InstrumentGas) { havocGas(thenBody); } BoogieCallCmd callCmd = new BoogieCallCmd(callee, inputs, outputs); thenBody.AddStatement(callCmd); BoogieStmtList elseBody = ifCmd == null ? null : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } } return(ifCmd); }
public static List <BoogieVariable> CollectLocalVars(List <ContractDefinition> contracts, AST_Handler context) { Debug.Assert(contracts.Count > 0, "Internal exception: expecting at least one contract here"); List <BoogieVariable> localVars = new List <BoogieVariable>() { new BoogieLocalVariable(new BoogieTypedIdent("this", BoogieType.Ref)), new BoogieLocalVariable(new BoogieTypedIdent("msgsender_MSG", BoogieType.Ref)), new BoogieLocalVariable(new BoogieTypedIdent("msgvalue_MSG", BoogieType.Int)), new BoogieLocalVariable(new BoogieTypedIdent("choice", BoogieType.Int)), }; // use to remove duplicated variables by name HashSet <string> uniqueVarNames = new HashSet <string>() { "this", "msgsender_MSG", "msgvalue_MSG", "choice" }; foreach (var contract in contracts) { if (contract.ContractKind != EnumContractKind.CONTRACT) { continue; } // Consider all visible functions HashSet <FunctionDefinition> funcDefs = context.RetrieveVisibleFunctions(contract); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.Visibility == EnumVisibility.PUBLIC || funcDef.Visibility == EnumVisibility.EXTERNAL) { var inpParamCount = 0; foreach (VariableDeclaration param in funcDef.Parameters.Parameters) { string name = $"__arg_{inpParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = Conversion_Utility_Tool.GetCanonicalLocalVariableName(param, context); } if (!uniqueVarNames.Contains(name)) { BoogieType type = Conversion_Utility_Tool.GetBoogieTypeFromSolidityTypeName(param.TypeName); BoogieVariable localVar = new BoogieLocalVariable(new BoogieTypedIdent(name, type)); localVars.Add(localVar); uniqueVarNames.Add(name); } } var retParamCount = 0; foreach (VariableDeclaration param in funcDef.ReturnParameters.Parameters) { string name = $"__ret_{retParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = Conversion_Utility_Tool.GetCanonicalLocalVariableName(param, context); } if (!uniqueVarNames.Contains(name)) { BoogieType type = Conversion_Utility_Tool.GetBoogieTypeFromSolidityTypeName(param.TypeName); BoogieVariable localVar = new BoogieLocalVariable(new BoogieTypedIdent(name, type)); localVars.Add(localVar); uniqueVarNames.Add(name); } } } } } return(localVars); }