def _load_from_bytes(self, tx_data: bytes,
                         meta_data: bytes) -> 'BaseTransaction':
        from hathor.transaction.base_transaction import tx_or_block_from_bytes
        from hathor.transaction.transaction_metadata import TransactionMetadata

        tx = tx_or_block_from_bytes(tx_data)
        tx._metadata = TransactionMetadata.create_from_json(
            json_loadb(meta_data))
        tx.storage = self
        return tx
示例#2
0
    def render_POST(self, request):
        """ Post request /create_tx/ that returns an encoded tx, if valid

            Expects {"inputs":[{"tx_id": <hex encoded>, "index": <int>, "data": <optional base64 encoded>}],
                     "outputs":[{"value": <int, 1.00 HTR = 100>, "token_uid": <optional omit for HTR, hex encoded>,
                     "address" or "script"}]} as POST data
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'POST')

        body_content = json_loadb(request.content.read())

        raw_inputs = body_content.get('inputs', [])
        raw_outputs = body_content.get('outputs', [])

        inputs = [TxInput.create_from_dict(i) for i in raw_inputs]
        tokens = []
        outputs = [from_raw_output(i, tokens) for i in raw_outputs]

        timestamp = int(max(self.manager.tx_storage.latest_timestamp, self.manager.reactor.seconds()))
        parents = self.manager.get_new_tx_parents(timestamp)
        # this tx will have to be mined by tx-mining-server or equivalent
        tx = Transaction(
            timestamp=timestamp,
            inputs=inputs,
            outputs=outputs,
            parents=parents,
            storage=self.manager.tx_storage,
        )
        fake_signed_tx = tx.clone()
        for tx_input in fake_signed_tx.inputs:
            # conservative estimate of the input data size to estimate a valid weight
            tx_input.data = b'\0' * 107
        tx.weight = minimum_tx_weight(fake_signed_tx)
        tx.verify_unsigned_skip_pow()

        if tx.is_double_spending():
            raise InvalidNewTransaction('At least one of your inputs has already been spent.')

        hex_data = bytes(tx).hex()
        data = tx.to_json()
        data.pop('hash', None)
        data.pop('nonce', None)

        return json_dumpb({
            'success': True,
            'hex_data': hex_data,
            'data': data,
        })
示例#3
0
 def onMessage(self, payload: bytes, isBinary: bool) -> None:
     self.log.info('message', payload=payload)
     try:
         data: Union[List[Dict], Dict] = json_loadb(payload)
     except JSONDecodeError:
         return self.send_response(error=JSON_RPC_PARSE_ERROR)
     try:
         if isinstance(data, list):
             for batch_data in data:
                 self._handle_request(batch_data)
         else:
             self._handle_request(data)
     except Exception:
         self.log.warn('internal error', exc_info=True)
         return self.send_response(error=JSON_RPC_INTERNAL_ERROR)
示例#4
0
    def render_POST(self, request):
        """ POST request for /submit_block/
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'GET')

        data = json_loadb(request.content.read())

        tx = tx_or_block_from_bytes(bytes.fromhex(data['hexdata']), storage=self.manager.tx_storage)

        if not tx.is_block:
            self.log.debug('expected Block, received Transaction', data=data)
            raise APIError('Not a block')

        if not self.manager.can_start_mining():
            self.log.debug('cannot propagate Block, node syncing', data=data)
            raise APIError('Node syncing')

        res = self.manager.submit_block(tx)

        return json_dumpb({'result': res})
示例#5
0
    def lineReceived(self, line: bytes) -> None:
        """Receives a line and parses it, checking if it is a valid JSON-RPC 2.0 message.
        If the message is valid, it calls a request, result or error handler.
        Otherwise it sends an appropriate error message to the sender.

        :param line: Bytes of a serialized JSON RPC request
        :type line: bytes

        """
        self.log.debug('line received', line=line)
        try:
            data = json_loadb(line)
        except JSONDecodeError:
            return self.send_error(PARSE_ERROR,
                                   data={'message': line.decode()})
        assert isinstance(data, dict)

        msgid = data.get('id')

        if 'method' in data:
            return self.handle_request(data['method'], data.get('params'),
                                       msgid)
        elif 'result' in data and 'error' in data:
            if data['result'] and data['error'] is None:
                return self.handle_result(data['result'], msgid)
            elif data['error'] and data['result'] is None:
                return self.handle_error(data['error'], data.get('data'),
                                         msgid)
        elif 'result' in data:
            return self.handle_result(data['result'], msgid)
        elif 'error' in data:
            return self.handle_error(data['error'], data.get('data'), msgid)

        return self.send_error(
            INVALID_REQUEST,
            data={
                'message': data,
                'error':
                'Could not identify message as request, result or error.'
            })
示例#6
0
    def render_POST(self, request: Request) -> bytes:
        """ POST request for /push_tx/
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'POST')

        error_ret = json_dumpb({
            'success': False,
            'message': 'Missing hexadecimal data',
            'can_force': False
        })
        body_content = request.content.read()
        if not body_content:
            return error_ret

        data = json_loadb(body_content)

        # Need to do that because json_loadb returns an object, which is not compatible with Dict[str, Any]
        data = cast(Dict[str, Any], data)

        if 'hex_tx' not in data:
            return error_ret

        return self.handle_push_tx(data)
示例#7
0
 def json_value(self):
     return json_loadb(self.written[0])
 def _from_value_info(self, value: bytes) -> _InfoDict:
     return cast(_InfoDict, json_loadb(value))