Add print to show the state variables ordering

Add utility to compare the state variables order given two version of a contract
pull/148/head
Josselin 6 years ago
parent 8f7832144a
commit 318f2fe036
  1. 5
      slither/__main__.py
  2. 2
      slither/core/solidity_types/mapping_type.py
  3. 2
      slither/printers/summary/function_ids.py
  4. 29
      slither/printers/summary/variables_order.py
  5. 56
      utils/upgradability/compare_variables_order.py

@ -180,7 +180,7 @@ def get_detectors_and_printers():
from slither.printers.summary.human_summary import PrinterHumanSummary from slither.printers.summary.human_summary import PrinterHumanSummary
from slither.printers.functions.cfg import CFG from slither.printers.functions.cfg import CFG
from slither.printers.summary.function_ids import FunctionIds from slither.printers.summary.function_ids import FunctionIds
from slither.printers.summary.variables_order import VariablesOrder
printers = [FunctionSummary, printers = [FunctionSummary,
ContractSummary, ContractSummary,
PrinterInheritance, PrinterInheritance,
@ -191,7 +191,8 @@ def get_detectors_and_printers():
PrinterSlithIRSSA, PrinterSlithIRSSA,
PrinterHumanSummary, PrinterHumanSummary,
CFG, CFG,
FunctionIds] FunctionIds,
VariablesOrder]
# Handle plugins! # Handle plugins!
for entry_point in iter_entry_points(group='slither_analyzer.plugin', name=None): for entry_point in iter_entry_points(group='slither_analyzer.plugin', name=None):

@ -18,7 +18,7 @@ class MappingType(Type):
return self._to return self._to
def __str__(self): def __str__(self):
return 'mapping({} => {}'.format(str(self._from), str(self._to)) return 'mapping({} => {})'.format(str(self._from), str(self._to))
def __eq__(self, other): def __eq__(self, other):
if not isinstance(other, MappingType): if not isinstance(other, MappingType):

@ -21,7 +21,7 @@ class FunctionIds(AbstractPrinter):
txt = '' txt = ''
for contract in self.slither.contracts_derived: for contract in self.slither.contracts_derived:
txt = '\n{}:\n'.format(contract.name) txt += '\n{}:\n'.format(contract.name)
table = PrettyTable(['Name', 'ID']) table = PrettyTable(['Name', 'ID'])
for function in contract.functions: for function in contract.functions:
if function.visibility in ['public', 'external']: if function.visibility in ['public', 'external']:

@ -0,0 +1,29 @@
"""
Module printing summary of the contract
"""
from prettytable import PrettyTable
from slither.printers.abstract_printer import AbstractPrinter
class VariablesOrder(AbstractPrinter):
ARGUMENT = 'variables-order'
HELP = 'Print the storage order of the state variables'
def output(self, _filename):
"""
_filename is not used
Args:
_filename(string)
"""
txt = ''
for contract in self.slither.contracts_derived:
txt += '\n{}:\n'.format(contract.name)
table = PrettyTable(['Name', 'Type'])
for variable in contract.state_variables:
if not variable.is_constant:
table.add_row([variable.name, str(variable.type)])
txt += str(table) + '\n'
self.info(txt)

@ -0,0 +1,56 @@
'''
This utility looks for functions collisions between a proxy and the implementation
More for information: https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357
'''
import sys
from slither import Slither
from slither.utils.function import get_function_id
from slither.utils.colors import red, green
if __name__ == "__main__":
if len(sys.argv) != 5:
print('Usage: python3 compare_variables_order.py v1.sol Contract1 v2.sol Contract2')
v1 = Slither(sys.argv[1])
v2 = Slither(sys.argv[3])
contract_v1 = v1.get_contract_from_name(sys.argv[2])
if contract_v1 is None:
print(red('Contract {} not found'.format(sys.argv[2])))
exit(-1)
contract_v2 = v2.get_contract_from_name(sys.argv[4])
if contract_v2 is None:
print(red('Contract {} not found'.format(sys.argv[4])))
exit(-1)
order_v1 = [(variable.name, variable.type) for variable in contract_v1.state_variables if not variable.is_constant]
order_v2 = [(variable.name, variable.type) for variable in contract_v2.state_variables if not variable.is_constant]
found = False
for idx in range(0, len(order_v1)):
(v1_name, v1_type) = order_v1[idx]
if len(order_v2) < idx:
print(red('Missing variable in the new version: {} {}'.format(v1_name, v1_type)))
continue
(v2_name, v2_type) = order_v2[idx]
if (v1_name != v2_name) or (v1_type != v2_type):
found = True
print(red('Different variable: {} {} -> {} {}'.format(v1_name,
v1_type,
v2_name,
v2_type)))
if len(order_v2) > len(order_v1):
new_variables = order_v2[len(order_v1):]
for (name, t) in new_variables:
print(green('New variable: {} {}'.format(name, t)))
if not found:
print(green('No error found'))
Loading…
Cancel
Save