public void Generate() { // Collect Global Variables. HashSet <BoogieGlobalVariable> globals = new HashSet <BoogieGlobalVariable>(); foreach (var decl in context.Program.Declarations) { if (decl is BoogieGlobalVariable) { var g = (BoogieGlobalVariable)decl; if (mustHaveShadow(g.Name)) { globals.Add(g); } } } // Generate shadow state. foreach (var g in globals) { var varName = g.TypedIdent.Name; BoogieTypedIdent shadowGlobal = new BoogieTypedIdent("__tmp__" + varName, g.TypedIdent.Type); BoogieGlobalVariable shadowGlobalDecl = new BoogieGlobalVariable(shadowGlobal); context.Program.AddDeclaration(shadowGlobalDecl); shadowGlobals.Add(varName, shadowGlobalDecl); } // Duplicate and rename methods. Dictionary <string, BoogieImplementation> proceduresWithImpl = new Dictionary <string, BoogieImplementation>(); procsWiltImplNames = proceduresWithImpl.Keys; foreach (var decl in context.Program.Declarations) { if (decl is BoogieImplementation) { var boogieImpl = ((BoogieImplementation)decl); if (proceduresInProgram.ContainsKey(boogieImpl.Name)) { proceduresWithImpl.Add(boogieImpl.Name, boogieImpl); } } } Dictionary <string, BoogieProcedure> failProcedures = new Dictionary <string, BoogieProcedure>(); foreach (var implPair in proceduresWithImpl) { BoogieProcedure proc = proceduresInProgram[implPair.Key]; if (isPublic(proc) || isConstructor(proc.Name)) { // If public maintain original definition as the wrapper. BoogieProcedure successVersion = duplicateProcedure(proc, "success", true); //BoogieImplementation successImpl = duplicateImplementation(implPair.Value, "success"); context.Program.AddDeclaration(successVersion); //context.Program.AddDeclaration(successImpl); BoogieProcedure failVersion = duplicateProcedure(proc, "fail", true); context.Program.AddDeclaration(failVersion); // Use original name of the procedure. failProcedures.Add(implPair.Key, failVersion); } else if (!isHarnessProcudure(proc.Name)) { // Otherwise reuse original definition/impl as the "successful" method. BoogieProcedure failVersion = duplicateProcedure(proc, "fail"); context.Program.AddDeclaration(failVersion); // Use original name of the procedure. failProcedures.Add(implPair.Key, failVersion); // Reuse original node proc.Name = proc.Name + "__success"; implPair.Value.Name = implPair.Value.Name + "__success"; } } // Create implementations for failing methods. foreach (var failProcedurePair in failProcedures) { string originalProcName = failProcedurePair.Key; BoogieProcedure proc = failProcedurePair.Value; var originalImpl = proceduresWithImpl[originalProcName]; if (!originalProcName.Equals("send")) { context.Program.AddDeclaration(createFailImplementation(proc.Name, originalImpl)); context.Program.AddDeclaration(createSuccessImplementation(originalProcName + "__success", originalImpl)); } else { context.Program.AddDeclaration(CreateSendFail()); context.Program.AddDeclaration(CreateSendSucess()); } // Remove original implementation for non-public methods if (!isPublic(proceduresInProgram[originalProcName]) && !isConstructor(originalProcName)) { context.Program.Declarations.Remove(originalImpl); } } foreach (var implPair in proceduresWithImpl) { // Update non-public methods in harness methods if (isHarnessProcudure(implPair.Key)) { context.Program.AddDeclaration(createSuccessImplementation(implPair.Key, implPair.Value)); context.Program.Declarations.Remove(implPair.Value); } } // Create wrappers for public methods. foreach (var proc in proceduresInProgram.Values) { if (proceduresWithImpl.ContainsKey(proc.Name) && (isPublic(proc) || isConstructor(proc.Name))) { BoogieImplementation impl = proceduresWithImpl[proc.Name]; impl.StructuredStmts = new BoogieStmtList(); impl.LocalVars = new List <BoogieVariable>(); var exceptionVarName = "__exception"; var revertGlobalName = "revert"; impl.LocalVars.Add(new BoogieLocalVariable(new BoogieTypedIdent(exceptionVarName, BoogieType.Bool))); var stmtList = impl.StructuredStmts; stmtList.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr(exceptionVarName))); stmtList.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(revertGlobalName), new BoogieLiteralExpr(false))); // Call Successful version. BoogieStmtList successCallStmtList = new BoogieStmtList(); if (isPayable(proc)) { successCallStmtList.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var balnSender = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("msgsender_MSG")); var balnThis = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("this")); var msgVal = new BoogieIdentifierExpr("msgvalue_MSG"); //assume Balance[msg.sender] >= msg.value successCallStmtList.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, balnSender, msgVal))); //balance[msg.sender] = balance[msg.sender] - msg.value successCallStmtList.AddStatement(new BoogieAssignCmd(balnSender, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balnSender, msgVal))); //balance[this] = balance[this] + msg.value successCallStmtList.AddStatement(new BoogieAssignCmd(balnThis, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balnThis, msgVal))); successCallStmtList.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); } successCallStmtList.AddStatement(new BoogieCallCmd(impl.Name + "__success", impl.InParams.Select(inParam => (BoogieExpr) new BoogieIdentifierExpr(inParam.Name)).ToList(), impl.OutParams.Select(outParam => new BoogieIdentifierExpr(outParam.Name)).ToList())); BoogieExpr successAssumePred = new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, new BoogieIdentifierExpr(revertGlobalName)); if (context.TranslateFlags.InstrumentGas) { successAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, successAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } successCallStmtList.AddStatement(new BoogieAssumeCmd(successAssumePred)); // Call fail version. BoogieStmtList failCallStmtList = new BoogieStmtList(); // Write global variables to temps foreach (var shadowGlobalPair in shadowGlobals) { string origVarName = shadowGlobalPair.Key; string shadowName = shadowGlobalPair.Value.Name; failCallStmtList.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(shadowName), new BoogieIdentifierExpr(origVarName))); } if (isPayable(proc)) { failCallStmtList.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var balnSender = new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), new BoogieIdentifierExpr("msgsender_MSG")); var balnThis = new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), new BoogieIdentifierExpr("this")); var msgVal = new BoogieIdentifierExpr("msgvalue_MSG"); //assume Balance[msg.sender] >= msg.value failCallStmtList.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, balnSender, msgVal))); //balance[msg.sender] = balance[msg.sender] - msg.value failCallStmtList.AddStatement(new BoogieAssignCmd(balnSender, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balnSender, msgVal))); //balance[this] = balance[this] + msg.value failCallStmtList.AddStatement(new BoogieAssignCmd(balnThis, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balnThis, msgVal))); failCallStmtList.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); } failCallStmtList.AddStatement(new BoogieCallCmd(impl.Name + "__fail", impl.InParams.Select(inParam => (BoogieExpr) new BoogieIdentifierExpr(inParam.Name)).ToList(), impl.OutParams.Select(outParam => new BoogieIdentifierExpr(outParam.Name)).ToList())); BoogieExpr failAssumePred = new BoogieIdentifierExpr(revertGlobalName); if (context.TranslateFlags.InstrumentGas) { failAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.OR, failAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } failCallStmtList.AddStatement(new BoogieAssumeCmd(failAssumePred)); stmtList.AddStatement(new BoogieIfCmd(new BoogieIdentifierExpr(exceptionVarName), failCallStmtList, successCallStmtList)); } } }
private BoogieImplementation CreateSendSucess() { // send__success(from: Ref, to: Ref, amt: uint) returns (success: boolean) // { // var __exception: bool; // havoc __exception; // // if(__exception) // { // //set tmps // if ((__tmp__Balance[from]) >= (amt)) { // call FallbackDispatch__fail(from, to, amt); // } // // success := false; // assume(__revert); // // revert := false; // } // else { // if ((Balance[from]) >= (amt)) { // call FallbackDispatch__success(from, to, amt); // success := true; // } else { // success := false; // } // // assume(!(__revert)); // } // } List <BoogieVariable> inParams = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("from", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("to", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("amount", BoogieType.Int)) }; List <BoogieVariable> outParms = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("success", BoogieType.Bool)) }; List <BoogieVariable> locals = new List <BoogieVariable>() { new BoogieLocalVariable(new BoogieTypedIdent("__exception", BoogieType.Bool)) }; var fromId = new BoogieIdentifierExpr("from"); var toId = new BoogieIdentifierExpr("to"); var amtId = new BoogieIdentifierExpr("amount"); var successId = new BoogieIdentifierExpr("success"); var revertId = new BoogieIdentifierExpr("revert"); var exceptionId = new BoogieIdentifierExpr("__exception"); BoogieStmtList body = new BoogieStmtList(); body.AddStatement(new BoogieHavocCmd(exceptionId)); BoogieStmtList exceptionCase = new BoogieStmtList(); foreach (var shadowGlobalPair in shadowGlobals) { string origVarName = shadowGlobalPair.Key; string shadowName = shadowGlobalPair.Value.Name; exceptionCase.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(shadowName), new BoogieIdentifierExpr(origVarName))); } var checkTmpBalGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), fromId), amtId); BoogieStmtList exceptionThen = new BoogieStmtList(); exceptionThen.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var exBalFrom = new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), new BoogieIdentifierExpr(inParams[0].Name)); var exBalTo = new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), new BoogieIdentifierExpr(inParams[1].Name)); var exMsgVal = new BoogieIdentifierExpr(inParams[2].Name); //balance[msg.sender] = balance[msg.sender] - msg.value exceptionThen.AddStatement(new BoogieAssignCmd(exBalFrom, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, exBalFrom, exMsgVal))); //balance[this] = balance[this] + msg.value exceptionThen.AddStatement(new BoogieAssignCmd(exBalTo, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, exBalTo, exMsgVal))); exceptionThen.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); var callFailDispatch = new BoogieCallCmd("FallbackDispatch__fail", new List <BoogieExpr>() { fromId, toId, amtId }, null); exceptionThen.AddStatement(callFailDispatch); exceptionCase.AddStatement(new BoogieIfCmd(checkTmpBalGuard, exceptionThen, null)); exceptionCase.AddStatement(new BoogieAssignCmd(successId, new BoogieLiteralExpr(false))); BoogieExpr failAssumePred = revertId; if (context.TranslateFlags.InstrumentGas) { failAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.OR, failAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } exceptionCase.AddStatement(new BoogieAssumeCmd(failAssumePred)); exceptionCase.AddStatement(new BoogieAssignCmd(revertId, new BoogieLiteralExpr(false))); var successCase = new BoogieStmtList(); var checkBalGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), fromId), amtId); var successCaseStmts = new BoogieStmtList(); successCaseStmts.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var balFrom = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr(inParams[0].Name)); var balTo = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr(inParams[1].Name)); var msgVal = new BoogieIdentifierExpr(inParams[2].Name); //balance[msg.sender] = balance[msg.sender] - msg.value successCaseStmts.AddStatement(new BoogieAssignCmd(balFrom, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balFrom, msgVal))); //balance[this] = balance[this] + msg.value successCaseStmts.AddStatement(new BoogieAssignCmd(balTo, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balTo, msgVal))); successCaseStmts.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); var callSuccessDispatch = new BoogieCallCmd("FallbackDispatch__success", new List <BoogieExpr>() { fromId, toId, amtId }, null); successCaseStmts.AddStatement(callSuccessDispatch); successCaseStmts.AddStatement(new BoogieAssignCmd(successId, new BoogieLiteralExpr(true))); successCase.AddStatement(new BoogieIfCmd(checkBalGuard, successCaseStmts, BoogieStmtList.MakeSingletonStmtList(new BoogieAssignCmd(successId, new BoogieLiteralExpr(false))))); BoogieExpr successAssumePred = new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, revertId); if (context.TranslateFlags.InstrumentGas) { successAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, successAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } successCase.AddStatement(new BoogieAssumeCmd(successAssumePred)); body.AddStatement(new BoogieIfCmd(exceptionId, exceptionCase, successCase)); return(new BoogieImplementation("send__success", inParams, outParms, locals, body)); }
private List <BoogieCmd> GenerateConstructorCall(ContractDefinition contract) { List <BoogieCmd> localStmtList = new List <BoogieCmd>(); string callee = TransUtils.GetCanonicalConstructorName(contract); List <BoogieExpr> inputs = new List <BoogieExpr>() { new BoogieIdentifierExpr("this"), new BoogieIdentifierExpr("msgsender_MSG"), new BoogieIdentifierExpr("msgvalue_MSG"), }; if (context.IsConstructorDefined(contract)) { FunctionDefinition ctor = context.GetConstructorByContract(contract); if (ctor.StateMutability.Equals(EnumStateMutability.PAYABLE)) { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); localStmtList.Add(new BoogieAssumeCmd(assumeExpr)); localStmtList.Add(new BoogieCommentCmd("---- Logic for payable function START ")); var balnSender = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("msgsender_MSG")); var balnThis = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("this")); var msgVal = new BoogieIdentifierExpr("msgvalue_MSG"); //assume Balance[msg.sender] >= msg.value localStmtList.Add(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, balnSender, msgVal))); //balance[msg.sender] = balance[msg.sender] - msg.value localStmtList.Add(new BoogieAssignCmd(balnSender, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balnSender, msgVal))); //balance[this] = balance[this] + msg.value localStmtList.Add(new BoogieAssignCmd(balnThis, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balnThis, msgVal))); localStmtList.Add(new BoogieCommentCmd("---- Logic for payable function END ")); } else { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); localStmtList.Add(new BoogieAssumeCmd(assumeExpr)); } foreach (VariableDeclaration param in ctor.Parameters.Parameters) { string name = TransUtils.GetCanonicalLocalVariableName(param, context); inputs.Add(new BoogieIdentifierExpr(name)); if (param.TypeName is ArrayTypeName array) { localStmtList.Add(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } } } else { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); localStmtList.Add(new BoogieAssumeCmd(assumeExpr)); } if (context.TranslateFlags.InstrumentGas) { var gasVar = new BoogieIdentifierExpr("gas"); localStmtList.Add(new BoogieAssignCmd(gasVar, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, gasVar, new BoogieLiteralExpr(TranslatorContext.CREATE_GAS_COST)))); } localStmtList.Add(new BoogieCallCmd(callee, inputs, null)); return(localStmtList); }
private BoogieStmtList GenerateBody(List <BoogieVariable> inParams) { // // foreach contract C that is not Lib/VeriSol // if (DT[this] == C) // if C has a fallback f // call ret := fallBack_C(this=to, sender=from, msg.value) // else // assume msg.value == 0; // else // call fallBack_unknownType(from, to, msg.value) BoogieIfCmd ifCmd = null; Debug.Assert(context.ContractDefinitions.Count >= 1, "There should be at least one contract"); List <BoogieExpr> arguments = new List <BoogieExpr>() { new BoogieIdentifierExpr(inParams[1].Name), new BoogieIdentifierExpr(inParams[0].Name), new BoogieIdentifierExpr(inParams[2].Name) }; List <BoogieIdentifierExpr> outParams = new List <BoogieIdentifierExpr>(); BoogieStmtList noMatchCase = BoogieStmtList.MakeSingletonStmtList( new BoogieCallCmd("Fallback_UnknownType", arguments, outParams)); foreach (var contract in context.ContractDefinitions) { if (contract.ContractKind == EnumContractKind.LIBRARY) { continue; } FunctionDefinition function = context.ContractToFallbackMap.ContainsKey(contract) ? context.ContractToFallbackMap[contract] : null; BoogieExpr lhs = new BoogieMapSelect(new BoogieIdentifierExpr("DType"), new BoogieIdentifierExpr(inParams[1].Name)); BoogieExpr rhs = new BoogieIdentifierExpr(contract.Name); BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, lhs, rhs); BoogieStmtList thenBody = null; if (function != null) { string callee = TransUtils.GetCanonicalFunctionName(function, context); thenBody = BoogieStmtList.MakeSingletonStmtList(new BoogieCallCmd(callee, arguments, outParams)); } else { // No fallback means not payable (amount == 0) thenBody = BoogieStmtList.MakeSingletonStmtList( new BoogieAssumeCmd( new BoogieBinaryOperation( BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr(inParams[2].Name), new BoogieLiteralExpr(BigInteger.Zero))) ); } BoogieStmtList elseBody = ifCmd == null ? noMatchCase : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } return(BoogieStmtList.MakeSingletonStmtList(ifCmd)); }
/// <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, TranslatorContext 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.GetVisibleFunctionsByContract(contract); List <FunctionDefinition> publicFuncDefs = new List <FunctionDefinition>(); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.IsConstructor) { continue; } if (funcDef.IsFallback) { 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 = TransUtils.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 = TransUtils.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 = TransUtils.GetCanonicalLocalVariableName(param, context); } outputs.Add(new BoogieIdentifierExpr(name)); } if (context.TranslateFlags.InstrumentGas) { var gasVar = new BoogieIdentifierExpr("gas"); thenBody.AddStatement(new BoogieAssignCmd(gasVar, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, gasVar, new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)))); } 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 Tuple <BoogieIfCmd, int> GeneratePartialChoiceBlock(List <ContractDefinition> contracts, TranslatorContext context, BoogieExpr thisExpr, int startingPoint, bool canRevert, BoogieIfCmd alternatives = null, Tuple <string, string> callBackTarget = null) { BoogieIfCmd ifCmd = alternatives; int j = startingPoint; foreach (var contract in contracts) { if (contract.ContractKind != EnumContractKind.CONTRACT) { continue; } HashSet <FunctionDefinition> funcDefs = context.GetVisibleFunctionsByContract(contract); List <FunctionDefinition> publicFuncDefs = new List <FunctionDefinition>(); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.IsConstructor) { continue; } if (funcDef.IsFallback) { continue; //let us not call fallback directly in harness } if (context.TranslateFlags.PerformFunctionSlice && !context.TranslateFlags.SliceFunctions.Contains(funcDef)) { continue; } 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 = TransUtils.GetCanonicalFunctionName(funcDef, context); List <BoogieExpr> inputs = new List <BoogieExpr>() { // let us just call back into the calling contract callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item1) : thisExpr, 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 = TransUtils.GetCanonicalLocalVariableName(param, context); } BoogieIdentifierExpr boogieVar = new BoogieIdentifierExpr(name); inputs.Add(boogieVar); if (param.TypeName is ArrayTypeName array) { thenBody.AddStatement(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } thenBody.AppendStmtList(constrainVarValues(context, param, boogieVar)); } 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 = TransUtils.GetCanonicalLocalVariableName(param, context); } outputs.Add(new BoogieIdentifierExpr(name)); } if (funcDef.StateMutability.Equals(EnumStateMutability.PAYABLE)) { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); thenBody.AddStatement(new BoogieAssumeCmd(assumeExpr)); if (!canRevert) { thenBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var balnSender = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("msgsender_MSG")); var balnThis = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("this")); var msgVal = new BoogieIdentifierExpr("msgvalue_MSG"); //assume Balance[msg.sender] >= msg.value thenBody.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, balnSender, msgVal))); //balance[msg.sender] = balance[msg.sender] - msg.value thenBody.AddStatement(new BoogieAssignCmd(balnSender, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balnSender, msgVal))); //balance[this] = balance[this] + msg.value thenBody.AddStatement(new BoogieAssignCmd(balnThis, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balnThis, msgVal))); thenBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); } } else { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); thenBody.AddStatement(new BoogieAssumeCmd(assumeExpr)); } BoogieCallCmd callCmd = new BoogieCallCmd(callee, inputs, outputs); thenBody.AddStatement(callCmd); if (context.TranslateFlags.InstrumentGas) { var gasVar = new BoogieIdentifierExpr("gas"); BoogieBinaryOperation gasGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, gasVar, new BoogieLiteralExpr(BigInteger.Zero)); BoogieIfCmd ifExpr = new BoogieIfCmd(gasGuard, thenBody, null); thenBody = new BoogieStmtList(); //thenBody.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, gasVar, new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)))); thenBody.AddStatement(new BoogieAssignCmd(gasVar, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, gasVar, new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)))); thenBody.AddStatement(ifExpr); } BoogieStmtList elseBody = ifCmd == null ? null : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } } return(new Tuple <BoogieIfCmd, int>(ifCmd, j)); }
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); }