- The paper presents InvCon+, an invariant generation framework that combines dynamic inference with static verification for Solidity smart contracts.
- Key methodology includes using execution trace analysis, invariant templating, and iterative implication inference to validate specifications.
- Evaluation shows high recall (0.80) and 100% precise invariant results, improving security and eliminating vulnerabilities in smart contracts.
Automated Invariant Generation for Solidity Smart Contracts
Smart contracts operating on blockchain networks facilitate the management of financial assets and automate agreements among distrusting parties. Ensuring their correctness is challenging due to the lack of specifications. Program invariants, which are properties preserved during execution, can enhance specifications. This paper introduces InvCon+, an invariant generation framework for Solidity contracts, extending the existing InvCon tool. InvCon+ automatically produces verified contract invariants using dynamic inference and static verification, inferring more expressive invariants that capture richer semantic relations.
Background on Smart Contracts and Invariant Inference
Solidity smart contracts consist of state variables and functions. Contract execution is triggered by blockchain transactions, potentially altering state variables. Invariant inference techniques are categorized as static (e.g., Houdini) and dynamic (e.g., Daikon). Static inference identifies conditions holding for any execution, while dynamic inference identifies likely invariants for specific executions. This paper aims to mine contract-level and function-level invariant specifications.
Invariant Specification Language
The paper defines an invariant specification language for Solidity smart contracts (Figure 1). The language accommodates variables of integer, Boolean, address, and string types. Invariant predicates are expressed as logical or implication expressions. Specification statements include function-level pre/postcondition invariant predicates and contract-level invariant predicates.
(Figure 1)
Figure 1: The core grammar of the Solidity language, presenting the foundational elements such as variables, functions, statements, and expressions.
Invariant Generation Approach
The invariant generation algorithm takes a smart contract, a sequence of transactions, and invariant templates as input. It initializes sets for verified invariants, potential candidates, and execution traces. The algorithm processes transaction histories to extract execution traces, performs dynamic invariant detection to obtain likely and partially supported invariant candidates, and applies static inference to verify the invariants.
Implication invariant inference involves two procedures: #1{FindImplications} and #1{WeakenImplications}. The #1{FindImplications} procedure explores potential implication candidates from unverified likely invariants and partial invariant candidates. A Delete rule is applied to eliminate implications that do not adhere to data-flow and control-flow relationships. The #1{WeakenImplications} procedure derives a weaker set of implication candidates from unverified candidates, using inference rules to generate weaker implications by combining two unverified candidates.
The termination of the algorithm is ensured by the finite set of primitive invariant predicates. The loop involving implication candidates terminates because #1{WeakenImplications} consistently generates weaker candidates. Assuming n primitive invariant predicates are found, the loop finishes in no more than 2×n iterations.
Implementation of InvCon+
InvCon+ is an automated invariant detection tool comprising four modules: a data parser, a dynamic invariant detector, a modular invariant verifier and implication learner, and a suppressor.
- Data Parser: Decodes contract code and transaction histories to extract the execution trace set. It collects historical transactions, decodes function inputs based on the contract's ABI, and interprets transaction outputs according to the storage layout.
- Dynamic Invariant Detector: Generates likely and partially supported invariants. It employs customized invariant templates conforming to the specification language. It retains invariants refuted by certain transactions, as implications may still hold.
- Modular Invariant Verifier: Implements a Houdini-like algorithm to infer verified primitive invariants. It instruments the contracts with mined invariants, converts them into Boogie programs, and uses the VeriSol tool for verification.
- Suppressor: Simplifies results by removing redundant invariants. It uses the Z3 solver to determine if one invariant predicate can be deduced from another, retaining only the strongest predicates.
Evaluation of InvCon+
The evaluation addresses three research questions:
- RQ1: How effectively does InvCon+ generate invariants for smart contracts?
- RQ2: How does the length of transaction histories used affect the performance of InvCon+?
- RQ3: How effective are the invariants detected by InvCon+ in preventing real-world security attacks?
The experiments were conducted on real-world ERC20 and ERC721 contracts. Precision and Recall are used to measure the effectiveness of generated invariants.
InvCon+ achieves a high recall score (0.80) and generates approximately 46 invariants per contract, all verified. InvCon performs less favorably due to the limitations of its invariant detection engine. InvCon+ outperforms baseline tools by leveraging an algorithm capable of producing implication invariants, yielding 100% precise invariant results.
The static inference process consumes the majority of the time. Mutation testing on ERC20 contracts shows that non-ERC20 standard invariants eliminate nearly the entire set of killed mutants, suggesting that the generated invariants capture richer program semantics. Furthermore, combining invariant results from multiple ERC721 contracts significantly improves the overall recall rate.
The scale of transaction histories affects the invariant results of InvCon+, with longer histories empowering it to generate more comprehensive invariant specifications. \Cref{fig:invnumber} illustrates the number of verified invariants per contract corresponding to the use of different transaction history lengths. \Cref{fig:recall} presents the recall score of invariant results for varying transaction history lengths.
Figure 2: The averaged ERC20 recall score of the invariant results generated with different number of transactions, showing the relationship between the number of transactions and the recall score of invariant results.
InvCon+ can detect invariants useful for preventing real-world smart contract vulnerabilities. Enforcing invariants in contract executions may ensure the security and reliability of smart contracts.
Related work includes smart contract security analysis and invariant inference. Security analysis focuses on detecting contract vulnerabilities such as integer overflow/underflow, reentrancy, and dangerous delegatecall operations. Static analysis tools use control-flow, data-flow, or taint-flow analysis, while others use symbolic execution. Formal verification tools ensure the correctness of functional properties and workflow policy. Dynamic analyses perform random or model-based testing. Invariant inference techniques include static and dynamic approaches. ESC/Java is a static checking tool for Java programs. Daikon is a dynamic invariant detection tool. SolType is a type checking tool for Solidity smart contracts. Cider applies deep reinforcement learning to learn contract invariants.
InvCon+ implements a unified invariant generation framework for Solidity contracts encompassing techniques from dynamic detection and static inference.
Conclusion
The paper presents InvCon+, an invariant generation framework for Solidity smart contracts integrating dynamic invariant detection and static inference. InvCon+ devises an iterative process to repeat the generation and verification of implications. Evaluation on real-world contracts demonstrates that InvCon+ achieves good recall to recover common specifications. Experiments on mutation testing and vulnerable benchmark contracts show that the generated invariant specifications are effective in excluding program mistakes and making contracts secure from vulnerabilities.