-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Solidity State Corpus Study #295
base: master
Are you sure you want to change the base?
Changes from all commits
fa38d24
7bda3a9
62d20c5
bc9fd3b
d42ab05
08f3591
a772970
aef81d6
7a529a5
f68168e
8bcb137
ef0d642
1c22d9c
5f34be0
9bd768d
97d3bab
583be07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
The corpus was gathered using the Google BigData query found in https://arxiv.org/pdf/1910.10601.pdf. In order to run smaller versions, the query size was cut down to 1000 and 10000 for the small and medium corpus respectively. | ||
The small corpus was then filtered for addresses that had code in a .sol format that could be compiled with solc. |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
0xdac17f958d2ee523a2206206994597c13d831ec7 | ||
0x8d12a197cb00d4747a1fe03395095ce2a5cc6819 | ||
0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208 | ||
0x06012c8cf97bead5deae237070f9587f8e7a266d | ||
0xd1ceeeeee83f8bcf3bedad437202b6154e9f5405 | ||
0xf230b790e05390fc8295f4d3f60332c93bed42e2 | ||
0xd26114cd6ee289accf82350c8d8487fedb8a0c07 | ||
0xa3c1e324ca1ce40db73ed6026c4a177f099b5770 | ||
0x8e766f57f7d16ca50b4a0b90b88f6468a09b0439 | ||
0x6090a6e47849629b7245dfa1ca21d94cd15878ef | ||
0x0d8775f648430679a709e98d2b0cb6250d2887ef | ||
0xa15c7ebe1f07caf6bff097d8a589fb8ac49ae5b3 | ||
0xb1690c08e213a35ed9bab7b318de14420fb57d8c | ||
0x39755357759ce0d7f32dc8dc45414cca409ae24e | ||
0x74fd51a98a4a1ecbef8cc43be801cce630e260bd | ||
0x1f0480a66883de97d2b054929252aae8f664c15c | ||
0x8a88f04e0c905054d2f33b26bb3a46d7091a039a |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
0x8fdcc30eda7e94f1c12ce0280df6cd531e8365c5 | ||
0x0e50e6d6bb434938d8fe670a2d7a14cd128eb50f | ||
0x21ab6c9fac80c59d401b37cb43f81ea9dde7fe34 | ||
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 | ||
0xb8c77482e45f1f44de1745f52c74426c631bdd52 | ||
0x93e682107d1e9defb0b5ee701c71707a4b2e46bc | ||
0x0d152b9ee87ebae179f64c067a966dd716c50742 | ||
0xd3ebdaea9aeac98de723f640bce4aa07e2e44192 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
To use these plugins with slither, first follow the instructions at https://github.com/crytic/slither/wiki/Developer-installation to set up the slither development environment. | ||
Then, create a symlink in <path-to-slither>/slither/slither/detectors to this directory and update all_detectors.py to include the detector names. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification | ||
from slither.core.expressions import * | ||
from functools import reduce | ||
from slither.core.declarations.solidity_variables import SOLIDITY_VARIABLES,SOLIDITY_VARIABLES_COMPOSED | ||
|
||
# Solidity variables that are used as state variables instead of | ||
# local variables, and thus must be explicitly checked for when | ||
# checking for state usage. | ||
SOLIDITY_VARIABLE_WHITELIST = ["now", "this", "block.number", "block.timestamp"] | ||
|
||
# This is a function used to check for state in multiple plugins, | ||
# and thus belongs on this level for easy code reuse. | ||
# | ||
# It takes a Solidity AST used inside of a conditional check, exp, | ||
# and traverses it to find all of the variables used in the check. | ||
# It converts the variables to strings and returns them in a set. | ||
def get_vars_used(exp) : | ||
if isinstance(exp, Identifier) : | ||
return {str(exp)} | ||
elif isinstance(exp, CallExpression) : | ||
vars = [get_vars_used(arg) for arg in exp.arguments] | ||
return reduce(lambda s,x : s.union(x), vars, set()) | ||
elif isinstance(exp, UnaryOperation) : | ||
return get_vars_used(exp.expression) | ||
elif isinstance(exp, BinaryOperation) : | ||
return (get_vars_used(exp.expression_left) | ||
.union(get_vars_used(exp.expression_right)) | ||
) | ||
elif isinstance(exp, Literal) : | ||
return set() | ||
elif isinstance(exp, IndexAccess) : | ||
return (get_vars_used(exp.expression_left) | ||
.union(get_vars_used(exp.expression_right)) | ||
) | ||
elif isinstance(exp, MemberAccess) : | ||
return {str(exp)} | ||
elif isinstance(exp, TupleExpression) : | ||
# There should be exactly one element in the tuple | ||
# (that is, they should act as parenthesis). | ||
# Comparing tuples for equality as a Solidity language feature | ||
# does not exist at the time of writing. | ||
return get_vars_used(exp.expressions[0]) | ||
return set() | ||
|
||
# Class implemented as a detector plugin for Slither. This detector detects, | ||
# for the given contracts, which contracts have state checks and | ||
# thus are stateful | ||
class HasState(AbstractDetector): | ||
|
||
STATEFUL_MESSAGE = "%s is stateful\n" | ||
|
||
# Variables declared for use in Slither | ||
ARGUMENT = 'hasstate' | ||
HELP = 'Help printed by slither' | ||
IMPACT = DetectorClassification.HIGH | ||
CONFIDENCE = DetectorClassification.HIGH | ||
|
||
WIKI = 'STATE TEST' | ||
|
||
WIKI_TITLE = 'TODO' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO? |
||
WIKI_DESCRIPTION = 'Detects whether or not a contract is stateful' | ||
WIKI_EXPLOIT_SCENARIO = ''' | ||
contract Pausable { | ||
event Pause(); | ||
event Unpause(); | ||
|
||
bool public paused = false; | ||
|
||
modifier whenNotPaused() { | ||
require(!paused); | ||
_; | ||
} | ||
|
||
modifier whenPaused { | ||
require(paused); | ||
_; | ||
} | ||
|
||
function pause() whenNotPaused returns (bool) { | ||
paused = true; | ||
Pause(); | ||
return true; | ||
} | ||
|
||
function unpause() whenPaused returns (bool) { | ||
paused = false; | ||
Unpause(); | ||
return true; | ||
} | ||
} | ||
|
||
In the above contract, there are two states checks, | ||
"require(paused)" and "require(!paused)". This contract is | ||
therefore stateful, and the detector will print out: | ||
%s | ||
''' % (STATEFUL_MESSAGE % "Pausable") | ||
|
||
WIKI_RECOMMENDATION = 'This is just a check, it does not indicate an error' | ||
|
||
# Checks if any contracts that contract inherits were already determined | ||
# to be stateful. Returns the truth value of that check. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if we haven't processed those contracts yet? Does Slither process in order of the inheritance hierarchy? |
||
def inherited_state(self, contract, stateful) : | ||
inherited = [str(c) for c in contract.inheritance] | ||
return bool([elem for elem in inherited if elem in stateful]) | ||
|
||
# Checks if the node makes a stateful check, and gives the result of | ||
# that check | ||
def is_stateful_node(self, node, state_vars) : | ||
str_vars = [str(sv) for sv in state_vars] | ||
constant_vars = [str(sv) for sv in state_vars if sv.is_constant] | ||
nonconstant_vars = [str(sv) for sv in state_vars if not sv.is_constant] | ||
argument = None | ||
if node.contains_require_or_assert() : | ||
#require and assert both only have one argument. | ||
argument = node.expression.arguments[0] | ||
elif node.contains_if() : | ||
argument = node.expression | ||
|
||
if argument : | ||
vars = get_vars_used(argument) | ||
uses_state = False | ||
for var in vars : | ||
if not (var in str_vars or var in SOLIDITY_VARIABLE_WHITELIST) : | ||
return False | ||
elif var in nonconstant_vars : | ||
uses_state = True | ||
return uses_state | ||
|
||
return False | ||
|
||
# Checks if the function has a stateful check, returns the result of that check | ||
def is_stateful_function(self, func, state_vars) : | ||
nodes = list(map(lambda n : self.is_stateful_node(n, state_vars), func.nodes)) | ||
return True in nodes | ||
|
||
# Checks if the contract has a function or modifier that makes a stateful check. | ||
def is_stateful_contract(self, contract) : | ||
state_vars = [sv for sv in contract.state_variables] | ||
functions = list(map(lambda f : self.is_stateful_function(f, state_vars), contract.modifiers + contract.functions)) | ||
return True in functions | ||
|
||
# Function called by Slither framework. Checks all contracts in scope of | ||
# the detector and gives the result of the check on those contracts. | ||
def _detect(self): | ||
stateful_contracts = [] | ||
for c in self.contracts : | ||
if self.is_stateful_contract(c) or self.inherited_state(c, stateful_contracts): | ||
stateful_contracts.append(c.name) | ||
|
||
stateful_contracts = [self.STATEFUL_MESSAGE % sc for sc in stateful_contracts] | ||
if stateful_contracts : | ||
return [self.generate_result(stateful_contracts)] | ||
return [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pycache files appear to be derived binaries; remove them from the PR. You can add them to .gitignore.