def test_no_combine_with_fee(self): """ Verify that unused unspents do not increase fee. """ unspents_single = [Unspent(5000, 0, '', '', 0)] unspents_original = [Unspent(5000, 0, '', '', 0), Unspent(5000, 0, '', '', 0)] outputs_original = [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 1000, 'satoshi')] unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=1, leftover=RETURN_ADDRESS, combine=False, message=None ) unspents_single, outputs_single = sanitize_tx_data( unspents_single, outputs_original, fee=1, leftover=RETURN_ADDRESS, combine=False, message=None ) assert unspents == [Unspent(5000, 0, '', '', 0)] assert unspents_single == [Unspent(5000, 0, '', '', 0)] assert len(outputs) == 2 assert len(outputs_single) == 2 assert outputs[1][0] == RETURN_ADDRESS assert outputs_single[1][0] == RETURN_ADDRESS assert outputs[1][1] == outputs_single[1][1]
def test_no_combine_insufficient_funds(self): unspents_original = [Unspent(1000, 0, '', '', 0), Unspent(1000, 0, '', '', 0)] outputs_original = [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 2500, 'satoshi')] with pytest.raises(InsufficientFunds): sanitize_tx_data( unspents_original, outputs_original, fee=50, leftover=RETURN_ADDRESS, combine=False, message=None )
def test_zero_remaining(self): unspents_original = [Unspent(1000, 0, '', '', 0), Unspent(1000, 0, '', '', 0)] outputs_original = [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 2000, 'satoshi')] unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS, combine=True, message=None ) assert unspents == unspents_original assert outputs == [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 2000)]
def test_message(self): unspents_original = [Unspent(10000, 0, '', '', 0), Unspent(10000, 0, '', '', 0)] outputs_original = [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 1000, 'satoshi')] unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=5, leftover=RETURN_ADDRESS, combine=True, message='hello' ) assert len(outputs) == 3 assert outputs[2][0] == b'hello' assert outputs[2][1] == 0
def test_combine_insufficient_funds(self): unspents_original = [ Unspent(1000, 0, '', '', 0), Unspent(1000, 0, '', '', 0) ] outputs_original = [('test', 2500, 'satoshi')] with pytest.raises(InsufficientFunds): sanitize_tx_data(unspents_original, outputs_original, fee=50, leftover=RETURN_ADDRESS, combine=True, message=None)
def test_no_combine_remaining(self): unspents_original = [Unspent(7000, 0, '', '', 0), Unspent(3000, 0, '', '', 0)] outputs_original = [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 2000, 'satoshi')] unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS, combine=False, message=None ) assert unspents == [Unspent(3000, 0, '', '', 0)] assert len(outputs) == 2 assert outputs[1][0] == RETURN_ADDRESS assert outputs[1][1] == 1000
def test_init(self): unspent = Unspent(10000, 7, 'script', 'txid', 0) assert unspent.amount == 10000 assert unspent.confirmations == 7 assert unspent.script == 'script' assert unspent.txid == 'txid' assert unspent.txindex == 0
def test_fee_applied(self): unspents_original = [ Unspent(1000, 0, "", "", 0), Unspent(1000, 0, "", "", 0) ] outputs_original = [(BITCOIN_CASHADDRESS_COMPRESSED, 2000, "satoshi")] with pytest.raises(InsufficientFunds): sanitize_tx_data( unspents_original, outputs_original, fee=1, leftover=RETURN_ADDRESS, combine=True, message=None, )
def test_init(self): unspent = Unspent(10000, 7, "script", "txid", 0) assert unspent.amount == 10000 assert unspent.confirmations == 7 assert unspent.script == "script" assert unspent.txid == "txid" assert unspent.txindex == 0
def test_combine_remaining(self): unspents_original = [ Unspent(1000, 0, '', '', 0), Unspent(1000, 0, '', '', 0) ] outputs_original = [('test', 500, 'satoshi')] unspents, outputs = sanitize_tx_data(unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS, combine=True, message=None) assert unspents == unspents_original assert len(outputs) == 2 assert outputs[1][0] == RETURN_ADDRESS assert outputs[1][1] == 1500
def get_unspent(cls, address): r = requests.get(cls.MAIN_UNSPENT_API.format(address), timeout=DEFAULT_TIMEOUT) r.raise_for_status() # pragma: no cover return [ Unspent(currency_to_satoshi(tx['amount'], 'bch'), tx['confirmations'], tx['scriptPubKey'], tx['txid'], tx['vout']) for tx in r.json() ]
def get_unspent_testnet(cls, address): r = requests.get(cls.TEST_UNSPENT_API.format(address), timeout=DEFAULT_TIMEOUT) if r.status_code != 200: # pragma: no cover raise ConnectionError return [ Unspent(currency_to_satoshi(tx['amount'], 'bch'), tx['confirmations'], tx['scriptPubKey'], tx['txid'], tx['vout']) for tx in r.json() ]
def test_combine_remaining(self): unspents_original = [ Unspent(1000, 0, "", "", 0), Unspent(1000, 0, "", "", 0) ] outputs_original = [(BITCOIN_CASHADDRESS_COMPRESSED, 500, "satoshi")] unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS, combine=True, message=None, ) assert unspents == unspents_original assert len(outputs) == 2 assert outputs[1][0] == RETURN_ADDRESS assert outputs[1][1] == 1500
def get_unspent(cls, address): address = address.replace('bitcoincash:', '') r = requests.get(cls.MAIN_UNSPENT_API.format(address), timeout=DEFAULT_TIMEOUT) r.raise_for_status() # pragma: no cover return [ Unspent(currency_to_satoshi(tx['value'], 'satoshi'), tx['confirmations'], tx['script'], tx['mintTxid'], tx['mintIndex']) for tx in r.json() ]
def test_message_pushdata(self): unspents_original = [ Unspent(10000, 0, '', '', 0), Unspent(10000, 0, '', '', 0) ] outputs_original = [(BITCOIN_CASHADDRESS_TEST_COMPRESSED, 1000, 'satoshi')] BYTES = len(b'hello').to_bytes(1, byteorder='little') + b'hello' unspents, outputs = sanitize_tx_data(unspents_original, outputs_original, fee=5, leftover=RETURN_ADDRESS, combine=True, message=BYTES, custom_pushdata=True) assert len(outputs) == 3 assert outputs[2][0] == b'\x05' + b'hello' assert outputs[2][1] == 0
async def _get_obj_unspent_list(self, addr): unspent_list = await self._get_raw_unspent_list(addr) return [ Unspent( int(D(str(unspent['amount'])) * COIN), unspent['confirmations'], unspent['scriptPubKey'], unspent['txid'], unspent['vout'] ) for unspent in unspent_list ]
def get_unspent(cls, address, network): API = cls.network_endpoint(network) + cls.UNSPENT_PATH r = requests.get(API.format(address), timeout=DEFAULT_TIMEOUT) r.raise_for_status() return [ Unspent( currency_to_satoshi(tx["amount"], "bch"), tx["confirmations"], r.json()["scriptPubKey"], tx["txid"], tx["vout"], ) for tx in r.json()["utxos"] ]
def test_message_pushdata(self): unspents_original = [ Unspent(10000, 0, "", "", 0), Unspent(10000, 0, "", "", 0) ] outputs_original = [(BITCOIN_CASHADDRESS_COMPRESSED, 1000, "satoshi")] BYTES = len(b"hello").to_bytes(1, byteorder="little") + b"hello" unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=5, leftover=RETURN_ADDRESS, combine=True, message=BYTES, custom_pushdata=True, ) assert len(outputs) == 3 assert outputs[2][0] == b"\x05" + b"hello" assert outputs[2][1] == 0
def get_unspent(cls, address): # As of 2018-05-16, cashexplorer.bitcoin.com only supports legacy addresses. address = cashaddress.to_legacy_address(address) r = requests.get(cls.MAIN_UNSPENT_API.format(address), timeout=DEFAULT_TIMEOUT) if r.status_code != 200: # pragma: no cover raise ConnectionError return [ Unspent(currency_to_satoshi(tx['amount'], 'bch'), tx['confirmations'], tx['scriptPubKey'], tx['txid'], tx['vout']) for tx in r.json() ]
def get_unspent(cls, address): if not cls.NEW_ADDRESS_SUPPORTED: address = cashaddress.to_legacy_address(address) r = requests.get((cls.MAIN_ENDPOINT+cls.MAIN_UNSPENT_API).format(address), timeout=DEFAULT_TIMEOUT) if r.status_code != 200: # pragma: no cover raise ConnectionError return [ Unspent(currency_to_satoshi(tx['amount'], 'bch'), tx['confirmations'], tx['scriptPubKey'], tx['txid'], tx['vout']) for tx in r.json() ]
def sign_transaction(self, tx_data): """Creates a signed P2PKH transaction using previously prepared transaction data. :param tx_data: Output of :func:`~bitcash.PrivateKeyTestnet.prepare_transaction`. :type tx_data: ``str`` :returns: The signed transaction as hex. :rtype: ``str`` """ data = json.loads(tx_data) unspents = [Unspent.from_dict(unspent) for unspent in data['unspents']] outputs = data['outputs'] return create_p2pkh_transaction(self, unspents, outputs)
def test_no_combine_remaining_small_inputs(self): unspents_original = [ Unspent(1500, 0, "", "", 0), Unspent(1600, 0, "", "", 0), Unspent(1700, 0, "", "", 0), ] outputs_original = [(BITCOIN_CASHADDRESS_COMPRESSED, 2000, "satoshi")] unspents, outputs = sanitize_tx_data( unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS, combine=False, message=None, ) print(unspents) assert unspents == [ Unspent(1500, 0, "", "", 0), Unspent(1600, 0, "", "", 0) ] assert len(outputs) == 2 assert outputs[1][0] == RETURN_ADDRESS assert outputs[1][1] == 1100
def get_unspent_testnet(cls, address): r = requests.get(cls.TEST_UNSPENT_API.format(address), timeout=DEFAULT_TIMEOUT) if r.status_code != 200: # pragma: no cover raise ConnectionError unspents = [] for tx in r.json(): # In weird conditions, the API will send back unspents without a scriptPubKey. if 'scriptPubKey' in tx: unspents.append( Unspent(currency_to_satoshi(tx['amount'], 'bch'), tx['confirmations'], tx['scriptPubKey'], tx['txid'], tx['vout'])) else: logging.warning('Unspent without scriptPubKey.') return unspents
def get_unspent_testnet(cls, address): address = address.replace('bchtest:', '') r = requests.get(cls.TEST_UNSPENT_API.format(address), timeout=DEFAULT_TIMEOUT) r.raise_for_status() # pragma: no cover unspents = [] for tx in r.json(): # In weird conditions, the API will send back unspents # without a scriptPubKey. if 'script' in tx: unspents.append( Unspent(currency_to_satoshi(tx['value'], 'satoshi'), tx['confirmations'], tx['script'], tx['mintTxid'], tx['mintIndex'])) else: logging.warning('Unspent without scriptPubKey.') return unspents
def get_unspent(cls, address, network): address = cls.remove_prefix(address) API = cls.network_endpoint(network) + cls.UNSPENT_API r = requests.get(API.format(address), timeout=DEFAULT_TIMEOUT) r.raise_for_status() unspents = [] for tx in r.json(): # In weird conditions, the API will send back unspents # without a scriptPubKey. if "script" in tx: unspents.append( Unspent( currency_to_satoshi(tx["value"], "satoshi"), tx["confirmations"], tx["script"], tx["mintTxid"], tx["mintIndex"], )) else: logging.warning("Unspent without scriptPubKey.") return unspents
def wallet_to_test_faucet(w, tx_hash, faucet_address='mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB'): """Transfer BCH from an Arcula wallet address (deterministically generated) back to the faucet.""" # This is the address holding the funds using our Arcula transaction format. cold_storage_key = w.get_cold_storage_public_key() cold_storage_address = verification_key_to_address(cold_storage_key) from_signing_key, from_certificate = w.get_signing_key_certificate( FROM_ACCOUNT) r = requests.get(f"{BLOCKDOZER_T_API}/tx/{tx_hash}") assert r.status_code == 200, r.status_code unspent, *_ = r.json()['vout'] unspent_output = \ Unspent(int(float(unspent['value']) * BCH_TO_SATOSHI), -1, unspent['scriptPubKey']['hex'], tx_hash, 0) bch_to_send = (unspent_output.amount - BCH_FEES_SATOSHI) / BCH_TO_SATOSHI assert bch_to_send > 0, bch_to_send print( f"Sending {bch_to_send} BCH from the wallet '{cold_storage_address}' node " f"with identifier '{from_certificate[1]}' to '{faucet_address}'...") tx_hex = _create_apkh2pkh_transaction( cold_storage_key, bitcash.PrivateKeyTestnet.from_int( from_signing_key.privkey.secret_multiplier), from_certificate, unspent_output, (faucet_address, int(bch_to_send * BCH_TO_SATOSHI)), ) bitcash.network.NetworkAPI.broadcast_tx_testnet(tx_hex) tx_hash = bitcash.transaction.calc_txid(tx_hex) print(f"Transaction: '{BITCOIN_EXPLORER_URL.format(tx_hash)}'.") return tx_hash
def test_repr(self): unspent = Unspent(10000, 7, "script", "txid", 0) assert repr(unspent) == ("Unspent(amount=10000, confirmations=7, " "script='script', txid='txid', txindex=0)")
def test_equality(self): unspent1 = Unspent(10000, 7, "script", "txid", 0) unspent2 = Unspent(10000, 7, "script", "txid", 0) unspent3 = Unspent(50000, 7, "script", "txid", 0) assert unspent1 == unspent2 assert unspent1 != unspent3
def test_dict_conversion(self): unspent = Unspent(10000, 7, "script", "txid", 0) assert unspent == Unspent.from_dict(unspent.to_dict())
def test_equality(self): unspent1 = Unspent(10000, 7, 'script', 'txid', 0) unspent2 = Unspent(10000, 7, 'script', 'txid', 0) unspent3 = Unspent(50000, 7, 'script', 'txid', 0) assert unspent1 == unspent2 assert unspent1 != unspent3