def get_address(scriptpubkey): pubkeyhash = get_pubkeyhash(scriptpubkey) if not pubkeyhash: return False pubkeyhash = binascii.hexlify(pubkeyhash).decode('utf-8') address = script.base58_check_encode(pubkeyhash, config.ADDRESSVERSION) # Test decoding of address. if address != config.UNSPENDABLE and binascii.unhexlify(bytes(pubkeyhash, 'utf-8')) != script.base58_check_decode(address, config.ADDRESSVERSION): return False return address
def decode_checksig(asm): pubkeyhash = script.get_checksig(asm) chunk = arc4_decrypt(pubkeyhash) if chunk[1:len(config.PREFIX) + 1] == config.PREFIX: # Data # Padding byte in each output (instead of just in the last one) so that encoding methods may be mixed. Also, it’s just not very much data. chunk_length = chunk[0] chunk = chunk[1:chunk_length + 1] destination, data = None, chunk[len(config.PREFIX):] else: # Destination pubkeyhash = binascii.hexlify(pubkeyhash).decode('utf-8') destination, data = script.base58_check_encode(pubkeyhash, config.ADDRESSVERSION), None return destination, data
def get_address(scriptpubkey): pubkeyhash = get_pubkeyhash(scriptpubkey) if not pubkeyhash: return False pubkeyhash = binascii.hexlify(pubkeyhash).decode('utf-8') address = script.base58_check_encode(pubkeyhash, config.ADDRESSVERSION) # Test decoding of address. if address != config.UNSPENDABLE and binascii.unhexlify( bytes(pubkeyhash, 'utf-8')) != script.base58_check_decode( address, config.ADDRESSVERSION): return False return address
def decode_checksig(asm): pubkeyhash = script.get_checksig(asm) chunk = arc4_decrypt(pubkeyhash) if chunk[1:len(config.PREFIX) + 1] == config.PREFIX: # Data # Padding byte in each output (instead of just in the last one) so that encoding methods may be mixed. Also, it’s just not very much data. chunk_length = chunk[0] chunk = chunk[1:chunk_length + 1] destination, data = None, chunk[len(config.PREFIX):] else: # Destination pubkeyhash = binascii.hexlify(pubkeyhash).decode('utf-8') destination, data = script.base58_check_encode( pubkeyhash, config.ADDRESSVERSION), None return destination, data
def test_p2sh_encoding(server_db): source = ADDR[0] destination = ADDR[1] with util_test.ConfigContext( OLD_STYLE_API=True), util_test.MockProtocolChangesContext( enhanced_sends=True, p2sh_encoding=True): utxos = dict(((utxo['txid'], utxo['vout']), utxo) for utxo in backend.get_unspent_txouts(source)) # pprint.pprint(utxos) fee = 20000 fee_per_kb = 50000 result = api.compose_transaction(server_db, 'send', { 'source': source, 'destination': destination, 'asset': 'XCP', 'quantity': 100 }, encoding='p2sh', fee_per_kb=fee_per_kb, fee=fee) assert not isinstance(result, list) pretxhex = result pretx = bitcoinlib.core.CTransaction.deserialize( binascii.unhexlify(pretxhex)) sumvin = sum([ int(utxos[(bitcoinlib.core.b2lx( vin.prevout.hash), vin.prevout.n)]['amount'] * 1e8) for vin in pretx.vin ]) sumvout = sum([vout.nValue for vout in pretx.vout]) assert len(pretx.vout) == 2 assert len(pretxhex) / 2 == 142 assert sumvin == 199909140 assert sumvout < sumvin assert sumvout == (sumvin - fee) # data P2SH output expected_datatx_length = 435 expected_datatx_fee = int(expected_datatx_length / 1000 * fee_per_kb) assert repr( pretx.vout[0].scriptPubKey ) == "CScript([OP_HASH160, x('7698101f9b9e5cdf0a0e11c2972dbc4860f374bf'), OP_EQUAL])" assert pretx.vout[0].nValue == expected_datatx_fee # change output assert pretx.vout[1].nValue == sumvin - expected_datatx_fee - fee assert pretxhex == "0100000001c1d8c075936c3495f6d653c50f73d987f75448d97a750249b1eb83bee71b24ae000000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788acffffffff02f65400000000000017a9147698101f9b9e5cdf0a0e11c2972dbc4860f374bf87febbe90b000000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788ac00000000" # 01000000 | version # 01 | inputs # c1d8c075936c3495f6d653c50f73d987f75448d97a750249b1eb83bee71b24ae | txout hash # 00000000 | txout index # 19 | script length # 76a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788ac | tx_script # ffffffff | Sequence # 02 | number of outputs # f654000000000000 | output 1 value (21750) # 17 | output 1 length (23 bytes) # a9147698101f9b9e5cdf0a0e11c2972dbc4860f374bf87 | output 1 script # febbe90b00000000 | output 2 value (199867390) # 19 | output 2 length (25 bytes) # 76a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788ac | output 2 script # 00000000 | locktime # first transaction should be considered BTC only with pytest.raises(exceptions.BTCOnlyError): blocks._get_tx_info(pretxhex) # store transaction pretxid, _ = util_test.insert_raw_transaction(pretxhex, server_db) logger.debug('pretxid %s' % (pretxid)) # check that when we do another, unrelated, send that it won't use our UTXO result = api.compose_transaction( server_db, 'send', { 'source': source, 'destination': destination, 'asset': 'XCP', 'quantity': 100 }) othertx = bitcoinlib.core.CTransaction.deserialize( binascii.unhexlify(result)) othertxid = bitcoinlib.core.lx( bitcoinlib.core.b2x(othertx.vin[0].prevout.hash)) # reverse hash assert not (binascii.hexlify(othertxid).decode('ascii') == pretxid and othertx.vin[0].prevout.n == 0) # now compose the data transaction result = api.compose_transaction( server_db, 'send', { 'source': source, 'destination': destination, 'asset': 'XCP', 'quantity': 100 }, p2sh_pretx_txid=pretxid, # pass the pretxid encoding='p2sh', fee_per_kb=fee_per_kb) assert not isinstance(result, list) datatxhex = result datatx = bitcoinlib.core.CTransaction.deserialize( binascii.unhexlify(datatxhex)) sumvin = sum( [pretx.vout[n].nValue for n, vin in enumerate(datatx.vin)]) sumvout = sum([vout.nValue for vout in datatx.vout]) fee = 10000 assert len(datatxhex) / 2 == 190 assert sumvin == expected_datatx_fee assert sumvout < sumvin assert sumvout == sumvin - expected_datatx_fee assert len(datatx.vout) == 1 # opreturn signalling P2SH assert repr( datatx.vout[0].scriptPubKey ) == "CScript([OP_RETURN, x('8a5dda15fb6f0562da344d2f')])" # arc4(PREFIX + 'P2SH') assert datatx.vout[0].nValue == 0 assert datatxhex == "01000000010a0746fe9308ac6e753fb85780a8b788b40655148dcde1435f2048783b784f06000000007431544553545858585800000002000000000000000100000000000000646f8d6ae8a3b381663118b4e1eff4cfc7d0954dd6ec2975210282b886c087eb37dc8182f14ba6cc3e9485ed618b95804d44aecc17c300b585b0ad007574008717a9147698101f9b9e5cdf0a0e11c2972dbc4860f374bf87ffffffff0100000000000000000e6a0c8a5dda15fb6f0562da344d2f00000000" # 01000000 | version # 01 | inputs # 0a0746fe9308ac6e753fb85780a8b788b40655148dcde1435f2048783b784f06 | txout hash # 00000000 | txout index (0) # 74 | script length (116) # 31544553545858585800000002000000000000000100000000000000 | tx_script # 646f8d6ae8a3b381663118b4e1eff4cfc7d0954dd6ec2975210282b886c087eb37dc8182f14ba6cc | ... # 3e9485ed618b95804d44aecc17c300b585b0ad007574008717a9147698101f9b9e5cdf0a0e11c297 | ... # 2dbc4860f374bf87 | ... # ffffffff | Sequence # 01 | number of outputs # 0000000000000000 | output 1 value (0) # 0e | output 1 length (14 bytes) # 6a0c8a5dda15fb6f0562da344d2f | output 1 script # 00000000 | locktime # verify parsed result parsed_source, parsed_destination, parsed_btc_amount, parsed_fee, parsed_data, extra = blocks._get_tx_info( datatxhex) assert parsed_source == source assert parsed_data == binascii.unhexlify( "00000002" "0000000000000001" "0000000000000064" "6f8d6ae8a3b381663118b4e1eff4cfc7d0954dd6ec" ) # ID=enhanced_send(0x02) ASSET=XCP(0x01) VALUE=100(0x64) destination_pubkey(0x6f8d...d6ec) assert parsed_btc_amount == 0 assert parsed_fee == expected_datatx_fee # check signing pubkey tx_script_start = 8 + 2 + 64 + 8 tx_script_length = int(datatxhex[tx_script_start:tx_script_start + 2], 16) * 2 tx_script = datatxhex[tx_script_start + 2:tx_script_start + 2 + tx_script_length] signing_pubkey_hash = tx_script[-44:-4] address = script.base58_check_encode(signing_pubkey_hash, config.ADDRESSVERSION)