示例#1
0
    def test_echidna_instrumentation(self):
        self.inorder_config.instrumentation.predicates = [
            'previously(b_called) -> c_called',
            'b_called -> since(c_called, a_called)'
        ]
        self.inorder_config.instrumentation.for_echidna = True
        self.inorder_config.verification.verisol.use = False

        proof_found, verisol_counterexample = self.inorder_veriman.analyze_contract(
            self.inorder_config, reuse_pre_process=True)

        # Restore test configs:
        self.inorder_config.instrumentation.for_echidna = False
        self.inorder_config.verification.verisol.use = True

        self.check_contract_compiles(self.inorder_veriman.contract_path)

        slither = Slither(self.inorder_veriman.contract_path)
        contract_info = slither.get_contract_from_name('InOrder')
        echidna_invariants = list(
            filter(lambda func: func.name.startswith('echidna_'),
                   contract_info.functions))

        self.assertEqual(len(echidna_invariants), 2)

        for invariant in echidna_invariants:
            self.assertEqual(invariant.return_type[0].name, 'bool')

        self.check_functions_with_asserts(self.inorder_veriman, [])

        os.remove(self.inorder_veriman.contract_path)
示例#2
0
    def test_inheritance(self):
        inheritance_config = TestVeriMan.get_test_config()
        inheritance_config.contract.path = os.path.dirname(
            os.path.abspath(__file__)) + '/Inheritance.sol'
        inheritance_config.contract.name = 'D'
        inheritance_config.instrumentation.predicates = [
            'a_var + b_var + c_var + d_var < 10', 'block.number > 10'
        ]
        inheritance_config.verification.verisol.use = False

        veriman = VeriMan()
        proof_found, verisol_counterexample = veriman.analyze_contract(
            inheritance_config)

        self.check_contract_compiles(veriman.contract_path)

        slither = Slither(veriman.contract_path)
        contract_info = slither.get_contract_from_name(
            inheritance_config.contract.name)

        expected_functions = set(
            list([
                'aFunction', 'toBeOverwritten', 'bFunction', 'withTheSameName',
                'callsC', 'dFunction', 'constructor'
            ]))

        found_functions = list(
            map(lambda func: func.name, contract_info.functions_declared))

        self.assertEqual(found_functions.count('withTheSameName'), 3)
        self.assertEqual(found_functions.count('toBeOverwritten'), 1)

        self.assertEqual(expected_functions, set(found_functions))

        os.remove(veriman.contract_path)
示例#3
0
def run(filename, contract_name):
    """Executes script"""

    # Init Slither
    slither = Slither(filename)

    # Get an instance of the contract to be analyzed
    contract = slither.get_contract_from_name(contract_name)
    if not contract:
        print(f"Contract {contract_name} not found")
        print(
            "Either you mispelled the contract's name or solc cannot compile the contract."
        )
        exit(-1)

    # Obtain all visible functions, filtering out any that comes from an interface contract
    visible_functions = get_visible_functions(
        get_implemented_functions(contract.functions))

    erc20_fx_matches = verify_signatures(visible_functions,
                                         ERC20_FX_SIGNATURES)

    print("== ERC20 functions definition ==")
    log_matches(erc20_fx_matches)

    print("\n== Custom modifiers ==")
    log_modifiers_per_function(verify_custom_modifiers(erc20_fx_matches))

    print("\n== ERC20 events ==")
    log_matches(verify_signatures(contract.events, ERC20_EVENT_SIGNATURES),
                log_return=False)
    log_event_per_function(
        verify_event_calls(erc20_fx_matches, ERC20_EVENT_BY_FX),
        ERC20_EVENT_BY_FX)

    print("\n== ERC20 getters ==")
    log_matches(
        verify_getters(contract.state_variables, visible_functions,
                       ERC20_GETTERS))

    print("\n== Allowance frontrunning mitigation ==")
    frontrun_fx_matches = verify_signatures(visible_functions,
                                            ALLOWANCE_FRONTRUN_FX_SIGNATURES)
    log_matches(frontrun_fx_matches)
    log_event_per_function(verify_event_calls(frontrun_fx_matches,
                                              ALLOWANCE_FRONTRUN_EVENT_BY_FX),
                           ALLOWANCE_FRONTRUN_EVENT_BY_FX,
                           must=False)

    print("\n== Balance check in approve function ==")
    approve_signature = ERC20_FX_SIGNATURES[1].to_string(with_return=False,
                                                         with_spaces=False)
    approve_function = contract.get_function_from_signature(approve_signature)
    is_checking_balance = any(
        checks_sender_balance_in_require(node)
        for node in approve_function.nodes)
    log_approve_checking_balance(is_checking_balance)
示例#4
0
    def pre_process_contract(self, contract_path, contract_name):
        self.contract_path = contract_path
        self.contract_name = contract_name

        slither = Slither(self.contract_path)
        self.contract_info = slither.get_contract_from_name(self.contract_name)
        if self.contract_info is None:
            raise Exception('Check config file for contract name')

        with open(self.contract_path) as contract_file:
            self.contract_lines = contract_file.readlines()

        self.__add_constructor(slither)

        self.__add_inherited_functions()

        # TODO improve efficiency:

        with open(self.contract_path, 'w') as contract_file:
            contract_file.writelines(self.contract_lines)

        slither = Slither(self.contract_path)
        self.contract_info = slither.get_contract_from_name(self.contract_name)
示例#5
0
    def instrument(self, contract_path, contract_name, predicates,
                   instrument_for_echidna):
        self.contract_path = contract_path
        self.contract_name = contract_name

        slither = Slither(self.contract_path)
        self.contract_info = slither.get_contract_from_name(self.contract_name)
        if self.contract_info is None:
            raise Exception('Check config file for contract name')

        with open(self.contract_path) as contract_file:
            contract = contract_file.read()
        contract = contract.replace('}', '\n}')
        self.contract_lines = contract.split('\n')

        self.__pre_process_contract()

        parser = Parser()

        echidna_function = ''

        for index, predicate_string in enumerate(predicates):
            predicate = parser.parse(predicate_string)

            functions_to_instrument = self.__get_functions_to_instrument(
                predicate)

            self.__instrument_new_variables(predicate, functions_to_instrument,
                                            instrument_for_echidna)

            if instrument_for_echidna:
                echidna_function += '(' + predicate.solidity_repr + ')\n&& '
            else:
                assert_string = f'assert({predicate.solidity_repr}); // VERIMAN ASSERT FOR PREDICATE NO. {index + 1}'
                self.__insert_in_functions(functions_to_instrument,
                                           assert_string,
                                           self.__insert_at_end_of_functions)

        if instrument_for_echidna:
            echidna_function = 'function echidna_invariant() public returns(bool) {\nreturn ' \
                               + echidna_function.rsplit('\n&& ', 1)[0]\
                               + ';\n}'
            self.__insert_in_contract(echidna_function)

        contract = '\n'.join(self.contract_lines)
        with open(self.contract_path, 'w') as contract_file:
            contract_file.write(contract)
示例#6
0
    def check_functions_with_asserts(self, veriman, expected):
        slither = Slither(veriman.contract_path)
        contract_info = slither.get_contract_from_name(veriman.contract_name)

        expected_functions = set(list(expected))

        found_functions = list(
            filter(
                lambda func: next(
                    filter(lambda call: call.name == 'assert(bool)', func.
                           solidity_calls), None) is not None,
                contract_info.functions_declared))

        found_functions_names = list(
            map(lambda func: func.name, found_functions))

        self.assertEqual(expected_functions, set(found_functions_names))
示例#7
0
def instantiate_dsl(sol_file, analysis, lambdas):
    ## Step 1: parse the original source .sol.
    # Init slither
    slither = Slither(sol_file)

    # Get the contract, all the contact's name is C by default.
    contract = slither.get_contract_from_name('C')
    other_contracts = list(
        filter(lambda x: x != 'C', map(str, slither.contracts)))
    harness_fun = contract.functions[0]
    vars_map = {}

    # Get the function, which has name 'foo' by default.
    assert harness_fun.name == 'foo'

    for var in harness_fun.variables_read:
        add_var(vars_map, var)

    for var in harness_fun.variables_written:
        add_var(vars_map, var)

    actual_spec = toy_spec_str

    int_str = ""
    address_str = ""
    maparray_str = ""
    mapint_str = ""
    prog_decl = ""

    with open(sol_file, "r") as f:
        ind = "//#LOOPVARS: "
        body = f.read()
        if ind in body:
            global_vars = body[body.index(ind) + 12:].split("\n")[0]
            global_vars = global_vars.replace('[', "").replace(
                ']', "").replace("'", "").replace(" ", "").split(", ")
        else:
            global_vars = ["i"]

    #TODO: HANDLE NESTED LOOPS
    i_global = global_vars[0] in list(map(str, contract.variables))

    for k in vars_map:
        for v in vars_map[k]:
            if v == global_vars[0]:
                if i_global:
                    prog_decl += k + ' ' + v + '; \n'
            else:
                prog_decl += k + ' ' + v + '; \n'

    # TODO: Presumes all constants are integers or booleans
    for const in analysis[5]:
        try:
            if 'uint256' in vars_map:
                vars_map['uint256'].append(str(int(const)))
            else:
                vars_map['uint256'] = [str(int(const))]
        except:
            if 'bool' in vars_map:
                vars_map['bool'].append(const)
            else:
                vars_map['bool'] = [const]

    base_types = ["uint", "bool", "address", "bytes"] + other_contracts
    map_types = list(
        map(lambda x: "mapping({0} => {1})".format(x[0], x[1]),
            product(base_types, repeat=2)))

    all_types = base_types + map_types

    type_table = {}

    length_vars = []
    for k in vars_map:
        v = map(lambda x: '"' + x + '"', vars_map[k])
        actual_symbols = ",".join(list(v))
        print('parsing key:', k, ",".join(list(v)))
        if "[]" in k:
            length_vars += vars_map[k]
            k = "mapping(uint => {0})".format(k.replace("[]", ""))
        k = k.replace("uint8", "uint")
        k = k.replace("uint128", "uint")
        k = k.replace("uint256", "uint")
        k = k.replace("bytes32", "bytes")
        if k in all_types:
            if k in map_types:
                matches = re.findall(r"(mapping\((.*) => (.*)\))", k)
                if matches != []:
                    full_dec = matches[0][0]
                    dom = matches[0][1]
                    codom = matches[0][2]
                    k = "mapping_{0}_{1}".format(dom, codom)

            if not k in type_table:
                type_table[k] = actual_symbols.split(",")
            else:
                type_table[k] += actual_symbols.split(",")
        else:
            print("IGNORED TYPE: {0}!".format(k))
            pass

    if "uint" in type_table:
        type_table["uint"] += list(
            map(lambda v: '"{0}.length"'.format(v), length_vars))
    else:
        type_table["uint"] = list(
            map(lambda v: '"{0}.length"'.format(v), length_vars))

    typ_enums, final_typ_dict = create_refinement_types(
        analysis, type_table, lambdas)

    actual_spec = expand_dsl(actual_spec, final_typ_dict, base_types)

    actual_spec = actual_spec.format(types=typ_enums)

    # print(actual_spec)

    return actual_spec, prog_decl, final_typ_dict, i_global, global_vars
示例#8
0
import sys
from slither.slither import Slither

if len(sys.argv) != 2:
    print('python.py function_called.py functions_called.sol')
    exit(-1)

# Init slither
slither = Slither(sys.argv[1])

# Get the contract
contract = slither.get_contract_from_name('Contract')

# Get the variable
entry_point = contract.get_function_from_signature('entry_point()')

all_calls = entry_point.all_internal_calls()

all_calls_formated = [f.contract.name + '.' + f.name for f in all_calls]

# Print the result
print(
    'From entry_point the functions reached are {}'.format(all_calls_formated))
示例#9
0
import sys
from slither.slither import Slither

if len(sys.argv) != 2:
    print("python function_writing.py functions_writing.sol")
    sys.exit(-1)

# Init slither
slither = Slither(sys.argv[1])

# Get the contract
contracts = slither.get_contract_from_name("Contract")
assert len(contracts) == 1
contract = contracts[0]
# Get the variable
var_a = contract.get_state_variable_from_name("a")

# Get the functions writing the variable
functions_writing_a = contract.get_functions_writing_to_variable(var_a)

# Print the result
print('The function writing "a" are {}'.format(
    [f.name for f in functions_writing_a]))
示例#10
0
import sys
from slither.slither import Slither
from slither.slithir.convert import convert_expression

if len(sys.argv) != 4:
    print(
        'python.py function_called.py functions_called.sol Contract function()'
    )
    exit(-1)

# Init slither
slither = Slither(sys.argv[1])

# Get the contract
contract = slither.get_contract_from_name(sys.argv[2])

# Get the variable
test = contract.get_function_from_signature(sys.argv[3])
#test = contract.get_function_from_signature('two()')

nodes = test.nodes

for node in nodes:
    if node.expression:
        print('Expression:\n\t{}'.format(node.expression))
        irs = convert_expression(node.expression)
        print('IR expressions:')
        for ir in irs:
            print('\t{}'.format(ir))
        print()
示例#11
0
import sys
from slither.slither import Slither
from slither.slithir.convert import convert_expression

if len(sys.argv) != 2:
    print('python function_called.py functions_called.sol')
    exit(-1)

# Init slither
slither = Slither(sys.argv[1])

# Get the contract
contract = slither.get_contract_from_name('Test')

# Get the variable
test = contract.get_function_from_signature('one()')

nodes = test.nodes

for node in nodes:
    if node.expression:
        print('Expression:\n\t{}'.format(node.expression))
        irs = convert_expression(node.expression)
        print('IR expressions:')
        for ir in irs:
            print('\t{}'.format(ir))
        print()
from slither.slither import Slither

slither = Slither('coin.sol')
coin = slither.get_contract_from_name('Coin')[0]

# Iterate over all the contracts
for contract in slither.contracts:
   # If the contract is derived from MyContract
   if coin in contract.inheritance:
      # Get the function definition  
      mint = contract.get_function_from_signature('_mint(address,uint256)')
      # If the function was not declarer by coin, there is a bug !  
      if mint.contract != coin:
           print(f'Error, {contract} overrides {mint}')
示例#13
0
import sys
from slither.slither import Slither
from slither.slithir.convert import convert_expression

if len(sys.argv) != 2:
    print("python function_called.py functions_called.sol")
    sys.exit(-1)

# Init slither
slither = Slither(sys.argv[1])

# Get the contract
contracts = slither.get_contract_from_name("Test")
assert len(contracts) == 1
contract = contracts[0]
# Get the variable
test = contract.get_function_from_signature("one()")
assert test
nodes = test.nodes

for node in nodes:
    if node.expression:
        print(f"Expression:\n\t{node.expression}")
        irs = convert_expression(node.expression, node)
        print("IR expressions:")
        for ir in irs:
            print(f"\t{ir}")
        print()