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
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)
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
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))
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
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))
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
def test_encoding(): assert Web3.toHex((1).to_bytes(4, 'little', signed=False)) == '0x01000000' assert b2lx((1).to_bytes(4, 'big', signed=False)) == "01000000"
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())
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))
def tx_hash(self): return b2lx(self.prevout.hash)
def _send_transaction(self, tx: CMutableTransaction, recipients: List[Address]): txid = self.proxy.sendrawtransaction(tx) for rec in recipients: rec.txid = txid return b2lx(txid)