Example #1
0
 def to_json(self):
     return {
         "is_awaiting_spend": self.is_awaiting_spend,
         "block": self.block.to_json(),
         "prevout": {
             "hash": b2lx(self.prevout.hash),
             "n": self.prevout.n
         },
         "value": self.value,
         "script_pubkey": b2lx(self.tx_out.scriptPubKey)
     }
 def write_buffer(self, buf):
     buf.write(self.prev_tx_id)
     buf.write(b2lx((self.vout).to_bytes(4, 'big', signed=False)))
     if self.sig_script:
         buf.write(
             VarIntSerializer.serialize(
                 len(Web3.toBytes(hexstr=self.sig_script))).hex())
         buf.write(self.sig_script)
     else:
         buf.write(b'\x00'.hex())
     buf.write(b2lx((self.sequence).to_bytes(4, 'big', signed=False)))
     return buf
 def to_buffer_writer(self) -> StringIO:
     buffer = StringIO()
     buffer.write(b2lx((self.version).to_bytes(4, 'big', signed=False)))
     buffer.write(b2lx(VarIntSerializer.serialize(len(self.inputs))))
     for _input in self.inputs:
         _input.write_buffer(buffer)
     buffer.write(b2lx(VarIntSerializer.serialize(len(self.outputs))))
     for _output in self.outputs:
         _output.write_buffer(buffer)
     buffer.write(b2lx((self.gas_limit).to_bytes(4, 'big', signed=False)))
     buffer.write(b2lx((self.lock_time).to_bytes(4, 'big', signed=True)))
     return buffer
Example #4
0
 def lockunspent(self, unlock, outpoints):
     """Lock or unlock outpoints"""
     json_outpoints = [{
         'txid': b2lx(outpoint.hash),
         'vout': outpoint.n
     } for outpoint in outpoints]
     return self._call('lockunspent', unlock, json_outpoints)
Example #5
0
    def getrawtransaction(self, txid, verbose=False):
        """Return transaction with hash txid

        Raises IndexError if transaction not found.

        verbose - If true a dict is returned instead with additional
        information on the transaction.

        Note that if all txouts are spent and the transaction index is not
        enabled the transaction may not be available.
        """
        try:
            r = self._call('getrawtransaction', b2lx(txid),
                           1 if verbose else 0)
        except InvalidAddressOrKeyError as ex:
            raise IndexError('%s.getrawtransaction(): %s (%d)' %
                             (self.__class__.__name__, ex.error['message'],
                              ex.error['code']))
        if verbose:
            r['tx'] = CTransaction.deserialize(unhexlify(r['hex']))
            del r['hex']
            del r['txid']
            del r['version']
            del r['locktime']
            del r['vin']
            del r['vout']
            r['blockhash'] = lx(r['blockhash']) if 'blockhash' in r else None
        else:
            r = CTransaction.deserialize(unhexlify(r))

        return r
Example #6
0
    def getblockheader(self, block_hash, verbose=False):
        """Get block header <block_hash>

        verbose - If true a dict is returned with the values returned by
                  getblockheader that are not in the block header itself
                  (height, nextblockhash, etc.)

        Raises IndexError if block_hash is not valid.
        """
        try:
            block_hash = b2lx(block_hash)
        except TypeError:
            raise TypeError(
                '%s.getblockheader(): block_hash must be bytes; got %r instance'
                % (self.__class__.__name__, block_hash.__class__))
        try:
            r = self._call('getblockheader', block_hash, verbose)
        except InvalidAddressOrKeyError as ex:
            raise IndexError('%s.getblockheader(): %s (%d)' %
                             (self.__class__.__name__, ex.error['message'],
                              ex.error['code']))

        if verbose:
            nextblockhash = None
            if 'nextblockhash' in r:
                nextblockhash = lx(r['nextblockhash'])
            return {
                'confirmations': r['confirmations'],
                'height': r['height'],
                'mediantime': r['mediantime'],
                'nextblockhash': nextblockhash,
                'chainwork': x(r['chainwork'])
            }
        else:
            return CBlockHeader.deserialize(unhexlify(r))
Example #7
0
    def gettransaction(self, txid):
        """Get detailed information about in-wallet transaction txid

        Raises IndexError if transaction not found in the wallet.

        FIXME: Returned data types are not yet converted.
        """
        try:
            r = self._call('gettransaction', b2lx(txid))
        except InvalidAddressOrKeyError as ex:
            raise IndexError('%s.getrawtransaction(): %s (%d)' %
                             (self.__class__.__name__, ex.error['message'],
                              ex.error['code']))
        return r
Example #8
0
    def getblock(self, block_hash):
        """Get block <block_hash>

        Raises IndexError if block_hash is not valid.
        """
        try:
            block_hash = b2lx(block_hash)
        except TypeError:
            raise TypeError(
                '%s.getblock(): block_hash must be bytes; got %r instance' %
                (self.__class__.__name__, block_hash.__class__))
        try:
            r = self._call('getblock', block_hash, False)
        except InvalidAddressOrKeyError as ex:
            raise IndexError('%s.getblock(): %s (%d)' %
                             (self.__class__.__name__, ex.error['message'],
                              ex.error['code']))
        return CBlock.deserialize(unhexlify(r))
Example #9
0
    def gettxout(self, outpoint, includemempool=True):
        """Return details about an unspent transaction output.

        Raises IndexError if outpoint is not found or was spent.

        includemempool - Include mempool txouts
        """
        r = self._call('gettxout', b2lx(outpoint.hash), outpoint.n,
                       includemempool)

        if r is None:
            raise IndexError('%s.gettxout(): unspent txout %r not found' %
                             (self.__class__.__name__, outpoint))

        r['txout'] = CTxOut(int(r['value'] * COIN),
                            CScript(unhexlify(r['scriptPubKey']['hex'])))
        del r['value']
        del r['scriptPubKey']
        r['bestblock'] = lx(r['bestblock'])
        return r
 def write_buffer(self, buf):
     buf.write(b2lx(struct.pack(">q", self.amount)))
     buf.write(
         VarIntSerializer.serialize(len(
             Web3.toBytes(hexstr=self.pk_script))).hex())
     buf.write(self.pk_script)
     if self.assets:
         buf.write(
             VarIntSerializer.serialize(
                 len(Web3.toBytes(hexstr=self.assets))).hex())
         buf.write(self.assets)
     else:
         buf.write(b'\x00'.hex())
     if self.data:
         buf.write(
             VarIntSerializer.serialize(len(
                 Web3.toBytes(hexstr=self.data))).hex())
         buf.write(self.data)
     else:
         buf.write(b'\x00'.hex())
     return buf
Example #11
0
def test_encoding():
    assert Web3.toHex((1).to_bytes(4, 'little', signed=False)) == '0x01000000'
    assert b2lx((1).to_bytes(4, 'big', signed=False)) == "01000000"
Example #12
0
def finalize_offer(half_signed_psbt, lnd):
    offer = p2oc_offer.get_offer_from_psbt(half_signed_psbt)
    reply = p2oc_offer.get_offer_reply_from_psbt(half_signed_psbt)

    p2oc_offer.validate_offer_integrity(half_signed_psbt,
                                        lnd,
                                        check_our_signature=False)
    p2oc_offer.validate_offer_reply_integrity(half_signed_psbt,
                                              lnd,
                                              check_our_signature=True)

    if offer.state != offer.CHANNEL_OPENED_STATE:
        raise RuntimeError(
            f"Got offer in a wrong state. Expected state='{offer.CHANNEL_OPENED_STATE}'"
            + f", got '{offer.state}'")

    if reply.state != reply.ACCEPTED_STATE:
        raise RuntimeError(
            f"Got reply in a wrong state. Expected state='{reply.ACCEPTED_STATE}'"
            + f", got '{reply.state}'")

    # check that the funding output is correct
    funding_output = p2oc_fund.create_funding_output(
        taker_pubkey=offer.channel_pubkey_key_desc.raw_key_bytes,
        maker_pubkey=reply.channel_pubkey_key_desc.raw_key_bytes,
        premium_amount=reply.premium_amount,
        fund_amount=reply.fund_amount,
    )

    if half_signed_psbt.unsigned_tx.vout[-1] != funding_output:
        raise RuntimeError(
            "Channel funding does not match parameters between offer and reply"
            +
            f"Expected funding_output={funding_output}, got {half_signed_psbt.unsigned_tx.vout[-1]}"
        )

    # check that the channel is pending and has the right config
    channel_point = f"{bc.b2lx(half_signed_psbt.unsigned_tx.GetTxid())}:{len(half_signed_psbt.unsigned_tx.vout)-1}"

    target_channel = p2oc_channel.get_pending_channel(channel_point, lnd)
    if target_channel.channel.local_balance != reply.fund_amount:
        raise RuntimeError(
            f"Pending channel's local balance={target_channel.channel.local_balance} does not "
            + f"match offer funding amount={reply.fund_amount}")

    # the other party is paying all commitment tx fees
    if (target_channel.channel.remote_balance !=
            reply.premium_amount - target_channel.commit_fee):
        raise RuntimeError(
            f"Pending channel's remote balance={target_channel.channel.remote_balance} does not "
            +
            f"match offer premium amount={reply.premium_amount} minus commit_fee={target_channel.commit_fee}"
        )

    if target_channel.channel.remote_node_pub != offer.node_pubkey:
        raise RuntimeError(
            f"Pending channel's remote node pubkey={target_channel.channel.remote_node_pub} "
            + f"does not match offer's node pubkey={offer.node_pubkey}")

    p2oc_sign.sign_inputs(half_signed_psbt, reply.input_indices, lnd)
    p2oc_psbt.finalize_and_publish_psbt(half_signed_psbt, lnd)

    return bc.b2lx(half_signed_psbt.unsigned_tx.GetTxid())
Example #13
0
    def check_serialize_deserialize(self, tx, tx_bytes, tx_decoded):
        self.assertEqual(tx_bytes, tx.serialize())
        self.assertEqual(tx_bytes,
                         CTransaction.deserialize(tx.serialize()).serialize())
        self.assertEqual(tx_bytes, tx.to_mutable().to_immutable().serialize())
        self.assertEqual(tx_decoded['version'], tx.nVersion)
        self.assertEqual(tx_decoded['locktime'], tx.nLockTime)
        # we ignore withash field - we do not have ComputeWitnessHash() function
        # as it is only relevant for blocks, not transactions
        self.assertEqual(tx_decoded['hash'], b2lx(tx.GetHash()))
        self.assertEqual(tx_decoded['txid'], b2lx(tx.GetTxid()))
        for n, vout in enumerate(tx_decoded['vout']):
            if 'amountcommitment' in vout:
                self.assertEqual(x(vout['amountcommitment']),
                                 tx.vout[n].nValue.commitment)
            if 'assetcommitment' in vout:
                self.assertEqual(x(vout['assetcommitment']),
                                 tx.vout[n].nAsset.commitment)
            if 'asset' in vout:
                self.assertEqual(vout['asset'],
                                 tx.vout[n].nAsset.to_asset().to_hex())
            if 'scriptPubKey' in vout:
                spk = vout['scriptPubKey']
                self.assertEqual(x(spk['hex']), tx.vout[n].scriptPubKey)

                if 'pegout_type' in spk:
                    self.assertEqual(spk['type'], 'nulldata')
                    self.assertTrue(tx.vout[n].scriptPubKey.is_pegout())
                    genesis_hash, pegout_scriptpubkey = tx.vout[
                        n].scriptPubKey.get_pegout_data()
                    if spk['pegout_type'] != 'nonstandard':
                        assert spk['pegout_type'] in ('pubkeyhash',
                                                      'scripthash')
                        addr = CCoinAddress.from_scriptPubKey(
                            pegout_scriptpubkey)
                        self.assertEqual(len(spk['pegout_addresses']), 1)
                        self.assertEqual(spk['pegout_addresses'][0], str(addr))
                    self.assertEqual(spk['pegout_hex'],
                                     b2x(pegout_scriptpubkey))
                    self.assertEqual(spk['pegout_chain'], b2lx(genesis_hash))

                if spk['type'] in ('pubkeyhash', 'scripthash'):
                    self.assertEqual(len(spk['addresses']), 1)
                    addr = CCoinAddress.from_scriptPubKey(
                        tx.vout[n].scriptPubKey)
                    self.assertEqual(spk['addresses'][0], str(addr))
                elif spk['type'] == 'nulldata':
                    self.assertEqual(tx.vout[n].scriptPubKey, x(spk['hex']))
                else:
                    self.assertEqual(spk['type'], 'fee')
                    self.assertEqual(len(tx.vout[n].scriptPubKey), 0)

            if secp256k1_has_zkp:
                if tx.wit.is_null():
                    rpinfo = None
                else:
                    rpinfo = tx.wit.vtxoutwit[n].get_rangeproof_info()
                if 'value-minimum' in vout:
                    self.assertIsNotNone(rpinfo)
                    self.assertEqual(vout['ct-exponent'], rpinfo.exp)
                    self.assertEqual(vout['ct-bits'], rpinfo.mantissa)
                    self.assertEqual(
                        coins_to_satoshi(vout['value-minimum'],
                                         check_range=False), rpinfo.value_min)
                    self.assertEqual(
                        coins_to_satoshi(vout['value-maximum'],
                                         check_range=False), rpinfo.value_max)
                else:
                    self.assertTrue(rpinfo is None or rpinfo.exp == -1)
                    if rpinfo is None:
                        value = tx.vout[n].nValue.to_amount()
                    else:
                        value = rpinfo.value_min
                    self.assertEqual(coins_to_satoshi(vout['value']), value)
            else:
                warn_zkp_unavailable()
                if 'value' in vout and tx.vout[n].nValue.is_explicit():
                    self.assertEqual(coins_to_satoshi(vout['value']),
                                     tx.vout[n].nValue.to_amount())

        for n, vin in enumerate(tx_decoded['vin']):
            if 'scripSig' in vin:
                self.assertEqual(
                    x(vin['scriptSig']['hex'], tx.vin[n].scriptSig))
            if 'txid' in vin:
                self.assertEqual(vin['txid'], b2lx(tx.vin[n].prevout.hash))
            if 'vout' in vin:
                self.assertEqual(vin['vout'], tx.vin[n].prevout.n)
            if 'is_pegin' in vin:
                self.assertEqual(vin['is_pegin'], tx.vin[n].is_pegin)
                if vin['is_pegin'] is False:
                    if 'scriptWitness' in vin:
                        self.assertTrue(
                            tx.wit.vtxinwit[n].scriptWitness.is_null())
                    if 'pegin_witness' in vin:
                        self.assertTrue(
                            tx.wit.vtxinwit[n].pegin_witness.is_null())
                else:
                    for stack_index, stack_item in enumerate(
                            vin['scriptWitness']):
                        self.assertTrue(
                            stack_item,
                            b2x(tx.wit.vtxinwit[n].scriptWitness.
                                stack[stack_index]))
                    for stack_index, stack_item in enumerate(
                            vin['pegin_witness']):
                        self.assertTrue(
                            stack_item,
                            b2x(tx.wit.vtxinwit[n].pegin_witness.
                                stack[stack_index]))
            if 'sequence' in vin:
                self.assertEqual(vin['sequence'], tx.vin[n].nSequence)
            if 'coinbase' in vin:
                self.assertTrue(tx.is_coinbase())
            if 'issuance' in vin:
                iss = vin['issuance']
                self.assertEqual(
                    iss['assetBlindingNonce'],
                    tx.vin[n].assetIssuance.assetBlindingNonce.to_hex())
                if 'asset' in iss:
                    if iss['isreissuance']:
                        self.assertTrue(not tx.vin[n].assetIssuance.
                                        assetBlindingNonce.is_null())
                        self.assertEqual(
                            iss['assetEntropy'],
                            tx.vin[n].assetIssuance.assetEntropy.to_hex())
                        asset = calculate_asset(
                            tx.vin[n].assetIssuance.assetEntropy)
                    else:
                        entropy = generate_asset_entropy(
                            tx.vin[n].prevout,
                            tx.vin[n].assetIssuance.assetEntropy)
                        self.assertEqual(iss['assetEntropy'], entropy.to_hex())
                        asset = calculate_asset(entropy)
                        reiss_token = calculate_reissuance_token(
                            entropy,
                            tx.vin[n].assetIssuance.nAmount.is_commitment())
                        self.assertEqual(iss['token'], reiss_token.to_hex())
                    self.assertEqual(iss['asset'], asset.to_hex())
                if 'assetamount' in iss:
                    self.assertEqual(
                        coins_to_satoshi(iss['assetamount']),
                        tx.vin[n].assetIssuance.nAmount.to_amount())
                elif 'assetamountcommitment' in iss:
                    self.assertEqual(
                        iss['assetamountcommitment'],
                        b2x(tx.vin[n].assetIssuance.nAmount.commitment))
                if 'tokenamount' in iss:
                    self.assertEqual(
                        coins_to_satoshi(iss['tokenamount']),
                        tx.vin[n].assetIssuance.nInflationKeys.to_amount())
                elif 'tokenamountcommitment' in iss:
                    self.assertEqual(
                        iss['tokenamountcommitment'],
                        b2x(tx.vin[n].assetIssuance.nInflationKeys.commitment))
Example #14
0
 def tx_hash(self):
     return b2lx(self.prevout.hash)
Example #15
0
 def _send_transaction(self, tx: CMutableTransaction,
                       recipients: List[Address]):
     txid = self.proxy.sendrawtransaction(tx)
     for rec in recipients:
         rec.txid = txid
     return b2lx(txid)