Example #1
0
class Disconnect(BaseCommand[DisconnectReason]):
    protocol_command_id = 1
    serialization_codec = RLPCodec(
        sedes=DISCONNECT_STRUCTURE,
        process_outbound_payload_fn=compose(lambda v: (v, ),
                                            operator.attrgetter('value')),
        process_inbound_payload_fn=compose(DisconnectReason,
                                           operator.itemgetter(0)),
    )
Example #2
0
def get_request_formatters(
    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Dict[str, Callable[..., Any]]:
    request_formatter_maps = (METHOD_NORMALIZERS, PYTHONIC_REQUEST_FORMATTERS,
                              ABI_REQUEST_FORMATTERS)
    formatters = combine_formatters(request_formatter_maps, method_name)
    return compose(*formatters)
Example #3
0
    def register(self, topic: Topic, enr: ENRAPI, current_time: float) -> None:
        """
        Register a new ad.

        A `ValueError` will be raised if the ad cannot be added because the table is full,
        because the node already is present in the queue, or because the topic's wait time is
        non-zero.
        """
        queue = self.topic_queues[topic]

        wait_time = self.get_wait_time(topic, current_time)
        if wait_time > 0:
            raise ValueError(
                f"Topic queue or table is full (time to wait: {wait_time})")

        present_node_ids = tuple(entry.node_id
                                 for entry in self.get_enrs_for_topic(topic))
        if enr.node_id in present_node_ids[:self.max_queue_size - 1]:
            raise ValueError(
                f"Topic queue already contains entry for node {encode_hex(enr.node_id)}"
            )

        if self.is_full:
            queues = [queue for queue in self.topic_queues.values() if queue]
            queue_with_oldest_ad = min(
                queues,
                key=toolz.compose(operator.attrgetter("registration_time"),
                                  operator.itemgetter(-1)),
            )
            queue_with_oldest_ad.pop()
            self.total_size -= 1

        self.total_size -= len(queue)
        queue.appendleft(Ad(enr=enr, registration_time=current_time))
        self.total_size += len(queue)
Example #4
0
class Status(BaseCommand[StatusPayload]):
    protocol_command_id = 0
    serialization_codec: RLPCodec[StatusPayload] = RLPCodec(
        sedes=STATUS_STRUCTURE,
        process_inbound_payload_fn=compose(
            lambda args: StatusPayload(*args), ),
    )
Example #5
0
class ContractCodes(BaseCommand[ContractCodesPayload]):
    protocol_command_id = 11
    serialization_codec = RLPCodec(
        sedes=CONTRACT_CODES_STRUCTURE,
        process_inbound_payload_fn=compose(
            lambda args: ContractCodesPayload(*args), ),
    )
Example #6
0
class ProofsV2(BaseCommand[ProofsPayloadV2]):
    protocol_command_id = 16
    serialization_codec = RLPCodec(
        sedes=PROOFS_V2_STRUCTURE,
        process_inbound_payload_fn=compose(
            lambda args: ProofsPayloadV2(*args), ),
    )
Example #7
0
def get_error_formatters(method_name):
    #  Note error formatters work on the full response dict
    # TODO - test this function
    error_formatter_maps = ()
    formatters = combine_formatters(error_formatter_maps, method_name)

    return compose(*formatters)
Example #8
0
def get_result_formatters(method_name):
    formatters = combine_formatters((PYTHONIC_RESULT_FORMATTERS, ),
                                    method_name)
    attrdict_formatter = apply_formatter_if(is_dict and not_attrdict,
                                            AttributeDict.recursive)

    return compose(*formatters, attrdict_formatter)
Example #9
0
def test_gap_continuity(changes):
    MAX_BLOCK_NUM = 21

    # method to get all the block numbers that are in a gap right now
    _all_missing = compose(
        set, partial(_all_gap_numbers, highest_block_number=MAX_BLOCK_NUM))

    @to_set
    def _all_inserted(chain_gaps):
        """List all the inserted headers, the block numbers not in gaps"""
        missing = _all_missing(chain_gaps)
        for block_num in range(MAX_BLOCK_NUM + 1):
            if block_num not in missing:
                yield block_num

    chain_gaps = GENESIS_CHAIN_GAPS

    for do_insert, block_num in changes:
        starts_inserted = _all_inserted(chain_gaps)
        starts_missing = _all_missing(chain_gaps)

        if do_insert:
            to_insert = block_num
            _, chain_gaps = fill_gap(to_insert, chain_gaps)
            assert not is_block_number_in_gap(to_insert, chain_gaps)

            # Make sure that at most this one block number was filled
            finished_inserted = _all_inserted(chain_gaps)
            assert to_insert in finished_inserted
            new_inserts = finished_inserted - starts_inserted
            if block_num in starts_inserted:
                assert new_inserts == set()
            else:
                assert new_inserts == {block_num}

            # Make sure that no new gaps were created
            finished_missing = _all_missing(chain_gaps)
            assert to_insert not in finished_missing
            new_missing = finished_missing - starts_missing
            assert new_missing == set()
        else:
            to_remove = block_num
            # Note that removing a header is inserting a gap
            chain_gaps = reopen_gap(to_remove, chain_gaps)
            assert is_block_number_in_gap(to_remove, chain_gaps)

            # Make sure that no gaps were filled
            finished_inserted = _all_inserted(chain_gaps)
            new_inserts = finished_inserted - starts_inserted
            assert new_inserts == set()

            # Make sure that at most this one block number gap was reopened
            finished_missing = _all_missing(chain_gaps)
            new_missing = finished_missing - starts_missing
            if block_num in starts_missing:
                assert new_missing == set()
            else:
                assert new_missing == {block_num}

        _validate_gap_invariants(chain_gaps)
Example #10
0
    def sign_and_send_raw_middleware(
            make_request: Callable[[RPCEndpoint, Any], Any],
            w3: "Web3") -> Callable[[RPCEndpoint, Any], RPCResponse]:
        format_and_fill_tx = compose(format_transaction,
                                     fill_transaction_defaults(w3),
                                     fill_nonce(w3))

        def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
            if method != "eth_sendTransaction":
                return make_request(method, params)
            else:
                transaction = format_and_fill_tx(params[0])

            if 'from' not in transaction:
                return make_request(method, params)
            elif transaction.get('from') not in accounts:
                return make_request(method, params)

            account = accounts[transaction['from']]
            raw_tx = account.sign_transaction(transaction).rawTransaction

            return make_request(RPCEndpoint("eth_sendRawTransaction"),
                                [raw_tx])

        return middleware
Example #11
0
def get_error_formatters(
    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Callable[..., Any]:
    #  Note error formatters work on the full response dict
    error_formatter_maps = (ERROR_FORMATTERS, )
    formatters = combine_formatters(error_formatter_maps, method_name)

    return compose(*formatters)
Example #12
0
class Status(BaseCommand[StatusPayload]):
    protocol_command_id = 0
    serialization_codec: RLPCodec[StatusPayload] = RLPCodec(
        sedes=sedes.List(
            (sedes.big_endian_int, sedes.big_endian_int, sedes.big_endian_int,
             hash_sedes, hash_sedes, ForkID)),
        process_inbound_payload_fn=compose(
            lambda args: StatusPayload(*args), ),
    )
Example #13
0
class NewBlock(BaseCommand[NewBlockPayload]):
    protocol_command_id = 7
    serialization_codec = RLPCodec(sedes=NEW_BLOCK_STRUCTURE,
                                   process_inbound_payload_fn=compose(
                                       lambda args: NewBlockPayload(*args),
                                       apply_formatter_at_index(
                                           lambda args: BlockFields(*args),
                                           0,
                                       )))
Example #14
0
def get_error_formatters(
    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Dict[str, Callable[..., Any]]:
    #  Note error formatters work on the full response dict
    # TODO - test this function
    error_formatter_maps = ()
    formatters = combine_formatters(error_formatter_maps, method_name)

    return compose(*formatters)
Example #15
0
class GetBlockHeaders(BaseCommand[GetBlockHeadersPayload]):
    protocol_command_id = 2
    serialization_codec = RLPCodec(
        sedes=GET_BLOCK_HEADERS_STRUCTURE,
        process_inbound_payload_fn=compose(
            lambda args: GetBlockHeadersPayload(*args),
            apply_formatter_at_index(lambda args: BlockHeadersQuery(*args),
                                     1)),
    )
Example #16
0
def get_result_formatters(
    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Dict[str, Callable[..., Any]]:
    formatters = combine_formatters((PYTHONIC_RESULT_FORMATTERS, ),
                                    method_name)
    attrdict_formatter = apply_formatter_if(is_dict and not_attrdict,
                                            AttributeDict.recursive)

    return compose(attrdict_formatter, *formatters)
Example #17
0
 def _find_oldest_unpruned_task_id(self, finished_task_id: TTaskID) -> TTaskID:
     get_dependency_of_id = compose(
         curry(do)(self._validate_has_task),
         self._dependency_of,
         attrgetter('task'),
         self._tasks.get,
     )
     ancestors = iterate(get_dependency_of_id, finished_task_id)
     return nth(self._max_depth, ancestors)
Example #18
0
    def normalize_result(msg: Tuple[BlockBody, ...]) -> BlockBodyBundles:
        uncles_hashes = tuple(
            map(compose(keccak, rlp.encode),
                tuple(body.uncles for body in msg)))
        transaction_roots_and_trie_data = tuple(
            map(make_trie_root_and_nodes,
                tuple(body.transactions for body in msg)))

        body_bundles = tuple(
            zip(msg, transaction_roots_and_trie_data, uncles_hashes))
        return body_bundles
Example #19
0
 def _revert_pending_transaction_filter(self, filter):
     is_valid_transaction_hash = excepts(
         (TransactionNotFound,),
         compose(
             bool,
             self.get_transaction_by_hash,
             self.normalizer.normalize_outbound_transaction_hash,
         ),
         lambda v: False,
     )
     values_to_remove = remove(is_valid_transaction_hash, filter.get_all())
     filter.remove(*values_to_remove)
Example #20
0
class NewBlock(BaseCommand[NewBlockPayload]):
    protocol_command_id = 7
    serialization_codec: RLPCodec[NewBlockPayload] = RLPCodec(
        sedes=sedes.List((sedes.List(
            (BlockHeader, sedes.CountableList(UninterpretedTransactionRLP),
             sedes.CountableList(BlockHeader))), sedes.big_endian_int)),
        process_inbound_payload_fn=compose(
            lambda args: NewBlockPayload(*args),
            apply_formatter_at_index(
                lambda args: BlockFields(*args),
                0,
            )))
Example #21
0
 def _revert_block_filter(self, filter):
     is_valid_block_hash = excepts(
         (BlockNotFound,),
         compose(
             bool,
             self.get_block_by_hash,
             self.normalizer.normalize_outbound_block_hash,
         ),
         lambda v: False,
     )
     values_to_remove = tuple(remove(is_valid_block_hash, filter.get_all()))
     filter.remove(*values_to_remove)
Example #22
0
class GetContractCodes(BaseCommand[GetContractCodesPayload]):
    protocol_command_id = 10
    serialization_codec = RLPCodec(
        sedes=GET_CONTRACT_CODES_STRUCTURE,
        process_inbound_payload_fn=compose(
            lambda args: GetContractCodesPayload(*args),
            apply_formatter_at_index(
                apply_formatter_to_array(
                    lambda args: ContractCodeRequest(*args)),
                1,
            ),
        ),
    )
Example #23
0
    def _prune_forward(self, root_id: TTaskID, depth: int) -> Tuple[TTaskID]:
        """
        Prune all forks forward from the root
        """
        def prune_parent(prune_task_id: TTaskID) -> Set[TTaskID]:
            children = self._dependencies.pop(prune_task_id, set())
            del self._tasks[prune_task_id]
            if prune_task_id in self._declared_finished:
                self._declared_finished.remove(prune_task_id)
            return children

        prune_parent_list = compose(tuple, curry(mapcat)(prune_parent))
        prune_trunk = repeat(prune_parent_list, depth)
        return pipe((root_id, ), *prune_trunk)
Example #24
0
def get_result_formatters(
    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]],
    module: "Module",
) -> Dict[str, Callable[..., Any]]:
    formatters = combine_formatters((PYTHONIC_RESULT_FORMATTERS, ),
                                    method_name)
    formatters_requiring_module = combine_formatters(
        (FILTER_RESULT_FORMATTERS, ), method_name)

    partial_formatters = apply_module_to_formatters(
        formatters_requiring_module, module, method_name)
    attrdict_formatter = apply_formatter_if(is_dict and not_attrdict,
                                            AttributeDict.recursive)
    return compose(*partial_formatters, attrdict_formatter, *formatters)
Example #25
0
def get_request_formatters(
    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Dict[str, Callable[..., Any]]:
    request_formatter_maps = (
        ABI_REQUEST_FORMATTERS,
        # METHOD_NORMALIZERS needs to be after ABI_REQUEST_FORMATTERS
        # so that eth_getLogs's apply_formatter_at_index formatter
        # is applied to the whole address
        # rather than on the first byte of the address
        METHOD_NORMALIZERS,
        PYTHONIC_REQUEST_FORMATTERS,
    )
    formatters = combine_formatters(request_formatter_maps, method_name)
    return compose(*formatters)
Example #26
0
 def mine_blocks(self, num_blocks=1, coinbase=None):
     for _ in range(num_blocks):
         block_to_mine = dissoc(self.block, 'hash')
         block_hash = fake_rlp_hash(block_to_mine)
         mined_block = assoc(block_to_mine, 'hash', block_hash)
         assign_block_info = compose(
             partial(assoc, key='block_number',
                     value=mined_block['number']),
             partial(assoc, key='block_hash', value=mined_block['hash']),
         )
         mined_block['transactions'] = tuple(
             assign_block_info(transaction)
             for transaction in mined_block['transactions'])
         self.blocks.append(mined_block)
         self.block = make_block_from_parent(mined_block)
         yield block_hash
Example #27
0
    def __init__(self, chain: BaseAsyncChain, peer_pool: BaseChainPeerPool,
                 stitcher: HeaderStitcher, token: CancelToken) -> None:
        super().__init__(token=token)
        self._chain = chain
        self._stitcher = stitcher
        max_pending_fillers = 50
        self._filler_header_tasks = TaskQueue(
            max_pending_fillers,
            # order by block number of the parent header
            compose(attrgetter('block_number'), itemgetter(0)),
        )

        # queue up idle peers, ordered by speed that they return block bodies
        self._waiting_peers: WaitingPeers[TChainPeer] = WaitingPeers(
            BaseBlockHeaders)
        self._peer_pool = peer_pool
Example #28
0
 def _find_root(self, task_id: TTaskID) -> Tuple[TTaskID, int]:
     """
     return the oldest root, and the depth to it from the seed task
     """
     root_candidate = task_id
     get_dependency_of_id = compose(self._dependency_of, attrgetter('task'), self._tasks.get)
     # We'll use the maximum saved history (_max_depth) to cap how long the stale cache
     # of history might get, when pruning. Increasing the cap should not be a problem, if needed.
     for depth in range(0, self._max_depth):
         dependency = get_dependency_of_id(root_candidate)
         if dependency not in self._tasks:
             return root_candidate, depth
         else:
             root_candidate = dependency
     raise ValidationError(
         f"Stale task history too long ({depth}) before pruning. {dependency} is still in cache."
     )
Example #29
0
    def __init__(self, chain: AsyncChainAPI, peer_pool: BaseChainPeerPool,
                 stitcher: HeaderStitcher) -> None:
        self.logger = get_logger('trinity.sync.common.headers.SkeletonSyncer')
        self._chain = chain
        self._stitcher = stitcher
        max_pending_fillers = 50
        self._filler_header_tasks = TaskQueue(
            max_pending_fillers,
            # order by block number of the parent header
            compose(attrgetter('block_number'), itemgetter(0)),
        )

        # queue up idle peers, ordered by speed that they return block bodies
        self._waiting_peers: WaitingPeers[TChainPeer] = WaitingPeers(
            (ETHBlockHeaders, LESBlockHEaders), )
        self._peer_pool = peer_pool
        self.sync_progress: SyncProgress = None
Example #30
0
    def get_ancestors(self, limit: int, header: BlockHeaderAPI) -> Tuple[BlockAPI, ...]:
        ancestor_count = min(header.block_number, limit)

        # We construct a temporary block object
        vm_class = self.get_vm_class_for_block_number(header.block_number)
        block_class = vm_class.get_block_class()
        block = block_class(header=header, uncles=[], transactions=[])

        ancestor_generator = iterate(compose(
            self.get_block_by_hash,
            operator.attrgetter('parent_hash'),
            operator.attrgetter('header'),
        ), block)
        # we peel off the first element from the iterator which will be the
        # temporary block object we constructed.
        next(ancestor_generator)

        return tuple(take(ancestor_count, ancestor_generator))