def test_match_values(self):
        pubkey_hash = '6o6ul2c+sqAariBVW+CwNaSJb9w='
        pubkey = 'Awmloohhey8WhajdDURgvbk1z3JHX2vxDSBjz9uG9wEp'
        # ./hathor-cli oracle-encode-data str:some_id int:1543974403 int:100
        oracle_data = 'B3NvbWVfaWQEXAcuAwFk'
        oracle_signature = 'MEYCIQC5cyg1tOY4oyPZ5KY7ugWJGRShrsSPxr8AxxyuvO5PYwIhAOxHBDMid7aRXe' \
                           '+85rIaDPI2ussIcw54avaFWfT9svSp'

        address = base58.b58decode(self.get_address(0))

        # they should be the same
        nc = NanoContractMatchValues(base64.b64decode(pubkey_hash), 1543970403,
                                     'some_id'.encode('utf-8'), {address: 100})
        script = nc.create_output_script()
        nc2 = NanoContractMatchValues.parse_script(script)
        self.assertIsNotNone(nc2)
        self.assertEqual(json.dumps(nc.to_human_readable()),
                         json.dumps(nc2.to_human_readable()))

        # if we add some more bytes, parsing should not match
        script2 = script + b'00'
        nc3 = NanoContractMatchValues.parse_script(script2)
        self.assertIsNone(nc3)

        # test script eval is true
        input_data = NanoContractMatchValues.create_input_data(
            base64.b64decode(oracle_data), base64.b64decode(oracle_signature),
            base64.b64decode(pubkey))
        txin = TxInput(b'aa', 0, input_data)
        spent_tx = Transaction(outputs=[TxOutput(20, script)])
        tx = Transaction(
            outputs=[TxOutput(20, P2PKH.create_output_script(address))])
        script_eval(tx, txin, spent_tx)
Exemple #2
0
    def render_GET(self, request):
        """ Get request /wallet/nano-contract/decode/ that returns the tx decoded, if success

        Expects 'hex_tx' as GET parameter

        :rtype: string (json)
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'GET')

        if b'hex_tx' in request.args:
            requested_decode = request.args[b'hex_tx'][0].decode('utf-8')
        else:
            return get_missing_params_msg('hex_tx')

        pattern = r'[a-fA-F\d]+'
        if re.match(pattern,
                    requested_decode) and len(requested_decode) % 2 == 0:
            tx_bytes = bytes.fromhex(requested_decode)

            try:
                tx = Transaction.create_from_struct(tx_bytes)
            except struct.error:
                data = {'success': False, 'message': 'Invalid transaction'}
                return json.dumps(data).encode('utf-8')

            outputs = []
            nano_contract = None
            for _output in tx.outputs:
                _nano_contract = NanoContractMatchValues.parse_script(
                    _output.script)
                if _nano_contract:
                    nano_contract = _nano_contract.to_human_readable()
                    nano_contract['value'] = _output.value
                    continue
                else:
                    outputs.append(_output.to_human_readable())

            my_inputs, other_inputs = self.manager.wallet.separate_inputs(
                tx.inputs, self.manager.tx_storage)

            my_inputs = [_in.to_human_readable() for _in in my_inputs]
            other_inputs = [_in.to_human_readable() for _in in other_inputs]

            data = {
                'success': True,
                'nano_contract': nano_contract,
                'outputs': outputs,
                'my_inputs': my_inputs,
                'other_inputs': other_inputs
            }
        else:
            data = {'success': False, 'message': 'Invalid transaction'}
        return json.dumps(data).encode('utf-8')
Exemple #3
0
    def to_human_readable(self) -> Dict[str, Any]:
        """Checks what kind of script this is and returns it in human readable form
        """
        from hathor.transaction.scripts import parse_address_script, NanoContractMatchValues

        script_type = parse_address_script(self.script)
        if script_type:
            ret = script_type.to_human_readable()
            ret['value'] = self.value
            ret['token_data'] = self.token_data
            return ret

        nano_contract = NanoContractMatchValues.parse_script(self.script)
        if nano_contract:
            return nano_contract.to_human_readable()

        return {}
    def render_PUT(self, request):
        """ Updates a nano contract tx and returns it in hexadecimal format.

        Post data should be a json with the following items:
        hex_tx: tx being updated, in hex value
        new_values: List[{'address', 'value'}], with bet address and value
        input_value: amount this wallet should stake in the nano contract

        :rtype: string (json)
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'PUT')

        try:
            data = json.loads(request.content.read().decode('utf-8'))
        except json.JSONDecodeError:
            return json.dumps({'success': False, 'message': 'Invalid format for post data'}).encode('utf-8')

        for param in PARAMS_PUT:
            if param not in data:
                return get_missing_params_msg(param)

        try:
            decoded_params = self.decode_put_params(data)
        except ValueError as e:
            return json.dumps({'success': False, 'message': e.message}).encode('utf-8')

        try:
            tx = Transaction.create_from_struct(decoded_params.tx_bytes)
        except struct.error:
            return json.dumps({'success': False, 'message': 'Could not decode hex transaction'}).encode('utf-8')

        tx_outputs = []
        nano_contract = None
        for _output in tx.outputs:
            _nano_contract = NanoContractMatchValues.parse_script(_output.script)
            if _nano_contract:
                total_value = _output.value
                nano_contract = _nano_contract
            else:
                tx_outputs.append(_output)

        if not nano_contract:
            return json.dumps({'success': False, 'message': 'Nano contract not found'}).encode('utf-8')

        for address, value in decoded_params.new_value_dict.items():
            nano_contract.value_dict[address] = value

        tx.outputs = tx_outputs

        inputs, total_inputs_amount = self.manager.wallet.get_inputs_from_amount(
            decoded_params.input_value,
            self.manager.tx_storage
        )
        change_tx = self.manager.wallet.handle_change_tx(total_inputs_amount, decoded_params.input_value)
        if change_tx:
            tx.outputs.append(TxOutput(change_tx.value, P2PKH.create_output_script(change_tx.address)))

        tx.outputs.insert(0, TxOutput(total_value, nano_contract.create_output_script()))

        for txin in inputs:
            tx.inputs.append(TxInput(txin.tx_id, txin.index, b''))

        ret = {'success': True, 'hex_tx': tx.get_struct().hex()}
        return json.dumps(ret).encode('utf-8')