예제 #1
0
 def __eq__(self, other):
     if type(other) is str:
         try:
             address = web3.toChecksumAddress(other)
             return address == self.address
         except ValueError:
             return False
     return super().__eq__(other)
예제 #2
0
    def at(self, address):
        '''Retrieves an Account instance from the address string. Raises
        ValueError if the account cannot be found.

        Args:
            address: string of the account address.

        Returns:
            Account instance.
        '''
        try:
            address = web3.toChecksumAddress(address)
        except ValueError:
            raise ValueError("{} is not a valid address".format(address))
        try:
            return next(i for i in self._accounts if i == address)
        except StopIteration:
            raise ValueError("No account exists for {}".format(address))
예제 #3
0
    def at(self, address, owner=None, tx=None):
        '''Returns a contract address.
        
        Raises ValueError if no bytecode exists at the address.

        Args:
            address: Address string of the contract.
            owner: Default Account instance to send contract transactions from.
            tx: Transaction ID of the contract creation.'''
        address = web3.toChecksumAddress(address)
        if address in deployed_contracts[self._name]:
            return deployed_contracts[self._name][address]
        contract = find_contract(address)
        if contract:
            raise ValueError("Contract '{}' already declared at {}".format(
                contract._name, address))
        if web3.eth.getCode(address).hex() == "0x":
            raise ValueError("No contract deployed at {}".format(address))
        contract = Contract(address, self._build, owner, tx)
        deployed_contracts[self._name][address] = contract
        if CONFIG['active_network']['persist']:
            add_contract(self._name, address, tx.hash if tx else None, owner)
        return deployed_contracts[self._name][address]
예제 #4
0
    def _get_trace(self):
        '''Retrieves the stack trace via debug_traceTransaction, and adds the
        following attributes to each step:

        address: The address executing this contract.
        contractName: The name of the contract.
        fn: The name of the function.
        source: Start and end offset associated source code.
        jumpDepth: Number of jumps made since entering this contract. The
                   initial value is 1.'''
        self.trace = []
        self.return_value = None
        self.revert_msg = None
        if (self.input == "0x"
                and self.gas_used == 21000) or self.contract_address:
            return
        trace = web3.providers[0].make_request('debug_traceTransaction',
                                               [self.txid, {}])
        if 'error' in trace:
            raise ValueError(trace['error']['message'])
        self.trace = trace = trace['result']['structLogs']
        c = contract.find_contract(self.receiver or self.contract_address)
        last = {
            0: {
                'address': self.receiver or self.contract_address,
                'contract': c._name,
                'fn': [self.fn_name.split('.')[-1]],
            }
        }
        pc = c._build['pcMap'][0]
        trace[0].update({
            'address': last[0]['address'],
            'contractName': last[0]['contract'],
            'fn': last[0]['fn'][-1],
            'jumpDepth': 1,
            'source': {
                'filename': pc['contract'],
                'start': pc['start'],
                'stop': pc['stop']
            }
        })
        for i in range(1, len(trace)):
            # if depth has increased, tx has called into a different contract
            if trace[i]['depth'] > trace[i - 1]['depth']:
                address = web3.toChecksumAddress(trace[i -
                                                       1]['stack'][-2][-40:])
                c = contract.find_contract(address)
                stack_idx = -4 if trace[i - 1]['op'] in ('CALL',
                                                         'CALLCODE') else -3
                memory_idx = int(trace[i - 1]['stack'][stack_idx], 16) * 2
                sig = "0x" + "".join(
                    trace[i - 1]['memory'])[memory_idx:memory_idx + 8]
                last[trace[i]['depth']] = {
                    'address': address,
                    'contract': c._name,
                    'fn':
                    [next(k for k, v in c.signatures.items() if v == sig)],
                }
            trace[i].update({
                'address':
                last[trace[i]['depth']]['address'],
                'contractName':
                last[trace[i]['depth']]['contract'],
                'fn':
                last[trace[i]['depth']]['fn'][-1],
                'jumpDepth':
                len(set(last[trace[i]['depth']]['fn']))
            })
            c = contract.find_contract(trace[i]['address'])
            pc = c._build['pcMap'][trace[i]['pc']]
            trace[i]['source'] = {
                'filename': pc['contract'],
                'start': pc['start'],
                'stop': pc['stop']
            }
            # jump 'i' is moving into an internal function
            if pc['jump'] == 'i':
                source = c._build['source'][pc['start']:pc['stop']]
                if source[:7] not in ("library", "contrac") and "(" in source:
                    fn = source[:source.index('(')].split('.')[-1]
                else:
                    fn = last[trace[i]['depth']]['fn'][-1]
                last[trace[i]['depth']]['fn'].append(fn)
            # jump 'o' is coming out of an internal function
            elif pc['jump'] == "o" and len(last[trace[i]['depth']]['fn']) > 1:
                last[trace[i]['depth']]['fn'].pop()
예제 #5
0
def find_contract(address):
    address = web3.toChecksumAddress(address)
    contracts = [x for v in deployed_contracts.values() for x in v.values()]
    return next((i for i in contracts if i == address), False)
예제 #6
0
 def __contains__(self, address):
     try:
         address = web3.toChecksumAddress(address)
         return address in self._accounts
     except ValueError:
         return False