Exemple #1
0
def test_Bitcoin(raw_header, header_hash, version, prev_hash, merkle_root,
                 timestamp, bits, nonce):
    header_hash = hex_str_to_hash(header_hash)
    prev_hash = hex_str_to_hash(prev_hash)
    merkle_root = hex_str_to_hash(merkle_root)

    assert Bitcoin.header_hash(raw_header) == header_hash
    assert Bitcoin.header_prev_hash(raw_header) == prev_hash
    assert Bitcoin.header_work(raw_header) == bits_to_work(bits)
    assert Bitcoin.header_timestamp(raw_header) == timestamp

    header = Bitcoin.deserialized_header(raw_header, 0)
    assert header.version == version
    assert header.prev_hash == prev_hash
    assert header.merkle_root == merkle_root
    assert header.timestamp == timestamp
    assert header.bits == bits
    assert header.nonce == nonce
    assert header.raw == raw_header
    assert header.hash == header_hash
    assert header.height == 0
    assert header.work() == Bitcoin.header_work(raw_header)
    assert header.target() == bits_to_target(bits)
    assert header.hash_value() == hash_to_value(header_hash)
    assert header.hex_str() == hash_to_hex_str(header_hash)
    assert 'height=0' in str(header)
Exemple #2
0
    def test_pickle(self, tmpdir):
        testnet_genesis_checkpoint = CheckPoint(BitcoinTestnet.genesis_header, 0, 0)
        headers_obj = create_headers(tmpdir, testnet_genesis_checkpoint)

        header1 = bytes.fromhex(
            '0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa'
            '927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b672'
        )
        header2 = bytes.fromhex(
            '0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e'
            '3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d23534'
        )

        headers_obj.connect(header1)
        headers_obj.connect(header2)

        pickle_bytes = pickle.dumps(headers_obj)

        headers_obj2 = pickle.loads(pickle_bytes)
        assert headers_obj._short_hashes == headers_obj2._short_hashes
        assert headers_obj._heights == headers_obj2._heights
        assert headers_obj._chain_indices == headers_obj2._chain_indices
        assert len(headers_obj._chains) == len(headers_obj2._chains)

        # Chain objects cannot be directly compared, so we need to do the legwork.
        # This goes beyond what is needed here as it might be reused for a wider variety of
        # cases if necessary.
        for i in range(len(headers_obj._chains)):
            original_chain = headers_obj._chains[i]
            unpickled_chain = headers_obj2._chains[i]
            assert original_chain.tip == unpickled_chain.tip
            assert original_chain.work == unpickled_chain.work
            assert original_chain.first_height == unpickled_chain.first_height
            assert original_chain._header_indices == unpickled_chain._header_indices
            if original_chain.parent is None:
                assert unpickled_chain.parent is None
            else:
                assert unpickled_chain.parent is not None
                original_index = headers_obj._chains.index(original_chain.parent)
                unpickled_index = headers_obj2._chains.index(unpickled_chain.parent)
                assert original_index == unpickled_index

        header_1_hash_hex = '00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206'
        header_1_hash = hex_str_to_hash(header_1_hash_hex)

        headers_obj2.common_setup(headers_obj.network, storage_filename(tmpdir),
            testnet_genesis_checkpoint)

        original_header, original_chain = headers_obj.lookup(header_1_hash)
        unpickled_header, unpickled_chain = headers_obj2.lookup(header_1_hash)
        assert original_header == unpickled_header

        header_2_hash_hex = '000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820'
        header_2_hash = hex_str_to_hash(header_2_hash_hex)

        original_header, original_chain = headers_obj.lookup(header_2_hash)
        unpickled_header, unpickled_chain = headers_obj2.lookup(header_2_hash)
        assert original_header == unpickled_header
Exemple #3
0
def increment_counter(counter_obj, prev_txid, prev_out_idx, funding_txid,
                      funding_out_idx, unlock_key_priv, miner_fee):
    # Get data from previous counter tx
    r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(
        prev_txid)).json()
    prev_locking_script = Script.from_hex(
        r['vout'][prev_out_idx]['scriptPubKey']['hex'])
    prev_counter_bytes = list(prev_locking_script.ops())[-1]
    prev_counter_val = int.from_bytes(prev_counter_bytes, 'little')
    unlocked_satoshis_counter = int(r['vout'][prev_out_idx]['value'] * 10**8)

    # Get data from funding tx
    r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(
        funding_txid)).json()
    funding_locking_script = Script.from_hex(
        r['vout'][funding_out_idx]['scriptPubKey']['hex'])
    unlocked_satoshis_funding = int(r['vout'][funding_out_idx]['value'] *
                                    10**8)

    # Set data for next iteration
    counter_obj.set_data_part(
        scryptlib.utils.get_push_int(prev_counter_val + 1))

    ## Construct tx
    n_sequence = 0xffffffff

    # Counter input and output
    prev_tx_hash = hex_str_to_hash(prev_txid)
    counter_in = TxInput(prev_tx_hash, prev_out_idx, None, n_sequence)
    out_satoshis = unlocked_satoshis_counter + unlocked_satoshis_funding - miner_fee
    contract_out = TxOutput(out_satoshis, counter_obj.locking_script)

    # Funding input
    funding_tx_hash = hex_str_to_hash(funding_txid)
    funding_in = TxInput(funding_tx_hash, funding_out_idx, None, n_sequence)

    tx = Tx(2, [counter_in, funding_in], [contract_out], 0x00000000)

    # Set input script to unlock previous counter
    sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID)
    preimage = scryptlib.utils.get_preimage(tx, 0, unlocked_satoshis_counter,
                                            prev_locking_script, sighash_flag)
    increment_func_call = counter_obj.increment(SigHashPreimage(preimage),
                                                Int(out_satoshis))
    tx.inputs[0].script_sig = increment_func_call.script

    # Set input script to unlock funding output
    unlock_key_pub = unlock_key_priv.public_key
    sighash = tx.signature_hash(1, unlocked_satoshis_funding,
                                funding_locking_script, sighash_flag)
    sig = unlock_key_priv.sign(sighash, hasher=None)
    sig = sig + pack_byte(sighash_flag)
    unlock_script = Script() << sig << unlock_key_pub.to_bytes()
    tx.inputs[1].script_sig = unlock_script

    broadcast_tx(tx)
Exemple #4
0
    def parse_label_sync_json(klass, account: AbstractAccount,
                              text: str) -> LabelImportResult:
        addresses = klass._get_addresses(account)
        updates: Dict[str, str] = json.loads(text).items()
        results = LabelImportResult(LabelImportFormat.LABELSYNC)
        for label_reference, label_text in updates:
            if len(label_reference
                   ) == 64:  # length of the transaction id (hex of hash)
                try:
                    tx_hash = hex_str_to_hash(label_reference)
                except (TypeError, ValueError):
                    pass
                else:
                    results.transaction_labels[tx_hash] = label_text
                    continue
            else:
                try:
                    address = Address.from_string(label_reference, Net.COIN)
                except (Base58Error, ValueError):
                    pass
                else:
                    keyinstance_id = addresses.get(address)
                    if keyinstance_id is not None:
                        results.key_labels[keyinstance_id] = label_text
                        continue
            results.unknown_labels[label_reference] = label_text

        return results
Exemple #5
0
def test_import_labelsync_format() -> None:
    account = MockAccount()
    results = LabelImport.parse_label_sync_json(account, labelsync_text)
    assert 7 == len(results.transaction_labels)

    tx_hash = hex_str_to_hash("44e14e2eef1482bc803d1a32d9348b4914922990dbb730fe70b8a40753aeea03")
    assert "Return funding to 'mainnet_cash'" == results.transaction_labels[tx_hash]
Exemple #6
0
 def _fetch_transaction_dto(self, account: AbstractAccount,
                            tx_id) -> Optional[Dict]:
     tx_hash = hex_str_to_hash(tx_id)
     tx = account.get_transaction(tx_hash)
     if not tx:
         raise Fault(Errors.TRANSACTION_NOT_FOUND_CODE,
                     Errors.TRANSACTION_NOT_FOUND_MESSAGE)
     return {"tx_hex": tx.to_hex()}
Exemple #7
0
 def utxo_from_dict(self, d):
     return UTXO(value=d['value'],
                 script_pubkey=bitcoinx.Script.from_hex(d['script_pubkey']),
                 script_type=d['script_type'],
                 tx_hash=bitcoinx.hex_str_to_hash(d['tx_hash']),
                 out_index=d['out_index'],
                 keyinstance_id=d['keyinstance_id'],
                 address=bitcoinx.Address.from_string(d['address'],
                                                      coin=Net.COIN),
                 is_coinbase=d['is_coinbase'],
                 flags=d['flags'])
Exemple #8
0
    async def remove_txs(self, request):
        # follows this spec https://opensource.zalando.com/restful-api-guidelines/#152
        """This might be used to clean up after creating many transactions that were never sent."""
        try:
            vars = await self.argparser(request,
                                        required_vars=[
                                            VNAME.WALLET_NAME,
                                            VNAME.ACCOUNT_ID, VNAME.TXIDS
                                        ])
            wallet_name = vars[VNAME.WALLET_NAME]
            account_id = vars[VNAME.ACCOUNT_ID]
            txids = vars[VNAME.TXIDS]
            account = self._get_account(wallet_name, account_id)

            results = []
            if txids:
                for txid in txids:
                    try:
                        self.remove_transaction(bitcoinx.hex_str_to_hash(txid),
                                                account)
                        results.append({"id": txid, "result": 200})
                    except Fault as e:
                        if e.code == Errors.DISABLED_FEATURE_CODE:
                            results.append({
                                "id":
                                txid,
                                "result":
                                400,
                                "description":
                                Errors.DISABLED_FEATURE_MESSAGE
                            })
                        if e.code == Errors.TRANSACTION_NOT_FOUND_CODE:
                            results.append({
                                "id":
                                txid,
                                "result":
                                400,
                                "description":
                                Errors.TRANSACTION_NOT_FOUND_MESSAGE
                            })
            return self.batch_response({"items": results})
        except Fault as e:
            return fault_to_http_response(e)
    def _transaction_state_dto(self, wallet: AbstractAccount,
        tx_ids: Optional[Iterable[str]]=None) -> Union[Fault, Dict[Any, Any]]:
        chain = self.app_state.daemon.network.chain()

        result = {}
        for tx_id in tx_ids:
            tx_hash = hex_str_to_hash(tx_id)
            if wallet.has_received_transaction(tx_hash):
                # height, conf, timestamp
                height, conf, timestamp = wallet.get_tx_height(tx_hash)
                block_id = None
                if timestamp:
                    block_id = self.app_state.headers.header_at_height(chain, height).hex_str()
                result[tx_id] = {
                    "block_id": block_id,
                    "height": height,
                    "conf": conf,
                    "timestamp": timestamp,
                }
        return result
Exemple #10
0
def initialize_counter(counter_obj, counter_initial_val, funding_txid, funding_out_idx, \
        unlock_key_priv, miner_fee, contract_out_sats, change_addr):
    counter_obj.set_data_part(
        scryptlib.utils.get_push_int(counter_initial_val))

    # Funding TX
    funding_tx_hash = hex_str_to_hash(funding_txid)
    unlock_key_pub = unlock_key_priv.public_key

    r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(
        funding_txid)).json()
    funding_locking_script = Script.from_hex(
        r['vout'][funding_out_idx]['scriptPubKey']['hex'])
    unlocked_satoshis = int(r['vout'][funding_out_idx]['value'] * 10**8)
    n_sequence = 0xffffffff
    tx_input = TxInput(funding_tx_hash, funding_out_idx, None, n_sequence)

    # Output with counter script code
    contract_out = TxOutput(contract_out_sats, counter_obj.locking_script)

    # Change output
    tx_output_script = P2PKH_Address.from_string(change_addr,
                                                 Bitcoin).to_script()
    change_out = TxOutput(unlocked_satoshis - miner_fee - contract_out_sats,
                          tx_output_script)

    tx = Tx(2, [tx_input], [contract_out, change_out], 0x00000000)

    # Create signature for input
    sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID)
    sighash = tx.signature_hash(0, unlocked_satoshis, funding_locking_script,
                                sighash_flag)
    sig = unlock_key_priv.sign(sighash, hasher=None)
    sig = sig + pack_byte(sighash_flag)

    # Set script for input
    unlock_script = Script() << sig << unlock_key_pub.to_bytes()
    tx.inputs[0].script_sig = unlock_script

    broadcast_tx(tx)
Exemple #11
0
 def to_tx_input(txin):
     prev_hash, prev_idx = txin['output'].split(':')
     x_pubkeys = []
     value = txin.get('value')
     sec = txin.get('privkey')
     threshold = 1
     if sec:
         privkey = PrivateKey.from_text(sec)
         privkey, compressed = privkey.to_bytes(), privkey.is_compressed()
         x_pubkey = XPublicKey(privkey.public_key.to_hex())
         keypairs[x_pubkey] = privkey, compressed
         x_pubkeys = [x_pubkey]
     return XTxInput(
         prev_hash=hex_str_to_hash(prev_hash),
         prev_idx=int(prev_idx),
         script_sig=Script(),
         sequence=0xffffffff,
         value=value,
         x_pubkeys=x_pubkeys,
         address=None,
         threshold=threshold,
         signatures=[NO_SIGNATURE] * len(x_pubkeys),
     )
Exemple #12
0
    def parse_label_export_json(klass, account: AbstractAccount,
                                text: str) -> LabelImportResult:
        updates: Dict[str, Any] = json.loads(text)
        results = LabelImportResult(LabelImportFormat.ACCOUNT)
        for tx_id, label_text in updates.get("transactions", []):
            if len(tx_id) == 64:  # length of the transaction id (hex of hash)
                try:
                    tx_hash = hex_str_to_hash(tx_id)
                except (TypeError, ValueError):
                    pass
                else:
                    results.transaction_labels[tx_hash] = label_text
                    continue
            results.unknown_labels[tx_id] = label_text

        keydata: Optional[Dict[str, Any]] = updates.get("keys")
        if keydata is not None:
            account_fingerprint = account.get_fingerprint().hex()
            if isinstance(keydata.get("account_fingerprint"), str):
                results.account_fingerprint = keydata["account_fingerprint"]
            derivations = klass._get_derivations(account)
            for derivation_path_text, label_text in keydata["entries"]:
                try:
                    derivation_path = tuple(
                        bip32_decompose_chain_string(derivation_path_text))
                except (TypeError, ValueError):
                    pass
                else:
                    # We never import key descriptions if the account does not match.
                    if account_fingerprint == results.account_fingerprint:
                        keyinstance_id = derivations.get(derivation_path)
                        if keyinstance_id is not None:
                            results.key_labels[keyinstance_id] = label_text
                            continue
                results.unknown_labels[derivation_path_text] = label_text

        return results
Exemple #13
0
unlock_key_priv = PrivateKey.from_WIF(
    '****************************************************')
unlock_key_pub = unlock_key_priv.public_key
addr_dest = '1Pc1iF4g8iVmnu1puvGasSyDcwv2FS1VcH'
prev_txid = 'c1543650beafbf646e75aeeae9b091e4c477362db4a18e740d3f9d2ae250c013'
miner_fee = 120
contract = '../test/res/p2pkh.scrypt'

compiler_result = scryptlib.utils.compile_contract(contract)
desc = compiler_result.to_desc()

P2PKH = scryptlib.contract.build_contract_class(desc)
p2pkh_obj = P2PKH(Ripemd160(addr_dest))

prev_tx_hash = hex_str_to_hash(prev_txid)
prev_out_idx = 0

r = requests.get(
    'https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(prev_txid)).json()
prev_locking_script = Script.from_hex(
    r['vout'][prev_out_idx]['scriptPubKey']['hex'])
unlocked_satoshis = int(r['vout'][prev_out_idx]['value'] * 10**8)
out_satoshis = unlocked_satoshis - miner_fee
n_sequence = 0xffffffff

tx_input = TxInput(prev_tx_hash, prev_out_idx, None, n_sequence)
tx_output = TxOutput(out_satoshis, p2pkh_obj.locking_script)

tx = Tx(2, [tx_input], [tx_output], 0x00000000)
class Net(metaclass=_CurrentNetMeta):

    _net = SVTestnet


SPENDABLE_UTXOS = [
    UTXO(address=Address.from_string('miz93i75XiTdnvzkU6sDddvGcCr4ZrCmou',
                                     Net.COIN),
         is_coinbase=False,
         out_index=0,
         script_pubkey=Script(
             b'v\xa9\x14&\x0c\x95\x8e\x81\xc8o\xe3.\xc3\xd4\x1d7\x1cy'
             b'\x0e\xed\x9a\xb4\xf3\x88\xac'),
         tx_hash=hex_str_to_hash(
             '76d5bfabe40ca6cbd315b04aa24b68fdd8179869fd1c3501d5a88a980c61c1bf'
         ),
         value=100000,
         script_type=ScriptType.P2PKH,
         keyinstance_id=0,
         flags=TransactionOutputFlag.NONE),
    UTXO(address=Address.from_string('msccMGHunfHANQWXMZragRggHMkJaBWSFr',
                                     Net.COIN),
         is_coinbase=False,
         out_index=0,
         script_pubkey=Script(
             b'v\xa9\x14\x84\xb3[1i\xe4+"}+\x9d\x85s!\t\xa1y\xab\xff'
             b'\x12\x88\xac'),
         tx_hash=hex_str_to_hash(
             '76d5bfabe40ca6cbd315b04aa24b68fdd8179869fd1c3501d5a88a980c61c1bf'
         ),
Exemple #15
0
def reverse_hash(hex_string):
    hex_string = bitcoinx.hex_str_to_hash(hex_string)[::-1]
    return bitcoinx.hash_to_hex_str(hex_string)