def log_filter(chain, address, signature, topics):
    bn = chain.web3.eth.blockNumber
    topics = topics[:]
    if topics is not None:
        for i in range(len(topics)):
            topics[i] = a2t(topics[i])
    # "LogAnonymous()"
    # "NewChannel(address, address, bytes32)"
    enc_sig = eth_utils.encode_hex(event_signature_to_log_topic(signature))
    topics.insert(0, enc_sig)
    obj = {
        'fromBlock': bn,
        'toBlock': "latest",
        'address': address,
        'topics': topics
    }
    return (chain, chain.web3.eth.filter(obj).filter_id, enc_sig)
Exemple #2
0
def _encode_to_topic(event_signature):
    return event_signature_to_log_topic(event_signature)
Exemple #3
0
class LogTopics:
    LogAnonymous = encode_hex(event_signature_to_log_topic("LogAnonymous()"))
    LogNoArguments = encode_hex(event_signature_to_log_topic("LogNoArguments()"))
    LogSingleArg = encode_hex(event_signature_to_log_topic("LogSingleArg(uint256)"))
    LogSingleAnonymous = encode_hex(event_signature_to_log_topic("LogSingleAnonymous(uint256)"))
    LogSingleWithIndex = encode_hex(event_signature_to_log_topic("LogSingleWithIndex(uint256)"))
    LogDoubleArg = encode_hex(event_signature_to_log_topic("LogDoubleArg(uint256,uint256)"))
    LogDoubleAnonymous = encode_hex(event_signature_to_log_topic("LogDoubleAnonymous(uint256,uint256)"))  # noqa: E501
    LogDoubleWithIndex = encode_hex(event_signature_to_log_topic("LogDoubleWithIndex(uint256,uint256)"))  # noqa: E501
    LogTripleArg = encode_hex(event_signature_to_log_topic("LogTripleArg(uint256,uint256,uint256)"))
    LogTripleWithIndex = encode_hex(event_signature_to_log_topic("LogTripleWithIndex(uint256,uint256,uint256)"))  # noqa: E501
    LogQuadrupleArg = encode_hex(event_signature_to_log_topic("LogQuadrupleArg(uint256,uint256,uint256,uint256)"))  # noqa: E501
    LogQuadrupleWithIndex = encode_hex(event_signature_to_log_topic("LogQuadrupleWithIndex(uint256,uint256,uint256,uint256)"))  # noqa: E501
    LogBytes = encode_hex(event_signature_to_log_topic("LogBytes(bytes)"))
    LogString = encode_hex(event_signature_to_log_topic("LogString(string)"))
    LogDynamicArgs = encode_hex(event_signature_to_log_topic("LogDynamicArgs(string,string)"))
    LogListArgs = encode_hex(event_signature_to_log_topic("LogListArgs(bytes2[],bytes2[])"))
    LogAddressIndexed = encode_hex(event_signature_to_log_topic(
        "LogAddressIndexed(address,address)"))
    LogAddressNotIndexed = encode_hex(event_signature_to_log_topic(
        "LogAddressNotIndexed(address,address)"))
Exemple #4
0
    CollationHeader, )


class NextLogUnavailable(Exception):
    pass


class NoCandidateHead(Exception):
    pass


# For handling logs filtering
# Event:
#   CollationAdded(indexed uint256 shard, bytes collationHeader, bool isNewHead, uint256 score)
COLLATION_ADDED_TOPIC = event_signature_to_log_topic(
    "CollationAdded(int128,int128,bytes32,bytes32,bytes32,address,bytes32,bytes32,int128,bool,int128)"  # noqa: E501
)


@to_dict
def parse_collation_added_log(log):
    # `shard_id` is the first indexed entry,hence the second entry in topics
    shard_id_bytes32 = log['topics'][1]
    data_bytes = decode_hex(log['data'])
    header_bytes = shard_id_bytes32 + data_bytes[:-64]
    is_new_head = bool(big_endian_to_int(data_bytes[-64:-32]))
    score = big_endian_to_int(data_bytes[-32:])
    collation_header = CollationHeader.from_bytes(header_bytes)
    yield 'header', collation_header
    yield 'is_new_head', is_new_head
    yield 'score', score
Exemple #5
0
class LogTopics(object):
    LogAnonymous = encode_hex(event_signature_to_log_topic("LogAnonymous()"))
    LogNoArguments = encode_hex(
        event_signature_to_log_topic("LogNoArguments()"))
    LogSingleArg = encode_hex(
        event_signature_to_log_topic("LogSingleArg(uint256)"))
    LogSingleAnonymous = encode_hex(
        event_signature_to_log_topic("LogSingleAnonymous(uint256)"))
    LogSingleWithIndex = encode_hex(
        event_signature_to_log_topic("LogSingleWithIndex(uint256)"))
    LogDoubleArg = encode_hex(
        event_signature_to_log_topic("LogDoubleArg(uint256,uint256)"))
    LogDoubleAnonymous = encode_hex(
        event_signature_to_log_topic("LogDoubleAnonymous(uint256,uint256)"))
    LogDoubleWithIndex = encode_hex(
        event_signature_to_log_topic("LogDoubleWithIndex(uint256,uint256)"))
    LogTripleArg = encode_hex(
        event_signature_to_log_topic("LogTripleArg(uint256,uint256,uint256)"))
    LogTripleWithIndex = encode_hex(
        event_signature_to_log_topic(
            "LogTripleWithIndex(uint256,uint256,uint256)"))
    LogQuadrupleArg = encode_hex(
        event_signature_to_log_topic(
            "LogQuadrupleArg(uint256,uint256,uint256,uint256)"))
    LogQuadrupleWithIndex = encode_hex(
        event_signature_to_log_topic(
            "LogQuadrupleWithIndex(uint256,uint256,uint256,uint256)"))
    LogBytes = encode_hex(event_signature_to_log_topic("LogBytes(bytes)"))
    LogString = encode_hex(event_signature_to_log_topic("LogString(string)"))
    LogDynamicArgs = encode_hex(
        event_signature_to_log_topic("LogDynamicArgs(string,string)"))
Exemple #6
0
class ShardTracker:
    '''Track logs `CollationAdded` in mainchain
    '''
    # For handling logs filtering
    # Event:
    #   CollationAdded(indexed uint256 shard, bytes collationHeader, bool isNewHead, uint256 score)
    COLLATION_ADDED_TOPIC = event_signature_to_log_topic(
        "CollationAdded(int128,int128,bytes32,bytes32,bytes32,address,bytes32,bytes32,int128,bool,int128)"  # noqa: E501
    )
    # older <---------------> newer
    current_score = None
    new_logs = None
    unchecked_logs = None

    def __init__(self, shard_id, log_handler, vmc_address):
        # TODO: currently set one log_handler for each shard. Should see if there is a better way
        #       to make one log_handler shared over all shards.
        self.shard_id = shard_id
        self.log_handler = log_handler
        self.vmc_address = vmc_address
        self.current_score = None
        # older <---------------> newer
        self.new_logs = []
        self.unchecked_logs = []

    @to_tuple
    def _get_new_logs(self):
        shard_id_topic_hex = encode_hex(
            self.shard_id.to_bytes(32, byteorder='big'))
        new_logs = self.log_handler.get_new_logs(
            address=self.vmc_address,
            topics=[
                encode_hex(self.COLLATION_ADDED_TOPIC),
                shard_id_topic_hex,
            ],
        )
        for log in new_logs:
            yield parse_collation_added_log(log)

    def get_next_log(self):
        new_logs = self._get_new_logs()
        self.new_logs.extend(new_logs)
        if len(self.new_logs) == 0:
            raise NextLogUnavailable("No more next logs")
        return self.new_logs.pop()

    # TODO: this method may return wrong result when new logs arrive before the logs inside
    #       `self.new_logs` are consumed entirely. This issue can be resolved by saving the
    #       status of `new_logs`, `unchecked_logs`, and `current_score`, when it start to run
    #       `GUESS_HEAD`. If there is a new block arriving, just restore them to the saved status,
    #       append new logs to `new_logs`, and re-run `GUESS_HEAD`
    def fetch_candidate_head(self):
        # Try to return a log that has the score that we are checking for,
        # checking in order of oldest to most recent.
        unchecked_logs = pipe(
            self.unchecked_logs,
            enumerate,
            tuple,
            reversed,
            tuple,
        )
        current_score = self.current_score

        for idx, logs_entry in unchecked_logs:
            if logs_entry['score'] == current_score:
                return self.unchecked_logs.pop(idx)
        # If no further recorded but unchecked logs exist, go to the next
        # is_new_head = true log
        while True:
            # TODO: currently just raise when there is no log anymore
            log_entry = self.get_next_log()
            if log_entry['is_new_head']:
                break
            self.unchecked_logs.append(log_entry)
        self.current_score = log_entry['score']
        return log_entry