示例#1
0
    def signTransaction(self, transaction_dict, private_key):
        '''
        @param private_key in bytes, str, or int.
        '''
        assert isinstance(transaction_dict, Mapping)

        account = self.privateKeyToAccount(private_key)

        # sign transaction
        (
            v,
            r,
            s,
            rlp_encoded,
        ) = sign_transaction_dict(account._key_obj, transaction_dict)

        transaction_hash = keccak(rlp_encoded)

        return AttributeDict({
            'rawTransaction': HexBytes(rlp_encoded),
            'hash': HexBytes(transaction_hash),
            'r': r,
            's': s,
            'v': v,
        })
示例#2
0
    def signTransaction(self, transaction_dict, private_key):
        '''
        @param private_key in bytes, str, or int.
            In Python 2, a bytes, unicode or str object will be interpreted as hexstr
            In Python 3, only a str object will be interpreted as hexstr
        '''
        assert isinstance(transaction_dict, Mapping)

        account = self.privateKeyToAccount(private_key)

        # sign transaction
        (
            v,
            r,
            s,
            rlp_encoded,
        ) = sign_transaction_dict(account._key_obj, transaction_dict)

        transaction_hash = keccak(rlp_encoded)

        return AttributeDict({
            'rawTransaction': HexBytes(rlp_encoded),
            'hash': HexBytes(transaction_hash),
            'r': HexBytes(r),
            's': HexBytes(s),
            'v': v,
        })
示例#3
0
    def signTransaction(self, transaction_dict, private_key):
        '''
        @param private_key in bytes, str, or int.
            In Python 2, a bytes, unicode or str object will be interpreted as hexstr
            In Python 3, only a str object will be interpreted as hexstr
        '''
        assert isinstance(transaction_dict, Mapping)

        account = self.privateKeyToAccount(private_key)

        # sign transaction
        (
            v,
            r,
            s,
            transaction_hash,
            rlp_encoded,
        ) = sign_transaction_dict(account._key_obj, transaction_dict)

        # format most returned elements as hex
        signature_info = {
            key: to_hex_with_size(val, 256)  # minimum size is 32 bytes
            for key, val in (
                ('rawTransaction', rlp_encoded),
                ('hash', transaction_hash),
                ('r', r),
                ('s', s),
            )
        }
        signature_info['v'] = v
        return AttributeDict(signature_info)
示例#4
0
 def sign(self,
          message=None,
          private_key=None,
          message_hexstr=None,
          message_text=None):
     '''
     @param private_key in bytes, str, or int.
         In Python 2, a bytes, unicode or str object will be interpreted as hexstr
         In Python 3, only a str object will be interpreted as hexstr
     '''
     msg_bytes = to_bytes(message, hexstr=message_hexstr, text=message_text)
     msg_hash = self.hashMessage(msg_bytes)
     key_bytes = hexstr_if_str(to_bytes, private_key)
     key = self._keys.PrivateKey(key_bytes)
     (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash)
     (r_hex, s_hex, eth_signature_hex) = map(to_hex,
                                             (r, s, eth_signature_bytes))
     return AttributeDict({
         'message': msg_bytes,
         'messageHash': msg_hash,
         'r': r_hex,
         's': s_hex,
         'v': v,
         'signature': eth_signature_hex,
     })
示例#5
0
 def _update_channel_data_from_blockchain(self, channel):
     channel_blockchain_data = self.mpe_contract.functions.channels(
         channel["channelId"]).call()
     channel = dict(channel)
     channel["nonce"] = channel_blockchain_data[0]
     channel["amount"] = channel_blockchain_data[5]
     channel["expiration"] = channel_blockchain_data[6]
     return AttributeDict(channel)
示例#6
0
    def middleware(method, params):
        response = make_request(method, params)

        if 'result' in response:
            result = response['result']
            if is_dict(result) and not isinstance(result, AttributeDict):
                return assoc(response, 'result', AttributeDict.recursive(result))
            else:
                return response
        else:
            return response
def test_attributedict_dict_in_list_in_dict():
    data = {'instructions': [
        0,
        1,
        'neither shalt thou count, excepting that thou then proceedeth to three',
        {'if_naughty': 'snuff it'},
        'shalt thou not count',
        'right out',
    ]}
    attrdict = AttributeDict.recursive(data)
    assert attrdict.instructions[3].if_naughty == 'snuff it'
示例#8
0
 def sign(self,
          message=None,
          private_key=None,
          message_hexstr=None,
          message_text=None):
     '''
     @param private_key in bytes, str, or int.
     '''
     msg_bytes = to_bytes(message, hexstr=message_hexstr, text=message_text)
     msg_hash = self.hashMessage(msg_bytes)
     key_bytes = HexBytes(private_key)
     key = self._keys.PrivateKey(key_bytes)
     (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash)
     return AttributeDict({
         'message': HexBytes(msg_bytes),
         'messageHash': msg_hash,
         'r': r,
         's': s,
         'v': v,
         'signature': HexBytes(eth_signature_bytes),
     })
示例#9
0
eth_initial_transaction = AttributeDict({
    'blockHash':
    HexBytes(
        '0x111346453964a0df4fcd50ac759231f4f90a858c6ab62255e7c75089b22b0b40'),
    'blockNumber':
    8388823,
    'chainId':
    None,
    'condition':
    None,
    'creates':
    None,
    'from':
    '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
    'gas':
    140502,
    'gasPrice':
    1000000000,
    'hash':
    HexBytes(
        '0xcf64ef4d0449cf7a78d2be1c1f7225dffb11dded98a58d569ebcc6e883ce9f2b'),
    'input':
    '0x7337c993000000000000000000000000000000000000000000000000000000005b782cfaed2e6fe492005de2dd82e84d38448'
    '467d632e81c000000000000000000000000000000000000000000000000d867f293ba129629a9f9355fa285b8d3711a90920000'
    '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
    '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    'nonce':
    283,
    'publicKey':
    HexBytes(
        '0x76c4f5810736d1d9b9964863abc339dce70ace058db5c820e5fdec26e0840f36f9adcb150e5216213bc301f3a6b71a178'
        'c81ddd34a361d696c8cb03970590d4f'),
    'r':
    HexBytes(
        '0x68e2bbdd4cb4e989854a87aa8964c65b3bf28f68183f73f905ab8841db690cbb'),
    'raw':
    HexBytes(
        '0xf9013282011b843b9aca00830224d694ce07ab9477bc20790b88b398a2a9e0f626c7d26387038d7ea4c68000b8c47337c993000000'
        '000000000000000000000000000000000000000000000000005b782cfaed2e6fe492005de2dd82e84d38448467d632e81c0000000000'
        '00000000000000000000000000000000000000d867f293ba129629a9f9355fa285b8d3711a9092000000000000000000000000000000'
        '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
        '0000000000000000000000000000000000000000000000000000001ca068e2bbdd4cb4e989854a87aa8964c65b3bf28f68183f73f905'
        'ab8841db690cbba0227712dc5c204041cc8c44facac023c457725acc905b2db311b1176cd53836e0'
    ),
    's':
    HexBytes(
        '0x227712dc5c204041cc8c44facac023c457725acc905b2db311b1176cd53836e0'),
    'standardV':
    1,
    'to':
    '0xce07aB9477BC20790B88B398A2A9e0F626c7D263',
    'transactionIndex':
    1,
    'v':
    28,
    'value':
    1000000000000000
})
示例#10
0
def test_attributedict_delitem_invalid():
    container = AttributeDict({'a': 1})
    with pytest.raises(TypeError):
        del container['a']
    assert container['a'] == 1
示例#11
0
def test_attributedict_equality(dict1, dict2):
    assert AttributeDict(dict1) == dict2
    assert AttributeDict(dict1) == AttributeDict(dict2)
    assert dict1 == AttributeDict(dict2)
示例#12
0
def test_attributedict_repr():
    dict1 = AttributeDict({'a': 1})
    dict2 = eval(repr(dict1))
    assert dict1 == dict2
示例#13
0
def test_attributedict_setattr_invalid():
    container = AttributeDict({'a': 1})
    with pytest.raises(TypeError):
        container.a = 0
    assert container.a == 1
示例#14
0
def test_attributedict_inequality(dict1, dict2):
    assert AttributeDict(dict1) != dict2
    assert AttributeDict(dict1) != AttributeDict(dict2)
    assert dict1 != AttributeDict(dict2)
示例#15
0
def test_attributedict_access():
    container = AttributeDict({'a': 1})
    assert container.a == 1
示例#16
0
    def client(self, *args, org_id=None, service_id=None, channel_id=None):
        client = MutableAttributeDict({})

        # Determine org_id, service_id and channel_id for client
        _org_id = org_id
        _service_id = service_id
        _channel_id = channel_id

        if len(args) == 2:
            (_org_id, _service_id) = args
        if len(args) == 1:
            raise ValueError(
                "Please either provide both organization id and service id as positional arguments or none of them"
            )

        if (_org_id is not None
                or _service_id is not None) and (org_id is not None
                                                 or service_id is not None):
            raise ValueError(
                "Please provide organization id and service id either as positional arguments or as keyword arguments"
            )

        if org_id is not None and _service_id is not None:
            _org_id = org_id
            _service_id = service_id

        if _org_id is None or _service_id is None:
            raise ValueError("""Could not instantiate client.
            Please provide at least an org_id and a service_id either as positional or keyword arguments"""
                             )

        # Get client metadata for service
        (found, registration_id, metadata_uri,
         tags) = self.registry_contract.functions.getServiceRegistrationById(
             bytes(_org_id, "utf-8"), bytes(_service_id, "utf-8")).call()
        client.metadata = AttributeDict(
            json.loads(
                self.ipfs_client.cat(
                    metadata_uri.rstrip(b"\0").decode('ascii')[7:])))
        default_group = AttributeDict(client.metadata.groups[0])
        client.default_payment_address = default_group["payment_address"]
        default_channel_value = client.metadata.pricing["price_in_cogs"] * 100
        default_channel_expiration = int(
            self.web3.eth.getBlock("latest").number +
            client.metadata.payment_expiration_threshold +
            (3600 * 24 * 7 / self.average_block_time))
        service_endpoint = None
        for endpoint in client.metadata["endpoints"]:
            if (endpoint["group_name"] == default_group["group_name"]):
                service_endpoint = endpoint["endpoint"]
                break

        # Functions to get a funded channel with a combination of calls to the blockchain and to the daemon
        grpc_channel = self._get_base_grpc_channel(service_endpoint)

        channel_state_service_proto_path = str(
            cur_dir.joinpath("resources", "proto"))
        sys.path.insert(0, channel_state_service_proto_path)
        _state_service_pb2 = importlib.import_module("state_service_pb2")
        _state_service_pb2_grpc = importlib.import_module(
            "state_service_pb2_grpc")
        sys.path.remove(channel_state_service_proto_path)

        def _get_channel_state(channel_id):
            stub = _state_service_pb2_grpc.PaymentChannelStateServiceStub(
                grpc_channel)
            message = web3.Web3.soliditySha3(["uint256"], [channel_id])
            signature = self.web3.eth.account.signHash(
                defunct_hash_message(message),
                self.signer_private_key).signature
            request = _state_service_pb2.ChannelStateRequest(
                channel_id=web3.Web3.toBytes(channel_id),
                signature=bytes(signature))
            response = stub.GetChannelState(request)
            return {
                "current_nonce":
                int.from_bytes(response.current_nonce, byteorder="big"),
                "current_signed_amount":
                int.from_bytes(response.current_signed_amount, byteorder="big")
            }

        def _get_channel_states():
            return [
                dict(
                    _get_channel_state(channel.channelId), **{
                        "channel_id": channel.channelId,
                        "initial_amount": channel.amount,
                        "expiration": channel.expiration
                    }) for channel in self._get_channels(
                        client.default_payment_address)
            ]

        def _client_open_channel(value, expiration):
            mpe_balance = self.mpe_contract.functions.balances(
                self.address).call()
            group_id = base64.b64decode(default_group.group_id)
            if value > mpe_balance:
                return (self.mpe_deposit_and_open_channel(
                    default_group.payment_address, group_id,
                    value - mpe_balance, expiration))
            else:
                return (self.mpe_open_channel(default_group.payment_address,
                                              group_id, value, expiration))

        def _client_add_funds(channel_id, amount):
            mpe_balance = self.mpe_contract.functions.balances(
                self.address).call()
            if value > mpe_balance:
                self.mpe_deposit(amount - mpe_balance)
            return (self.mpe_channel_add_funds(channel_id, amount))

        def _client_extend_and_add_funds(channel_id, new_expiration, amount):
            mpe_balance = self.mpe_contract.functions.balances(
                self.address).call()
            if amount > mpe_balance:
                self.mpe_deposit(amount - mpe_balance)
            return (self.mpe_channel_extend_and_add_funds(
                channel_id, new_expiration, amount))

        def _get_funded_channel():
            channel_states = _get_channel_states()

            if len(channel_states) == 0:
                if self.allow_transactions is False:
                    raise RuntimeError(
                        'No state channel found. Please open a new channel or set configuration parameter "allow_transactions=True" when creating Snet class instance'
                    )
                else:
                    _client_open_channel(default_channel_value,
                                         default_channel_expiration)
                    channel_states = _get_channel_states()

            funded_channels = list(
                filter(
                    lambda state: state["initial_amount"] - state[
                        "current_signed_amount"] >= int(
                            client.metadata.pricing["price_in_cogs"]),
                    iter(channel_states)))
            if len(funded_channels) == 0:
                if self.allow_transactions is True:
                    non_expired_unfunded_channels = list(
                        filter(
                            lambda state: state["expiration"] + client.metadata
                            .payment_expiration_threshold > self.web3.eth.
                            getBlock("latest").number, iter(channel_states)))
                    if len(non_expired_unfunded_channels) == 0:
                        channel_id = next(iter(channel_states))["channel_id"]
                        _client_extend_and_add_funds(
                            channel_id, default_channel_expiration,
                            default_channel_value)
                        return channel_id
                    else:
                        channel_id = next(
                            iter(non_expired_unfunded_channels))["channel_id"]
                        _client_add_funds(channel_id, default_channel_value)
                        return channel_id
                else:
                    raise RuntimeError(
                        'No funded channel found. Please open a new channel or fund an open one, or set configuration parameter "allow_transactions=True" when creating Snet class instance'
                    )

            valid_channels = list(
                filter(
                    lambda state: state["expiration"] + client.metadata.
                    payment_expiration_threshold > self.web3.eth.getBlock(
                        "latest").number, iter(funded_channels)))
            if len(valid_channels) == 0:
                if self.allow_transactions is True:
                    channel_id = next(iter(funded_channels))["channel_id"]
                    self.mpe_channel_extend(channel_id,
                                            default_channel_expiration)
                    return channel_id
                else:
                    raise RuntimeError(
                        'No non-expired channel found. Please open a new channel or extend an open and funded one, or set configuration parameter "allow_transactions=True" when creating Snet class instance'
                    )
            else:
                channel_id = next(iter(valid_channels))["channel_id"]

            return channel_id

        if _channel_id is None:
            _channel_id = _get_funded_channel()

        # Import modules and add them to client grpc object
        libraries_base_path = self.libraries_base_path

        client_library_path = str(
            main_dir_path.joinpath(self.libraries_base_path, _org_id,
                                   _service_id))
        sys.path.insert(0, client_library_path)

        grpc_modules = []
        for module_path in Path(client_library_path).glob("**/*_pb2.py"):
            grpc_modules.append(module_path)
        for module_path in Path(client_library_path).glob("**/*_pb2_grpc.py"):
            grpc_modules.append(module_path)

        grpc_modules = list(
            map(
                lambda x: str(
                    PurePath(
                        Path(x).relative_to(client_library_path).parent.
                        joinpath(PurePath(x).stem))), grpc_modules))

        imported_modules = MutableAttributeDict({})
        for grpc_module in grpc_modules:
            imported_module = importlib.import_module(grpc_module)
            imported_modules[grpc_module] = imported_module

        sys.path.remove(client_library_path)

        # Service channel utility methods
        def _get_service_call_metadata(channel_id):
            state = _get_channel_state(channel_id)
            amount = state["current_signed_amount"] + int(
                client.metadata.pricing["price_in_cogs"])
            message = web3.Web3.soliditySha3(
                ["address", "uint256", "uint256", "uint256"], [
                    self.mpe_contract.address, channel_id,
                    state["current_nonce"], amount
                ])
            signature = bytes(
                self.web3.eth.account.signHash(
                    defunct_hash_message(message),
                    self.signer_private_key).signature)
            metadata = [("snet-payment-type", "escrow"),
                        ("snet-payment-channel-id", str(channel_id)),
                        ("snet-payment-channel-nonce",
                         str(state["current_nonce"])),
                        ("snet-payment-channel-amount", str(amount)),
                        ("snet-payment-channel-signature-bin", signature)]

            return metadata

        # Client exports
        client.open_channel = lambda value=default_channel_value, expiration=default_channel_expiration: _client_open_channel(
            value, expiration)
        client.get_service_call_metadata = lambda: _get_service_call_metadata(
            _channel_id)
        client.grpc = imported_modules

        def intercept_call(client_call_details, request_iterator,
                           request_streaming, response_streaming):
            metadata = []
            if client_call_details.metadata is not None:
                metadata = list(client_call_details.metadata)
            metadata.extend(client.get_service_call_metadata())
            client_call_details = _ClientCallDetails(
                client_call_details.method, client_call_details.timeout,
                metadata, client_call_details.credentials)
            return client_call_details, request_iterator, None

        client.grpc_channel = grpc.intercept_channel(
            grpc_channel, generic_client_interceptor.create(intercept_call))

        return client
示例#17
0
def get_event_data(event_abi, log_entry):
    """
    Given an event ABI and a log entry for that event, return the decoded
    event data
    """
    if event_abi['anonymous']:
        log_topics = log_entry['topics']
    elif not log_entry['topics']:
        raise MismatchedABI(
            "Expected non-anonymous event to have 1 or more topics")
    elif event_abi_to_log_topic(event_abi) != log_entry['topics'][0]:
        raise MismatchedABI(
            "The event signature did not match the provided ABI")
    else:
        log_topics = log_entry['topics'][1:]

    log_topics_abi = get_indexed_event_inputs(event_abi)
    log_topic_normalized_inputs = normalize_event_input_types(log_topics_abi)
    log_topic_types = get_event_abi_types_for_decoding(
        log_topic_normalized_inputs)
    log_topic_names = get_abi_input_names({'inputs': log_topics_abi})

    if len(log_topics) != len(log_topic_types):
        raise ValueError("Expected {0} log topics.  Got {1}".format(
            len(log_topic_types),
            len(log_topics),
        ))

    log_data = hexstr_if_str(to_bytes, log_entry['data'])
    log_data_abi = exclude_indexed_event_inputs(event_abi)
    log_data_normalized_inputs = normalize_event_input_types(log_data_abi)
    log_data_types = get_event_abi_types_for_decoding(
        log_data_normalized_inputs)
    log_data_names = get_abi_input_names({'inputs': log_data_abi})

    # sanity check that there are not name intersections between the topic
    # names and the data argument names.
    duplicate_names = set(log_topic_names).intersection(log_data_names)
    if duplicate_names:
        raise ValueError(
            "Invalid Event ABI:  The following argument names are duplicated "
            "between event inputs: '{0}'".format(', '.join(duplicate_names)))

    decoded_log_data = decode_abi(log_data_types, log_data)
    normalized_log_data = map_abi_data(BASE_RETURN_NORMALIZERS, log_data_types,
                                       decoded_log_data)

    decoded_topic_data = [
        decode_single(topic_type, topic_data)
        for topic_type, topic_data in zip(log_topic_types, log_topics)
    ]
    normalized_topic_data = map_abi_data(BASE_RETURN_NORMALIZERS,
                                         log_topic_types, decoded_topic_data)

    event_args = dict(
        itertools.chain(
            zip(log_topic_names, normalized_topic_data),
            zip(log_data_names, normalized_log_data),
        ))

    event_data = {
        'args': event_args,
        'event': event_abi['name'],
        'logIndex': log_entry['logIndex'],
        'transactionIndex': log_entry['transactionIndex'],
        'transactionHash': log_entry['transactionHash'],
        'address': log_entry['address'],
        'blockHash': log_entry['blockHash'],
        'blockNumber': log_entry['blockNumber'],
    }

    return AttributeDict.recursive(event_data)
def test_attributedict_set_in_recursive_dict():
    data = {'mydict': {'myset': {'found'}}}
    attrdict = AttributeDict.recursive(data)
    assert 'found' in attrdict.mydict.myset
示例#19
0
eth_initial_transaction = AttributeDict({
    'blockHash': HexBytes('0xebb8d4e62dc5b0732bee6e2c3946c5a972988f41fbac321eb73311930a936804'),
    'blockNumber': 6600435,
    'chainId': None,
    'condition': None,
    'creates': None,
    'from': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
    'gas': 126221,
    'gasPrice': 14959965017,
    'hash': HexBytes('0x7221773115ded91f856cedb2032a529edabe0bab8785d07d901681512314ef41'),
    'input': (
        '0xeb8ae1ed000000000000000000000000000000000000000000000000000000005abe25ea10ff9'
        '72f3d8181f603aa7f6b4bc172de730fec2b00000000000000000000000000000000000000000000'
        '0000d867f293ba129629a9f9355fa285b8d3711a9092'
    ),
    'nonce': 16,
    'publicKey': HexBytes(
        '0x76c4f5810736d1d9b9964863abc339dce70ace058db5c820e5fdec26e0840f36f9adcb150e521'
        '6213bc301f3a6b71a178c81ddd34a361d696c8cb03970590d4f'
    ),
    'r': HexBytes('0x7a4e11ea96640fb0ab255960cea6afcf16732246ce1dadeec52eb6a8d59c2e05'),
    'raw': HexBytes(
        '0xf8ca1085037baef3598301ed0d949f7e5402ed0858ea0c5914d44b900a42c89547b80cb864eb8'
        'ae1ed000000000000000000000000000000000000000000000000000000005abe25ea10ff972f3d'
        '8181f603aa7f6b4bc172de730fec2b000000000000000000000000000000000000000000000000d'
        '867f293ba129629a9f9355fa285b8d3711a90921ba07a4e11ea96640fb0ab255960cea6afcf1673'
        '2246ce1dadeec52eb6a8d59c2e05a06f47ffe2bc88915013295be61c503bc52762fe4f7826fa249'
        '0b2d302a11bff85'
    ),
    's': HexBytes('0x6f47ffe2bc88915013295be61c503bc52762fe4f7826fa2490b2d302a11bff85'),
    'standardV': 0,
    'to': '0x9F7e5402ed0858Ea0C5914D44B900A42C89547B8',
    'transactionIndex': 0,
    'v': 27,
    'value': 12
})
示例#20
0
def test_attributedict_setattr_invalid():
    container = AttributeDict({'a': 1})
    with pytest.raises(TypeError):
        container.a = 0
    assert container.a == 1
def test_attributedict_recursive_dict():
    w = AttributeDict.recursive({'x': {'y': {'z': 8}}})
    assert w.x.y.z == 8
 def test_decode_transaction_logs(self):
     """
     Mocking `web3.eth.Eth.getTransactionReceipt()` response and verifies
     decoding transaction works as expected.
     """
     mocked_logs = [
         AttributeDict({
             'address':
             '0xCBf1735Aad8C4B337903cD44b419eFE6538aaB40',
             'topics': [
                 HexBytes('b76d0edd90c6a07aa3ff7a222d7f5933'
                          'e29c6acc660c059c97837f05c4ca1a84')
             ],
             'data':
             '000000000000000000000000fe8a5f3a7bb446e1cb4566717691cd3139289ed4'
             'b0230ab70b78e47050766089ea333f2ff7ad41c6f31e8bed8c2acfcb8e911841'
             '0000000000000000000000000000000000000000000000000000000000000000'
             '0000000000000000000000000000000000000000000000000000000000000100'
             '0000000000000000000000000000000000000000000000000000000000000140'
             '00000000000000000000000000000000000000000000000000000000000395f8'
             '1100000000000000000000000000000000000000000000000000000000000000'
             '00000000000000000000000000000000000000000000000000000004a817c800'
             '0000000000000000000000000000000000000000000000000000000000000006'
             '6e65737465640000000000000000000000000000000000000000000000000000'
             '00000000000000000000000000000000000000000000000000000000000001b4'
             '5b55524c5d205b276a736f6e2868747470733a2f2f6170692e72616e646f6d2e'
             '6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e7261'
             '6e646f6d5b2273657269616c4e756d626572222c2264617461225d272c20275c'
             '6e7b226a736f6e727063223a22322e30222c226d6574686f64223a2267656e65'
             '726174655369676e6564496e746567657273222c22706172616d73223a7b2261'
             '70694b6579223a247b5b646563727970745d20424b6733544373376c6b7a4e72'
             '316b523670786a50434d32534f656a63466f6a55504d544f73426b432f343748'
             '485066317350326f78564c546a4e42752b736c523953675a797144746a564f56'
             '35597a67313269556b62756270304470636a434564654a54486e477743366744'
             '3732394755566f47766f393668757877526f5a6c436a594f3830725771325747'
             '596f522f4c433357616d704475767632426f3d7d2c226e223a312c226d696e22'
             '3a312c226d6178223a3130302c227265706c6163656d656e74223a747275652c'
             '2262617365223a3130247b5b6964656e746974795d20227d227d2c226964223a'
             '31247b5b6964656e746974795d20227d227d275d000000000000000000000000',
         }),
         AttributeDict({
             'address':
             '0xFE8a5f3a7Bb446e1cB4566717691cD3139289ED4',
             'topics': [
                 HexBytes('1cb5bfc4e69cbacf65c8e05bdb84d7a3'
                          '27bd6bb4c034ff82359aefd7443775c4'),
                 HexBytes('b0230ab70b78e47050766089ea333f2f'
                          'f7ad41c6f31e8bed8c2acfcb8e911841'),
                 HexBytes('00000000000000000000000066d4bacf'
                          'e61df23be813089a7a6d1a749a5c936a'),
                 HexBytes('00000000000000000000000000000000'
                          '0000000000000000016a98b78c556c34')
             ],
             'data':
             '0000000000000000000000000000000000000000000000000007533f2ecb6c34'
             '000000000000000000000000000000000000000000000000016345785d8a0000'
             '0000000000000000000000000000000000000000000000000000000000000062',
         })
     ]
     chain_id = ChainID.ROPSTEN
     transaction_hash = (
         "0x330df22df6543c9816d80e582a4213b1fc11992f317be71775f49c3d853ed5be"
     )
     with \
             mock.patch('web3.eth.Eth.getTransactionReceipt') \
             as m_getTransactionReceipt, \
             mock.patch(
                 'etherscan.contracts.Contract.get_abi',
                 side_effect=self.m_get_abi, autospec=True):
         m_getTransactionReceipt.return_value.logs = mocked_logs
         decoded_methods = TransactionDebugger.decode_transaction_logs(
             chain_id, transaction_hash)
     self.assertEqual(len(decoded_methods), 2)
     decoded_method = decoded_methods[0]
     self.assertEqual(
         decoded_method['method_info']['definition'],
         'Log1(address,bytes32,uint256,string,string,uint256,bytes1,uint256)'
     )
     decoded_method = decoded_methods[1]
     self.assertEqual(
         decoded_method['method_info']['definition'],
         'LogBet(bytes32,address,uint256,uint256,uint256,uint256)')
示例#23
0
def stub_block(timestamp):
    return AttributeDict({
        'timestamp': timestamp,
        'number': 123,
    })
def test_attributedict_sequence_with_dict(sequence):
    data = sequence(['a', {'found': True}, 'c'])
    dict_in_sequence = AttributeDict.recursive(data)
    assert dict_in_sequence[1].found is True
示例#25
0
 def _castAttributeDict(self, maybe_dict):
     """Return an AttributeDict as is provided by web3 middleware."""
     if is_dict(maybe_dict) and not isinstance(maybe_dict, AttributeDict):
         return AttributeDict.recursive(maybe_dict)
     else:
         return maybe_dict
示例#26
0
def get_event_data(event_abi, log_entry):
    """
    Given an event ABI and a log entry for that event, return the decoded
    event data
    """
    if event_abi['anonymous']:
        log_topics = log_entry['topics']
    elif not log_entry['topics']:
        raise MismatchedABI("Expected non-anonymous event to have 1 or more topics")
    elif event_abi_to_log_topic(event_abi) != log_entry['topics'][0]:
        raise MismatchedABI("The event signature did not match the provided ABI")
    else:
        log_topics = log_entry['topics'][1:]

    log_topics_abi = get_indexed_event_inputs(event_abi)
    log_topic_normalized_inputs = normalize_event_input_types(log_topics_abi)
    log_topic_types = get_event_abi_types_for_decoding(log_topic_normalized_inputs)
    log_topic_names = get_abi_input_names({'inputs': log_topics_abi})

    if len(log_topics) != len(log_topic_types):
        raise ValueError("Expected {0} log topics.  Got {1}".format(
            len(log_topic_types),
            len(log_topics),
        ))

    log_data = hexstr_if_str(to_bytes, log_entry['data'])
    log_data_abi = exclude_indexed_event_inputs(event_abi)
    log_data_normalized_inputs = normalize_event_input_types(log_data_abi)
    log_data_types = get_event_abi_types_for_decoding(log_data_normalized_inputs)
    log_data_names = get_abi_input_names({'inputs': log_data_abi})

    # sanity check that there are not name intersections between the topic
    # names and the data argument names.
    duplicate_names = set(log_topic_names).intersection(log_data_names)
    if duplicate_names:
        raise ValueError(
            "Invalid Event ABI:  The following argument names are duplicated "
            "between event inputs: '{0}'".format(', '.join(duplicate_names))
        )

    decoded_log_data = decode_abi(log_data_types, log_data)
    normalized_log_data = map_abi_data(
        BASE_RETURN_NORMALIZERS,
        log_data_types,
        decoded_log_data
    )

    decoded_topic_data = [
        decode_single(topic_type, topic_data)
        for topic_type, topic_data
        in zip(log_topic_types, log_topics)
    ]
    normalized_topic_data = map_abi_data(
        BASE_RETURN_NORMALIZERS,
        log_topic_types,
        decoded_topic_data
    )

    event_args = dict(itertools.chain(
        zip(log_topic_names, normalized_topic_data),
        zip(log_data_names, normalized_log_data),
    ))

    event_data = {
        'args': event_args,
        'event': event_abi['name'],
        'logIndex': log_entry['logIndex'],
        'transactionIndex': log_entry['transactionIndex'],
        'transactionHash': log_entry['transactionHash'],
        'address': log_entry['address'],
        'blockHash': log_entry['blockHash'],
        'blockNumber': log_entry['blockNumber'],
    }

    return AttributeDict.recursive(event_data)