public static string GetCanonicalFunctionName(FunctionDefinition funcDef, TranslatorContext context) { ContractDefinition contract = context.GetContractByFunction(funcDef); string paramStr = ""; if (funcDef.Parameters != null) { foreach (VariableDeclaration paramDecl in funcDef.Parameters.Parameters) { String typeStr = ""; if (paramDecl.TypeName is Mapping map) { typeStr = "map" + map.KeyType.ToString(); } else if (paramDecl.TypeName is UserDefinedTypeName userDef) { typeStr = userDef.Name; } else if (paramDecl.TypeName is ArrayTypeName arr) { typeStr = "arr"; } else { typeStr = paramDecl.TypeName.ToString().Replace(" ", ""); } paramStr = $"{paramStr}~{typeStr}"; } } return($"{funcDef.Name}{paramStr}_{contract.Name}"); //return funcDef.Name + "_" + contract.Name; }
public static bool IsUsingBasedLibraryCall(TranslatorContext context, ContractDefinition curContract, MemberAccess memberAccess) { // since we only permit "using A for B" for non-contract types // this is sufficient, but not necessary in general since non // contracts (including libraries) do not have support methods return(GetUsedLibrary(context, curContract, memberAccess) != null); }
public static bool IsExternalFunctionCall(TranslatorContext context, FunctionCall node) { if (node.Expression is MemberAccess memberAccess) { if (memberAccess.Expression is Identifier identifier) { if (identifier.Name == "this") { return(true); } if (identifier.Name == "super") { return(true); } if (!context.HasASTNodeId(identifier.ReferencedDeclaration)) { return(true); } var contract = context.GetASTNodeById(identifier.ReferencedDeclaration) as ContractDefinition; if (contract == null) { return(true); } } else if (memberAccess.Expression is MemberAccess structSelect) { //a.b.c.foo(...) //TODO: do we want to check that the contract the struct variable is declared // is not in the "context"? Why this isn't done for IndexAccess? return(true); } else if (memberAccess.Expression.ToString().Equals("msg.sender")) { // calls can be of the form "msg.sender.call()" or "msg.sender.send()" or "msg.sender.transfer()" return(true); } else if (memberAccess.Expression is FunctionCall) { // TODO: example? return(true); } else if (memberAccess.Expression is IndexAccess) { //a[i].foo(..) return(true); } else if (memberAccess.Expression is TupleExpression) { return(true); } } return(false); }
public static bool IsStaticDispatching(TranslatorContext context, FunctionCall node) { if (node.Expression is MemberAccess memberAccess) { if (memberAccess.Expression is Identifier ident) { if (context.GetASTNodeById(ident.ReferencedDeclaration) is ContractDefinition) { return(true); } } } return(false); }
public static ContractDefinition GetStaticDispatchingContract(TranslatorContext context, FunctionCall node) { VeriSolAssert(node.Expression is MemberAccess); MemberAccess memberAccess = node.Expression as MemberAccess; Identifier contractId = memberAccess.Expression as Identifier; VeriSolAssert(contractId != null, $"Unknown contract name: {memberAccess.Expression}"); ContractDefinition contract = context.GetASTNodeById(contractId.ReferencedDeclaration) as ContractDefinition; VeriSolAssert(contract != null); return(contract); }
public static ContractDefinition IsLibraryFunctionCall(TranslatorContext context, FunctionCall node) { if (node.Expression is MemberAccess memberAccess) { if (memberAccess.Expression is Identifier identifier) { var contract = context.GetASTNodeById(identifier.ReferencedDeclaration) as ContractDefinition; // a Library is treated as an external function call // we need to do it here as the Lib.Foo, Lib is not an expression but name of a contract if (contract.ContractKind == EnumContractKind.LIBRARY) { return(contract); } } } return(null); }
public static string InferFunctionSignature(TranslatorContext context, FunctionCall node, bool forceNameLookup = false) { Debug.Assert(node.Arguments != null); if (!forceNameLookup && node.Expression is MemberAccess memberAccess) { Debug.Assert(memberAccess.ReferencedDeclaration != null); FunctionDefinition function = context.GetASTNodeById(memberAccess.ReferencedDeclaration.Value) as FunctionDefinition; Debug.Assert(function != null, $"Could not find function {node.ToString()}"); StringBuilder builder = new StringBuilder(); builder.Append(function.Name).Append("("); if (function.Parameters.Parameters != null && function.Parameters.Parameters.Count > 0) { foreach (VariableDeclaration varDecl in function.Parameters.Parameters) { //builder.Append(varDecl.TypeDescriptions.TypeString).Append(", "); builder.Append(InferTypeFromTypeString(varDecl.TypeDescriptions.TypeString)).Append(", "); } builder.Length -= 2; } builder.Append(")"); return(builder.ToString()); } else { string functionName = GetFuncNameFromFuncCall(node); StringBuilder builder = new StringBuilder(); builder.Append(functionName).Append("("); if (node.Arguments.Count > 0) { foreach (Expression argument in node.Arguments) { string typeString = InferTypeFromTypeString(argument.TypeDescriptions.TypeString); builder.Append(typeString).Append(", "); } builder.Length -= 2; } builder.Append(")"); return(builder.ToString()); } }
public static BoogieStmtList constrainVarValues(TranslatorContext context, VariableDeclaration var, BoogieIdentifierExpr boogieVar) { BoogieStmtList stmts = new BoogieStmtList(); if (context.TranslateFlags.UseModularArithmetic) { if (var.TypeDescriptions.IsUintWSize(null, out uint uintSize)) { BigInteger maxUIntValue = (BigInteger)Math.Pow(2, uintSize); BoogieBinaryOperation lower = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, boogieVar, new BoogieLiteralExpr(BigInteger.Zero)); BoogieBinaryOperation upper = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, boogieVar, new BoogieLiteralExpr(maxUIntValue)); stmts.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, lower, upper))); } else if (var.TypeDescriptions.IsIntWSize(out uint intSize)) { BigInteger maxIntValue = (BigInteger)Math.Pow(2, intSize); BoogieBinaryOperation lower = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, boogieVar, new BoogieLiteralExpr(-maxIntValue)); BoogieBinaryOperation upper = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, boogieVar, new BoogieLiteralExpr(maxIntValue)); stmts.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, lower, upper))); } } return(stmts); }
public static string GetCanonicalStateVariableName(VariableDeclaration varDecl, TranslatorContext context) { Debug.Assert(varDecl.StateVariable, $"{varDecl.Name} is not a state variable"); Dictionary <VariableDeclaration, ContractDefinition> varToContractMap = context.StateVarToContractMap; Debug.Assert(varToContractMap.ContainsKey(varDecl), $"Cannot find state variable: {varDecl.Name}"); return(varDecl.Name + "_" + varToContractMap[varDecl].Name); }
public FunctionEventCollector(TranslatorContext context) { this.context = context; }
public static string GetCanonicalVariableName(VariableDeclaration varDecl, TranslatorContext context) { return(varDecl.StateVariable ? GetCanonicalStateVariableName(varDecl, context) : GetCanonicalLocalVariableName(varDecl)); }
public HarnessGenerator(TranslatorContext context, Dictionary <string, List <BoogieExpr> > _contractInvariants) { this.context = context; this.contractInvariants = _contractInvariants; }
public GhostVarAndAxiomGenerator(TranslatorContext context) { this.context = context; }
// returns a map from integer id to an atomic Boogie predicate public static Dictionary <int, BoogieExpr> GenerateHoudiniVarMapping(ContractDefinition contract, TranslatorContext context) { Dictionary <int, BoogieExpr> ret = new Dictionary <int, BoogieExpr>(); HashSet <VariableDeclaration> stateVars = context.GetVisibleStateVarsByContract(contract); // collect all state variables of type address List <VariableDeclaration> addressVariables = new List <VariableDeclaration>(); foreach (VariableDeclaration stateVar in stateVars) { if (stateVar.TypeName is ElementaryTypeName elementaryType) { if (elementaryType.TypeDescriptions.TypeString.Equals("address") || elementaryType.TypeDescriptions.TypeString.Equals("address payable")) { addressVariables.Add(stateVar); } } } int id = 0; // equaility and disequality to null foreach (VariableDeclaration addressVar in addressVariables) { BoogieExpr lhs = GetBoogieExprOfStateVar(addressVar, context); BoogieExpr rhs = new BoogieIdentifierExpr("null"); BoogieExpr equality = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, lhs, rhs); ret[++id] = equality; BoogieExpr disequality = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.NEQ, lhs, rhs); ret[++id] = disequality; } // pair-wise equality and disequality for (int i = 0; i < addressVariables.Count; ++i) { BoogieExpr lhs = GetBoogieExprOfStateVar(addressVariables[i], context); for (int j = i + 1; j < addressVariables.Count; ++j) { BoogieExpr rhs = GetBoogieExprOfStateVar(addressVariables[j], context); BoogieExpr equality = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, lhs, rhs); ret[++id] = equality; BoogieExpr disequality = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.NEQ, lhs, rhs); ret[++id] = disequality; } } // PrintHoudiniCandidateMap(ret); return(ret); }
public ERC20SpecGenerator(TranslatorContext context, AST solidityAST, String entryPoint) { this.context = context; this.solidityAST = solidityAST; varDecls = new Dictionary <string, VariableDeclaration>(); fnContracts = new Dictionary <string, ContractDefinition>(); otherVars = new List <VariableDeclaration>(); declToContractInd = new Dictionary <VariableDeclaration, int>(); foreach (ContractDefinition def in context.ContractDefinitions) { if (def.Name.Equals(entryPoint)) { entryContract = def; } } int contractInd = 0; foreach (int id in entryContract.LinearizedBaseContracts) { contractInd++; ContractDefinition contract = context.GetASTNodeById(id) as ContractDefinition; if (context.ContractToStateVarsMap.ContainsKey(contract)) { otherVars.AddRange(context.ContractToStateVarsMap[contract]); foreach (VariableDeclaration decl in context.ContractToStateVarsMap[contract]) { declToContractInd[decl] = contractInd; } } if (!context.ContractToFunctionsMap.ContainsKey(contract)) { continue; } HashSet <FunctionDefinition> fnDefs = context.ContractToFunctionsMap[contract]; foreach (FunctionDefinition fnDef in fnDefs) { if (ERC20fns.Contains(fnDef.Name) && !fnContracts.ContainsKey(fnDef.Name)) { fnContracts[fnDef.Name] = contract; } if (ERC20Vars.Contains(fnDef.Name) && !varDecls.ContainsKey(fnDef.Name)) { ReturnDeclarationFinder declFinder = new ReturnDeclarationFinder(context); VariableDeclaration decl = declFinder.findDecl(contract, fnDef); if (decl != null) { varDecls[fnDef.Name] = decl; } } } } foreach (VariableDeclaration decl in varDecls.Values) { otherVars.Remove(decl); } otherVars.RemoveAll(v => v.Constant); }
public ConstructorCollector(TranslatorContext context) { this.context = context; }
public ModifierCollector(TranslatorContext context) { this.context = context; }
public static Tuple <string, int> GenerateSourceInfoAnnotation(ASTNode node, TranslatorContext context) { return(Tuple.Create <string, int>(context.GetAbsoluteSourcePathOfASTNode(node), context.GetLineNumberOfASTNode(node))); }
public static string GetCanonicalFunctionName(FunctionDefinition funcDef, TranslatorContext context) { ContractDefinition contract = context.GetContractByFunction(funcDef); return(funcDef.Name + "_" + contract.Name); }
private static BoogieMapSelect GetBoogieExprOfStateVar(VariableDeclaration varDecl, TranslatorContext context) { string name = TransUtils.GetCanonicalStateVariableName(varDecl, context); BoogieMapSelect mapSelect = new BoogieMapSelect(new BoogieIdentifierExpr(name), new BoogieIdentifierExpr("this")); return(mapSelect); }
public StateVariableCollector(TranslatorContext context) { this.context = context; }
// set of method@contract pairs whose translatin is skipped public BoogieAST Translate(AST solidityAST, HashSet <Tuple <string, string> > ignoredMethods, TranslatorFlags _translatorFlags = null) { bool generateInlineAttributesInBpl = _translatorFlags.GenerateInlineAttributes; SourceUnitList sourceUnits = solidityAST.GetSourceUnits(); TranslatorContext context = new TranslatorContext(ignoredMethods, generateInlineAttributesInBpl, _translatorFlags); context.IdToNodeMap = solidityAST.GetIdToNodeMap(); context.SourceDirectory = solidityAST.SourceDirectory; // collect the absolute source path and line number for each AST node SourceInfoCollector sourceInfoCollector = new SourceInfoCollector(context); sourceUnits.Accept(sourceInfoCollector); // de-sugar the solidity AST // will modify the AST SolidityDesugaring desugaring = new SolidityDesugaring(context); sourceUnits.Accept(desugaring); // collect all contract definitions ContractCollector contractCollector = new ContractCollector(context); sourceUnits.Accept(contractCollector); // collect all sub types for each contract InheritanceCollector inheritanceCollector = new InheritanceCollector(context); inheritanceCollector.Collect(); // collect explicit state variables StateVariableCollector stateVariableCollector = new StateVariableCollector(context); sourceUnits.Accept(stateVariableCollector); // resolve state variable declarations and determine the visible ones for each contract StateVariableResolver stateVariableResolver = new StateVariableResolver(context); stateVariableResolver.Resolve(); // collect mappings and arrays MapArrayCollector mapArrayCollector = new MapArrayCollector(context); sourceUnits.Accept(mapArrayCollector); // collect constructor definitions ConstructorCollector constructorCollector = new ConstructorCollector(context); sourceUnits.Accept(constructorCollector); // collect explicit function and event definitions FunctionEventCollector functionEventCollector = new FunctionEventCollector(context); sourceUnits.Accept(functionEventCollector); // resolve function and event definitions and determine the actual definition for a dynamic type FunctionEventResolver functionEventResolver = new FunctionEventResolver(context); functionEventResolver.Resolve(); // add types, gobal ghost variables, and axioms GhostVarAndAxiomGenerator generator = new GhostVarAndAxiomGenerator(context); generator.Generate(); // collect modifiers information ModifierCollector modifierCollector = new ModifierCollector(context); sourceUnits.Accept(modifierCollector); // translate procedures ProcedureTranslator procTranslator = new ProcedureTranslator(context, generateInlineAttributesInBpl); sourceUnits.Accept(procTranslator); // generate fallbacks FallbackGenerator fallbackGenerator = new FallbackGenerator(context); fallbackGenerator.Generate(); // generate harness for each contract if (!context.TranslateFlags.NoHarness) { HarnessGenerator harnessGenerator = new HarnessGenerator(context, procTranslator.ContractInvariants); harnessGenerator.Generate(); } if (context.TranslateFlags.ModelReverts) { RevertLogicGenerator reverGenerator = new RevertLogicGenerator(context); reverGenerator.Generate(); } return(new BoogieAST(context.Program)); }
public static string InferFunctionSignature(TranslatorContext context, FunctionCall node) { Debug.Assert(node.Arguments != null); if (node.Expression is MemberAccess memberAccess) { Debug.Assert(memberAccess.ReferencedDeclaration != null); FunctionDefinition function = context.GetASTNodeById(memberAccess.ReferencedDeclaration.Value) as FunctionDefinition; Debug.Assert(function != null, $"Could not find function {node.ToString()}"); StringBuilder builder = new StringBuilder(); builder.Append(function.Name).Append("("); if (function.Parameters.Parameters != null && function.Parameters.Parameters.Count > 0) { foreach (VariableDeclaration varDecl in function.Parameters.Parameters) { builder.Append(varDecl.TypeDescriptions.TypeString).Append(", "); } builder.Length -= 2; } builder.Append(")"); return(builder.ToString()); } else { string functionName = GetFuncNameFromFunctionCall(node); StringBuilder builder = new StringBuilder(); builder.Append(functionName).Append("("); if (node.Arguments.Count > 0) { foreach (Expression argument in node.Arguments) { string typeString = argument.TypeDescriptions.TypeString; if (typeString.StartsWith("int_const")) { typeString = "int256"; } if (typeString.StartsWith("uint_const")) { typeString = "int256"; } if (typeString.StartsWith("string") || typeString.StartsWith("literal_string")) { typeString = "string"; } if (typeString.StartsWith("bytes ")) { typeString = "bytes"; //"bytes storage ref" } if (typeString.Contains(" memory")) //"struct Foo memory" { typeString = typeString.Substring(0, typeString.IndexOf(" memory")); } if (typeString.Contains(" storage")) { typeString = typeString.Substring(0, typeString.IndexOf(" storage")); } builder.Append(typeString).Append(", "); } builder.Length -= 2; } builder.Append(")"); return(builder.ToString()); } }
public static ContractDefinition GetUsedLibrary(TranslatorContext context, ContractDefinition curContract, MemberAccess memberAccess) { FunctionDefinition fnDef = context.GetASTNodeById(memberAccess.ReferencedDeclaration.Value) as FunctionDefinition; if (fnDef == null || !context.FunctionToContractMap.ContainsKey(fnDef)) { return(null); } ContractDefinition fnContract = context.GetContractByFunction(fnDef); Dictionary <ContractDefinition, UserDefinedTypeName> usingLibs = new Dictionary <ContractDefinition, UserDefinedTypeName>(); List <int> contractIds = new List <int>(); contractIds.Add(curContract.Id); contractIds.AddRange(curContract.LinearizedBaseContracts); foreach (int id in contractIds) { ContractDefinition baseContract = context.GetASTNodeById(id) as ContractDefinition; foreach (UserDefinedTypeName typeName in context.UsingMap[baseContract].Keys) { ContractDefinition libDef = context.GetASTNodeById(typeName.ReferencedDeclaration) as ContractDefinition; if (!usingLibs.ContainsKey(libDef)) { usingLibs[libDef] = typeName; } } } if (usingLibs.ContainsKey(fnContract)) { if (memberAccess.Expression.TypeDescriptions.IsContract() && !memberAccess.Expression.TypeDescriptions.IsArray()) { //search sub-types UserDefinedTypeName libType = usingLibs[fnContract]; String contractName = memberAccess.Expression.TypeDescriptions.TypeString.Split(" ")[1]; ContractDefinition contractDef = context.GetContractByName(contractName); HashSet <ContractDefinition> usedBy = context.UsingMap[curContract][libType].FindAll(t => t is UserDefinedTypeName u && context.GetASTNodeById(u.ReferencedDeclaration) is ContractDefinition).Select(c => context.GetASTNodeById(((UserDefinedTypeName)(c)) .ReferencedDeclaration) as ContractDefinition).ToHashSet(); bool usesLib = usedBy.Contains(contractDef); foreach (int id in contractDef.LinearizedBaseContracts) { ContractDefinition baseContract = context.GetASTNodeById(id) as ContractDefinition; if (usedBy.Contains(baseContract)) { usesLib = true; } } return(usesLib ? fnContract : null); } else { return(fnContract); } } return(null); }
public RevertLogicGenerator(TranslatorContext context) { this.context = context; this.constructorNames = context.ContractDefinitions.Select(c => TransUtils.GetCanonicalConstructorName(c)).ToHashSet(); proceduresInProgram = context.Program.Declarations.OfType <BoogieProcedure>().ToDictionary(procedure => procedure.Name); }
public FallbackGenerator(TranslatorContext _context) { context = _context; }
public ModifierCollector(TranslatorContext context) { this.context = context; this.localTranslator = new ProcedureTranslator(context); }
public ContractCollector(TranslatorContext context) { this.context = context; }
// set of method@contract pairs whose translatin is skipped public BoogieAST Translate(AST solidityAST, HashSet <Tuple <string, string> > ignoredMethods, bool generateInlineAttributesInBpl) { if (generateInlineAttributesInBpl) { Console.WriteLine($"Warning! Found /noInlineAttrs option...the generated Bpl file cannot be used for unbounded verification"); } SourceUnitList sourceUnits = solidityAST.GetSourceUnits(); TranslatorContext context = new TranslatorContext(ignoredMethods, generateInlineAttributesInBpl); context.IdToNodeMap = solidityAST.GetIdToNodeMap(); context.SourceDirectory = solidityAST.SourceDirectory; // collect the absolute source path and line number for each AST node SourceInfoCollector sourceInfoCollector = new SourceInfoCollector(context); sourceUnits.Accept(sourceInfoCollector); // de-sugar the solidity AST // will modify the AST SolidityDesugaring desugaring = new SolidityDesugaring(context); sourceUnits.Accept(desugaring); // collect all contract definitions ContractCollector contractCollector = new ContractCollector(context); sourceUnits.Accept(contractCollector); // collect all sub types for each contract InheritanceCollector inheritanceCollector = new InheritanceCollector(context); inheritanceCollector.Collect(); // collect explicit state variables StateVariableCollector stateVariableCollector = new StateVariableCollector(context); sourceUnits.Accept(stateVariableCollector); // resolve state variable declarations and determine the visible ones for each contract StateVariableResolver stateVariableResolver = new StateVariableResolver(context); stateVariableResolver.Resolve(); // collect mappings and arrays MapArrayCollector mapArrayCollector = new MapArrayCollector(context); sourceUnits.Accept(mapArrayCollector); // collect constructor definitions ConstructorCollector constructorCollector = new ConstructorCollector(context); sourceUnits.Accept(constructorCollector); // collect explicit function and event definitions FunctionEventCollector functionEventCollector = new FunctionEventCollector(context); sourceUnits.Accept(functionEventCollector); // resolve function and event definitions and determine the actual definition for a dynamic type FunctionEventResolver functionEventResolver = new FunctionEventResolver(context); functionEventResolver.Resolve(); // add types, gobal ghost variables, and axioms GhostVarAndAxiomGenerator generator = new GhostVarAndAxiomGenerator(context); generator.Generate(); // collect modifiers information ModifierCollector modifierCollector = new ModifierCollector(context); sourceUnits.Accept(modifierCollector); // translate procedures ProcedureTranslator procTranslator = new ProcedureTranslator(context, generateInlineAttributesInBpl); sourceUnits.Accept(procTranslator); // generate harness for each contract HarnessGenerator harnessGenerator = new HarnessGenerator(context); harnessGenerator.Generate(); return(new BoogieAST(context.Program)); }
public ReturnDeclarationFinder(TranslatorContext context) { this.context = context; retDecl = null; }