Exemple #1
0
        def fill_content(content: Dict[str, Any]) -> Dict[str, Any]:
            if validation_passes[content['kind']] == 3:
                _gas_limit, _storage_limit, _fee = gas_limit, storage_limit, fee

                if _gas_limit is None:
                    _gas_limit = OperationResult.consumed_gas(content)
                    if content['kind'] in ['origination', 'transaction']:
                        _gas_limit += gas_reserve

                if storage_limit is None:
                    _paid_storage_size_diff = OperationResult.paid_storage_size_diff(content)
                    _burned = OperationResult.burned(content)
                    _storage_limit = _paid_storage_size_diff + _burned
                    if content['kind'] in ['origination', 'transaction']:
                        _storage_limit += burn_reserve

                if _fee is None:
                    _fee = calculate_fee(content, _gas_limit, extra_size)

                current_counter = int(content['counter'])
                content.update(
                    gas_limit=str(_gas_limit),
                    storage_limit=str(_storage_limit),
                    fee=str(_fee),
                    counter=str(current_counter + self.context.get_counter_offset()),
                )

            content.pop('metadata')
            logger.debug("autofilled transaction content: %s" % content)
            return content
Exemple #2
0
    def callback_view(self):
        """Get return value of an on-chain callback method.

        :returns: Decoded parameters of a callback
        """
        if self.address:
            initial_storage = self.shell.blocks[
                self.context.block_id].context.contracts[
                    self.address].storage()
        else:
            storage_ty = StorageSection.match(self.context.storage_expr)
            initial_storage = storage_ty.dummy(
                self.context).to_micheline_value(lazy_diff=True)

        operations, _, stdout, error = Interpreter.run_view(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage=initial_storage,
            context=self.context,
        )
        if not len(operations) == 1:
            raise Exception(
                'Multiple internal operations, not sure which one to pick')
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        return operations[0]
Exemple #3
0
    def interpret(
        self,
        storage=None,
        source=None,
        sender=None,
        amount=None,
        balance=None,
        chain_id=None,
        level=None,
        now=None,
        self_address=None,
    ) -> ContractCallResult:
        """Run code in the builtin REPL (WARNING! Not recommended for critical tasks).

        :param storage: initial storage as Python object, leave None if you want to generate a dummy one
        :param source: patch SOURCE
        :param sender: patch SENDER
        :param amount: patch AMOUNT
        :param balance: patch BALANCE
        :param chain_id: patch CHAIN_ID
        :param level: patch LEVEL
        :param now: patch NOW
        :param self_address: patch SELF/SELF_ADDRESS
        :rtype: pytezos.contract.result.ContractCallResult
        """
        storage_ty = StorageSection.match(self.context.storage_expr)
        if storage is None:
            initial_storage = storage_ty.dummy(
                self.context).to_micheline_value(lazy_diff=True)
        else:
            initial_storage = storage_ty.from_python_object(
                storage).to_micheline_value(lazy_diff=True)
        assert self.context.script
        operations, storage, lazy_diff, stdout, error = Interpreter.run_code(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage=initial_storage,
            script=self.context.script['code'],
            source=source,
            sender=sender or source,
            amount=amount or self.amount,
            balance=balance,
            chain_id=chain_id,
            level=level,
            now=now,
            address=self_address,
        )
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        res = {
            'operations': operations,
            'storage': storage,
            'lazy_diff': lazy_diff,
        }
        return ContractCallResult.from_run_code(
            res,
            parameters=self.parameters,
            context=self.context,
        )
Exemple #4
0
    def pull(cls, stack: MichelsonStack, stdout: List[str],
             context: AbstractContext):
        res_type: MichelsonType
        literal: Type[MichelineLiteral]
        res_type, literal = cls.args  # type: ignore
        res = res_type.from_literal(literal)
        if res_type.is_pushable():
            expected_res = stack.pop1()
        elif res_type.prim == 'big_map':
            if issubclass(literal, MichelineSequence):
                expected_res = stack.pop1()
            else:
                expected_res = stack.pop1()
                # NOTE: We care about validity of the pointer, not it's contents
                res = expected_res
        else:
            raise Exception(
                f'`{res_type.prim}` is neither pushable nor big_map')

        if res != expected_res:
            logger.debug('expected: %s(%s)', expected_res.__class__.__name__,
                         expected_res.__dict__)
            logger.debug('actual: %s(%s)', res.__class__.__name__,
                         res.__dict__)
            raise Exception('Stack content is not equal to expected')

        stdout.append(format_stdout(cls.prim, [], [res]))  # type: ignore
Exemple #5
0
def walk_state_change_interval(head: int, last: int, get: Callable, equals: Callable,
                               head_value: Any, last_value: Any) -> Generator:
    level = last
    value = last_value
    while not equals(value, head_value):
        level, value = find_state_change(head, level, get, equals, pred_value=value)
        logger.debug('%s -> %s at %s' % last_value, value, level)
        yield level, value
Exemple #6
0
 def wrapper(*args, **kwargs):
     for attempt in range(REQUEST_RETRY_COUNT):
         logger.debug('Node request attempt %s/%s', attempt + 1, REQUEST_RETRY_COUNT)
         try:
             return fn(*args, **kwargs)
         except requests.exceptions.ConnectionError as e:
             if attempt + 1 == REQUEST_RETRY_COUNT:
                 raise e
             logger.warning(e)
             time.sleep(REQUEST_RETRY_SLEEP)
Exemple #7
0
    def bisect(start: int, end: int):
        if end == start + 1:
            return end, get(end)

        level = (end + start) // 2
        value = get(level)
        logger.debug('%s at level %s' % value, level)

        if equals(value, pred_value):
            return bisect(level, end)
        else:
            return bisect(start, level)
Exemple #8
0
    def request(self, method: str, path: str, **kwargs) -> requests.Response:
        """Perform HTTP request to node.

        :param method: one of GET/POST/PUT/DELETE
        :param path: path to endpoint
        :param kwargs: requests.request arguments
        :raises RpcError: node has returned an error
        :returns: node response
        """
        logger.debug('>>>>> %s %s\n%s', method, path,
                     json.dumps(kwargs, indent=4))
        res = requests.request(
            method=method,
            url=_urljoin(self.uri[0], path),
            headers={
                'content-type': 'application/json',
                'user-agent': 'PyTezos',
            },
            **kwargs,
        )
        if res.status_code == 404:
            logger.debug('<<<<< %s\n%s', res.status_code, res.text)
            raise RpcError(f'Not found: {path}')
        if res.status_code != 200:
            logger.debug('<<<<< %s\n%s', res.status_code,
                         pformat(res.text, indent=4))
            raise RpcError.from_response(res)

        logger.debug('<<<<< %s\n%s', res.status_code,
                     json.dumps(res.json(), indent=4))
        return res
Exemple #9
0
    def storage_view(self):
        """Get return value of an off-chain storage view.

        :returns: Decoded parameters of a callback
        """
        _, storage, stdout, error = Interpreter.run_view(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage={'prim': 'None'},
            context=self.context,
        )
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        return storage  # type: ignore
Exemple #10
0
    def find_operation(self, operation_group_hash) -> dict:
        """ Find operation by hash.

        :param operation_group_hash: base58
        :raises: StopIteration if not found
        """
        last, head = self.get_range()
        if self._start < 0:
            levels = range(head, max(1, last - 1), -1)
        else:
            levels = range(last, head, 1)

        for block_level in levels:
            try:
                logger.debug(f'checking level %s...' % block_level)
                return self._getitem(block_level).operations[operation_group_hash]()
            except StopIteration:
                continue

        raise StopIteration(operation_group_hash)
Exemple #11
0
    def callback_view(self):
        """ Get return value of an on-chain callback method

        :returns: Decoded parameters of a callback
        """
        if self.address:
            initial_storage = self.shell.blocks[
                self.context.block_id].context.contracts[
                    self.address].storage()
        else:
            storage_ty = StorageSection.match(self.context.storage_expr)
            initial_storage = storage_ty.dummy(
                self.context).to_micheline_value(lazy_diff=True)

        res, stdout, error = Interpreter.run_view(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage=initial_storage,
            context=self.context)
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        return res
Exemple #12
0
    def get_counter_offset(self) -> int:
        """Return current count of pending transactions in mempool.
        """
        if self.key is None:
            raise Exception('`key` is not set')
        if self.shell is None:
            raise Exception('`shell` is not set')

        counter_offset = 0
        key_hash = self.key.public_key_hash()
        mempool = self.shell.mempool.pending_operations()

        for operations in mempool.values():
            for operation in operations:
                if isinstance(operation, list):
                    operation = operation[1]
                for content in operation.get('contents', []):
                    if content.get('source') == key_hash:
                        logger.debug("pending transaction in mempool: %s" %
                                     content)
                        counter_offset += 1

        logger.debug("counter offset: %s" % counter_offset)
        return counter_offset
Exemple #13
0
def find_state_change_intervals(head: int, last: int, get: Callable, equals: Callable,
                                step=60) -> Generator:
    succ_value = get(head)
    logger.debug('%s at head %s' % succ_value, head)

    for level in range(head - step, last, -step):
        value = get(level)
        logger.debug('%s at level %s' % value, level)

        if not equals(value, succ_value):
            logger.debug('%s -> %s at (%s, {level + step})' % value, succ_value, level)
            yield level + step, succ_value, level, value
            succ_value = value
Exemple #14
0
    def request(self, method, path, **kwargs) -> requests.Response:
        logger.debug('>>>>> %s %s\n%s', method, path,
                     json.dumps(kwargs, indent=4))
        res = self._session.request(method=method,
                                    url=urljoin(self.uri, path),
                                    headers={
                                        'content-type': 'application/json',
                                        'user-agent': 'PyTezos'
                                    },
                                    **kwargs)
        if res.status_code == 404:
            logger.debug('<<<<< %s\n%s', res.status_code, res.text)
            raise RpcError(f'Not found: {path}')
        elif res.status_code != 200:
            logger.debug('<<<<< %s\n%s', res.status_code,
                         pformat(res.text, indent=4))
            raise RpcError.from_response(res)

        logger.debug('<<<<< %s\n%s', res.status_code,
                     json.dumps(res.json(), indent=4))
        return res