コード例 #1
0
ファイル: test_lnutil.py プロジェクト: kkoenen/electrum
    def htlc_tx(self, htlc, htlc_output_index, amount_msat, htlc_payment_preimage, remote_htlc_sig, success, cltv_timeout, local_feerate_per_kw, our_commit_tx):
        _script, our_htlc_tx_output = make_htlc_tx_output(
            amount_msat=amount_msat,
            local_feerate=local_feerate_per_kw,
            revocationpubkey=local_revocation_pubkey,
            local_delayedpubkey=local_delayedpubkey,
            success=success,
            to_self_delay=local_delay)
        our_htlc_tx_inputs = make_htlc_tx_inputs(
            htlc_output_txid=our_commit_tx.txid(),
            htlc_output_index=htlc_output_index,
            amount_msat=amount_msat,
            witness_script=bh2u(htlc))
        our_htlc_tx = make_htlc_tx(
            cltv_expiry=cltv_timeout,
            inputs=our_htlc_tx_inputs,
            output=our_htlc_tx_output)

        local_sig = our_htlc_tx.sign_txin(0, local_privkey[:-1])

        our_htlc_tx_witness = make_htlc_tx_witness(
            remotehtlcsig=bfh(remote_htlc_sig) + b"\x01",  # 0x01 is SIGHASH_ALL
            localhtlcsig=bfh(local_sig),
            payment_preimage=htlc_payment_preimage if success else b'',  # will put 00 on witness if timeout
            witness_script=htlc)
        our_htlc_tx._inputs[0]['witness'] = bh2u(our_htlc_tx_witness)
        return str(our_htlc_tx)
コード例 #2
0
    def test_version_bytes(self):
        xprv_headers_b58 = {
            'standard': 'tprv',
            'p2wpkh-p2sh': 'uprv',
            'p2wsh-p2sh': 'Uprv',
            'p2wpkh': 'vprv',
            'p2wsh': 'Vprv',
        }
        xpub_headers_b58 = {
            'standard': 'tpub',
            'p2wpkh-p2sh': 'upub',
            'p2wsh-p2sh': 'Upub',
            'p2wpkh': 'vpub',
            'p2wsh': 'Vpub',
        }
        for xtype, xkey_header_bytes in constants.net.XPRV_HEADERS.items():
            xkey_header_bytes = bfh("%08x" % xkey_header_bytes)
            xkey_bytes = xkey_header_bytes + bytes([0] * 74)
            xkey_b58 = EncodeBase58Check(xkey_bytes)
            self.assertTrue(xkey_b58.startswith(xprv_headers_b58[xtype]))

            xkey_bytes = xkey_header_bytes + bytes([255] * 74)
            xkey_b58 = EncodeBase58Check(xkey_bytes)
            self.assertTrue(xkey_b58.startswith(xprv_headers_b58[xtype]))

        for xtype, xkey_header_bytes in constants.net.XPUB_HEADERS.items():
            xkey_header_bytes = bfh("%08x" % xkey_header_bytes)
            xkey_bytes = xkey_header_bytes + bytes([0] * 74)
            xkey_b58 = EncodeBase58Check(xkey_bytes)
            self.assertTrue(xkey_b58.startswith(xpub_headers_b58[xtype]))

            xkey_bytes = xkey_header_bytes + bytes([255] * 74)
            xkey_b58 = EncodeBase58Check(xkey_bytes)
            self.assertTrue(xkey_b58.startswith(xpub_headers_b58[xtype]))
コード例 #3
0
ファイル: paytoedit.py プロジェクト: kkoenen/electrum
 def parse_script(self, x):
     script = ''
     for word in x.split():
         if word[0:3] == 'OP_':
             opcode_int = opcodes[word]
             assert opcode_int < 256  # opcode is single-byte
             script += bitcoin.int_to_hex(opcode_int)
         else:
             bfh(word)  # to test it is hex data
             script += push_script(word)
     return script
コード例 #4
0
    def test_decode_onion_error(self):
        # test vector from bolt-04
        payment_path_pubkeys = [
            bfh('02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619'
                ),
            bfh('0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c'
                ),
            bfh('027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007'
                ),
            bfh('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991'
                ),
            bfh('02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145'
                ),
        ]
        session_key = bfh(
            '4141414141414141414141414141414141414141414141414141414141414141')
        error_packet_for_node_0 = bfh(
            '9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d'
        )

        decoded_error, index_of_sender = _decode_onion_error(
            error_packet_for_node_0, payment_path_pubkeys, session_key)
        self.assertEqual(
            bfh('4c2fc8bc08510334b6833ad9c3e79cd1b52ae59dfe5c2a4b23ead50f09f7ee0b0002200200fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
                ), decoded_error)
        self.assertEqual(4, index_of_sender)

        failure_msg, index_of_sender = decode_onion_error(
            error_packet_for_node_0, payment_path_pubkeys, session_key)
        self.assertEqual(4, index_of_sender)
        self.assertEqual(OnionFailureCode.TEMPORARY_NODE_FAILURE,
                         failure_msg.code)
        self.assertEqual(b'', failure_msg.data)
コード例 #5
0
 def get_noise_map(
         cls, versioned_seed: VersionedSeed) -> Dict[Tuple[int, int], int]:
     """Returns a map from (x,y) coordinate to pixel value 0/1, to be used as rawnoise."""
     w, h = cls.SIZE
     version = versioned_seed.version
     hex_seed = versioned_seed.seed
     checksum = versioned_seed.checksum
     noise_map = {}
     if version == '0':
         random.seed(int(hex_seed, 16))
         for x in range(w):
             for y in range(h):
                 noise_map[(x, y)] = random.randint(0, 1)
     elif version == '1':
         prng_seed = bfh(hex_seed + version + checksum)
         drbg = DRBG(prng_seed)
         num_noise_bytes = 1929  # ~ w*h
         noise_array = bin(
             int.from_bytes(drbg.generate(num_noise_bytes), 'big'))[2:]
         # there's an approx 1/1024 chance that the generated number is 'too small'
         # and we would get IndexError below. easiest backwards compat fix:
         noise_array += '0' * (w * h - len(noise_array))
         i = 0
         for x in range(w):
             for y in range(h):
                 noise_map[(x, y)] = int(noise_array[i])
                 i += 1
     else:
         raise Exception(f"unexpected revealer version: {version}")
     return noise_map
コード例 #6
0
ファイル: qt.py プロジェクト: kkoenen/electrum
    def do_send(self, tx):
        def on_success(result):
            window.show_message(
                _("Your transaction was sent to the cosigning pool.") + '\n' +
                _("Open your cosigner wallet to retrieve it."))

        def on_failure(exc_info):
            e = exc_info[1]
            try:
                self.logger.error("on_failure", exc_info=exc_info)
            except OSError:
                pass
            window.show_error(
                _("Failed to send transaction to cosigning pool") + ':\n' +
                repr(e))

        for window, xpub, K, _hash in self.cosigner_list:
            if not self.cosigner_can_sign(tx, xpub):
                continue
            # construct message
            raw_tx_bytes = bfh(str(tx))
            public_key = ecc.ECPubkey(K)
            message = public_key.encrypt_message(raw_tx_bytes).decode('ascii')
            # send message
            task = lambda: server.put(_hash, message)
            msg = _('Sending transaction to cosigning pool...')
            WaitingDialog(window, msg, task, on_success, on_failure)
コード例 #7
0
 def test_base58check(self):
     data_hex = '0cd394bef396200774544c58a5be0189f3ceb6a41c8da023b099ce547dd4d8071ed6ed647259fba8c26382edbf5165dfd2404e7a8885d88437db16947a116e451a5d1325e3fd075f9d370120d2ab537af69f32e74fc0ba53aaaa637752964b3ac95cfea7'
     data_bytes = bfh(data_hex)
     data_base58check = EncodeBase58Check(data_bytes)
     self.assertEqual(
         "4GCCJsjHqFbHxWbFBvRg35cSeNLHKeNqkXqFHW87zRmz6iP1dJU9Tk2KHZkoKj45jzVsSV4ZbQ8GpPwko6V3Z7cRfux3zJhUw7TZB6Kpa8Vdya8cMuUtL5Ry3CLtMetaY42u52X7Ey6MAH",
         data_base58check)
     self.assertEqual(data_bytes, DecodeBase58Check(data_base58check))
コード例 #8
0
 def test_base43(self):
     tx_hex = "020000000001021cd0e96f9ca202e017ca3465e3c13373c0df3a4cdd91c1fd02ea42a1a65d2a410000000000fdffffff757da7cf8322e5063785e2d8ada74702d2648fa2add2d533ba83c52eb110df690200000000fdffffff02d07e010000000000160014b544c86eaf95e3bb3b6d2cabb12ab40fc59cad9ca086010000000000232102ce0d066fbfcf150a5a1bbc4f312cd2eb080e8d8a47e5f2ce1a63b23215e54fb5ac02483045022100a9856bf10a950810abceeabc9a86e6ba533e130686e3d7863971b9377e7c658a0220288a69ef2b958a7c2ecfa376841d4a13817ed24fa9a0e0a6b9cb48e6439794c701210324e291735f83ff8de47301b12034950b80fa4724926a34d67e413d8ff8817c53024830450221008f885978f7af746679200ed55fe2e86c1303620824721f95cc41eb7965a3dfcf02207872082ac4a3c433d41a203e6d685a459e70e551904904711626ac899238c20a0121023d4c9deae1aacf3f822dd97a28deaec7d4e4ff97be746d124a63d20e582f5b290a971600"
     tx_bytes = bfh(tx_hex)
     tx_base43 = base_encode(tx_bytes, 43)
     self.assertEqual(
         "3E2DH7.J3PKVZJ3RCOXQVS3Y./6-WE.75DDU0K58-0N1FRL565N8ZH-DG1Z.1IGWTE5HK8F7PWH5P8+V3XGZZ6GQBPHNDE+RD8CAQVV1/6PQEMJIZTGPMIJ93B8P$QX+Y2R:TGT9QW8S89U4N2.+FUT8VG+34USI/N/JJ3CE*KLSW:REE8T5Y*9:U6515JIUR$6TODLYHSDE3B5DAF:5TF7V*VAL3G40WBOM0DO2+CFKTTM$G-SO:8U0EW:M8V:4*R9ZDX$B1IRBP9PLMDK8H801PNTFB4$HL1+/U3F61P$4N:UAO88:N5D+J:HI4YR8IM:3A7K1YZ9VMRC/47$6GGW5JEL1N690TDQ4XW+TWHD:V.1.630QK*JN/.EITVU80YS3.8LWKO:2STLWZAVHUXFHQ..NZ0:.J/FTZM.KYDXIE1VBY7/:PHZMQ$.JZQ2.XT32440X/HM+UY/7QP4I+HTD9.DUSY-8R6HDR-B8/PF2NP7I2-MRW9VPW3U9.S0LQ.*221F8KVMD5ANJXZJ8WV4UFZ4R.$-NXVE+-FAL:WFERGU+WHJTHAP",
         tx_base43)
     self.assertEqual(tx_bytes, base_decode(tx_base43, None, 43))
コード例 #9
0
 def test_base58(self):
     data_hex = '0cd394bef396200774544c58a5be0189f3ceb6a41c8da023b099ce547dd4d8071ed6ed647259fba8c26382edbf5165dfd2404e7a8885d88437db16947a116e451a5d1325e3fd075f9d370120d2ab537af69f32e74fc0ba53aaaa637752964b3ac95cfea7'
     data_bytes = bfh(data_hex)
     data_base58 = base_encode(data_bytes, 58)
     self.assertEqual(
         "VuvZ2K5UEcXCVcogny7NH4Evd9UfeYipsTdWuU4jLDhyaESijKtrGWZTFzVZJPjaoC9jFBs3SFtarhDhQhAxkXosUD8PmUb5UXW1tafcoPiCp8jHy7Fe2CUPXAbYuMvAyrkocbe6",
         data_base58)
     self.assertEqual(data_bytes, base_decode(data_base58, None, 58))
コード例 #10
0
ファイル: test_lnutil.py プロジェクト: kkoenen/electrum
 def test_key_derivation(self):
     # BOLT3, Appendix E
     base_secret = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
     per_commitment_secret = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100
     revocation_basepoint_secret = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
     base_point = secret_to_pubkey(base_secret)
     self.assertEqual(base_point, bfh('036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2'))
     per_commitment_point = secret_to_pubkey(per_commitment_secret)
     self.assertEqual(per_commitment_point, bfh('025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486'))
     localpubkey = derive_pubkey(base_point, per_commitment_point)
     self.assertEqual(localpubkey, bfh('0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5'))
     localprivkey = derive_privkey(base_secret, per_commitment_point)
     self.assertEqual(localprivkey, 0xcbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f)
     revocation_basepoint = secret_to_pubkey(revocation_basepoint_secret)
     self.assertEqual(revocation_basepoint, bfh('036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2'))
     revocationpubkey = derive_blinded_pubkey(revocation_basepoint, per_commitment_point)
     self.assertEqual(revocationpubkey, bfh('02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0'))
コード例 #11
0
def trezor_validate_op_return_output_and_get_data(output: TxOutput) -> bytes:
    if output.type != TYPE_SCRIPT:
        raise Exception("Unexpected output type: {}".format(output.type))
    script = bfh(output.address)
    if not (script[0] == opcodes.OP_RETURN and
            script[1] == len(script) - 2 and script[1] <= 75):
        raise UserFacingException(_("Only OP_RETURN scripts, with one constant push, are supported."))
    if output.value != 0:
        raise UserFacingException(_("Amount for OP_RETURN output must be zero."))
    return script[2:]
コード例 #12
0
ファイル: build_psbt.py プロジェクト: kkoenen/electrum
    def write_kv(ktype, val, key=b''):
        # serialize helper: write w/ size and key byte
        out_fd.write(my_var_int(1 + len(key)))
        out_fd.write(bytes([ktype]) + key)

        if isinstance(val, str):
            val = bfh(val)

        out_fd.write(my_var_int(len(val)))
        out_fd.write(val)
コード例 #13
0
 def show_qr(self):
     text = bfh(str(self.tx))
     text = base_encode(text, base=43)
     try:
         self.main_window.show_qrcode(text, 'Transaction', parent=self)
     except qrcode.exceptions.DataOverflowError:
         self.show_error(
             _('Failed to display QR code.') + '\n' +
             _('Transaction is too large in size.'))
     except Exception as e:
         self.show_error(_('Failed to display QR code.') + '\n' + repr(e))
コード例 #14
0
ファイル: trezor.py プロジェクト: kkoenen/electrum
    def tx_inputs(self, tx, xpub_path, for_sig=False):
        inputs = []
        for txin in tx.inputs():
            txinputtype = TxInputType()
            if txin['type'] == 'coinbase':
                prev_hash = b"\x00" * 32
                prev_index = 0xffffffff  # signed int -1
            else:
                if for_sig:
                    x_pubkeys = txin['x_pubkeys']
                    xpubs = [parse_xpubkey(x) for x in x_pubkeys]
                    multisig = self._make_multisig(txin.get('num_sig'), xpubs,
                                                   txin.get('signatures'))
                    script_type = self.get_trezor_input_script_type(
                        txin['type'])
                    txinputtype = TxInputType(script_type=script_type,
                                              multisig=multisig)
                    # find which key is mine
                    for xpub, deriv in xpubs:
                        if xpub in xpub_path:
                            xpub_n = parse_path(xpub_path[xpub])
                            txinputtype.address_n = xpub_n + deriv
                            break

                prev_hash = bfh(txin['prevout_hash'])
                prev_index = txin['prevout_n']

            if 'value' in txin:
                txinputtype.amount = txin['value']
            txinputtype.prev_hash = prev_hash
            txinputtype.prev_index = prev_index

            if txin.get('scriptSig') is not None:
                script_sig = bfh(txin['scriptSig'])
                txinputtype.script_sig = script_sig

            txinputtype.sequence = txin.get('sequence', 0xffffffff - 1)

            inputs.append(txinputtype)

        return inputs
コード例 #15
0
 def test_push_script(self):
     # https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#push-operators
     self.assertEqual(push_script(''), bh2u(bytes([opcodes.OP_0])))
     self.assertEqual(push_script('07'), bh2u(bytes([opcodes.OP_7])))
     self.assertEqual(push_script('10'), bh2u(bytes([opcodes.OP_16])))
     self.assertEqual(push_script('81'), bh2u(bytes([opcodes.OP_1NEGATE])))
     self.assertEqual(push_script('11'), '0111')
     self.assertEqual(push_script(75 * '42'), '4b' + 75 * '42')
     self.assertEqual(
         push_script(76 * '42'),
         bh2u(bytes([opcodes.OP_PUSHDATA1]) + bfh('4c' + 76 * '42')))
     self.assertEqual(
         push_script(100 * '42'),
         bh2u(bytes([opcodes.OP_PUSHDATA1]) + bfh('64' + 100 * '42')))
     self.assertEqual(
         push_script(255 * '42'),
         bh2u(bytes([opcodes.OP_PUSHDATA1]) + bfh('ff' + 255 * '42')))
     self.assertEqual(
         push_script(256 * '42'),
         bh2u(bytes([opcodes.OP_PUSHDATA2]) + bfh('0001' + 256 * '42')))
     self.assertEqual(
         push_script(520 * '42'),
         bh2u(bytes([opcodes.OP_PUSHDATA2]) + bfh('0802' + 520 * '42')))
コード例 #16
0
ファイル: trezor.py プロジェクト: kkoenen/electrum
 def electrum_tx_to_txtype(self, tx, xpub_path):
     t = TransactionType()
     if tx is None:
         # probably for segwit input and we don't need this prev txn
         return t
     d = deserialize(tx.raw)
     t.version = d['version']
     t.lock_time = d['lockTime']
     t.inputs = self.tx_inputs(tx, xpub_path)
     t.bin_outputs = [
         TxOutputBinType(amount=vout['value'],
                         script_pubkey=bfh(vout['scriptPubKey']))
         for vout in d['outputs']
     ]
     return t
コード例 #17
0
ファイル: keepkey.py プロジェクト: kkoenen/electrum
 def electrum_tx_to_txtype(self, tx):
     t = self.types.TransactionType()
     if tx is None:
         # probably for segwit input and we don't need this prev txn
         return t
     d = deserialize(tx.raw)
     t.version = d['version']
     t.lock_time = d['lockTime']
     inputs = self.tx_inputs(tx)
     t.inputs.extend(inputs)
     for vout in d['outputs']:
         o = t.bin_outputs.add()
         o.amount = vout['value']
         o.script_pubkey = bfh(vout['scriptPubKey'])
     return t
コード例 #18
0
ファイル: trezor.py プロジェクト: kkoenen/electrum
    def _make_multisig(self, m, xpubs, signatures=None):
        if len(xpubs) == 1:
            return None

        pubkeys = [self._make_node_path(xpub, deriv) for xpub, deriv in xpubs]
        if signatures is None:
            signatures = [b''] * len(pubkeys)
        elif len(signatures) != len(pubkeys):
            raise RuntimeError('Mismatched number of signatures')
        else:
            signatures = [bfh(x)[:-1] if x else b'' for x in signatures]

        return MultisigRedeemScriptType(pubkeys=pubkeys,
                                        signatures=signatures,
                                        m=m)
コード例 #19
0
    def _do_test_bip32(self, seed: str, sequence):
        node = BIP32Node.from_rootseed(bfh(seed), xtype='standard')
        xprv, xpub = node.to_xprv(), node.to_xpub()
        self.assertEqual("m/", sequence[0:2])
        sequence = sequence[2:]
        for n in sequence.split('/'):
            if n[-1] != "'":
                xpub2 = BIP32Node.from_xkey(xpub).subkey_at_public_derivation(
                    n).to_xpub()
            node = BIP32Node.from_xkey(xprv).subkey_at_private_derivation(n)
            xprv, xpub = node.to_xprv(), node.to_xpub()
            if n[-1] != "'":
                self.assertEqual(xpub, xpub2)

        return xpub, xprv
コード例 #20
0
ファイル: trezor.py プロジェクト: kkoenen/electrum
 def sign_transaction(self, keystore, tx, prev_tx, xpub_path):
     prev_tx = {
         bfh(txhash): self.electrum_tx_to_txtype(tx, xpub_path)
         for txhash, tx in prev_tx.items()
     }
     client = self.get_client(keystore)
     inputs = self.tx_inputs(tx, xpub_path, True)
     outputs = self.tx_outputs(keystore.get_derivation(), tx)
     details = SignTx(lock_time=tx.locktime, version=tx.version)
     signatures, _ = client.sign_tx(self.get_coin_name(),
                                    inputs,
                                    outputs,
                                    details=details,
                                    prev_txes=prev_tx)
     signatures = [(bh2u(x) + '01') for x in signatures]
     tx.update_signatures(signatures)
コード例 #21
0
ファイル: coldcard.py プロジェクト: kkoenen/electrum
    def show_address(self, wallet, address, keystore=None):
        if keystore is None:
            keystore = wallet.get_keystore()
        if not self.show_address_helper(wallet, address, keystore):
            return

        txin_type = wallet.get_txin_type(address)

        # Standard_Wallet => not multisig, must be bip32
        if type(wallet) is Standard_Wallet:
            sequence = wallet.get_address_index(address)
            keystore.show_address(sequence, txin_type)
        elif type(wallet) is Multisig_Wallet:
            # More involved for P2SH/P2WSH addresses: need M, and all public keys, and their
            # derivation paths. Must construct script, and track fingerprints+paths for
            # all those keys

            pubkeys = wallet.get_public_keys(address)

            xfps = []
            for xp, ks in zip(wallet.get_master_public_keys(),
                              wallet.get_keystores()):
                path = "%s/%d/%d" % (getattr(
                    ks, 'derivation', 'm'), *wallet.get_address_index(address))

                # need master XFP for each co-signers
                ks_xfp = xfp_for_keystore(ks)
                xfps.append(unpacked_xfp_path(ks_xfp, path))

            # put into BIP45 (sorted) order
            pkx = list(sorted(zip(pubkeys, xfps)))

            script = bfh(multisig_script([pk for pk, xfp in pkx], wallet.m))

            keystore.show_p2sh_address(wallet.m, script,
                                       [xfp for pk, xfp in pkx], txin_type)

        else:
            keystore.handler.show_error(
                _('This function is only available for standard wallets when using {}.'
                  ).format(self.device))
            return
コード例 #22
0
    def test_sign_transaction(self):
        eckey1 = ecc.ECPrivkey(
            bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d'
                ))
        sig1 = eckey1.sign_transaction(
            bfh('5a548b12369a53faaa7e51b5081829474ebdd9c924b3a8230b69aa0be254cd94'
                ))
        self.assertEqual(
            bfh('3045022100902a288b98392254cd23c0e9a49ac6d7920f171b8249a48e484b998f1874a2010220723d844826828f092cf400cb210c4fa0b8cd1b9d1a7f21590e78e022ff6476b9'
                ), sig1)

        eckey2 = ecc.ECPrivkey(
            bfh('c7ce8c1462c311eec24dff9e2532ac6241e50ae57e7d1833af21942136972f23'
                ))
        sig2 = eckey2.sign_transaction(
            bfh('642a2e66332f507c92bda910158dfe46fc10afbf72218764899d3af99a043fac'
                ))
        self.assertEqual(
            bfh('30440220618513f4cfc87dde798ce5febae7634c23e7b9254a1eabf486be820f6a7c2c4702204fef459393a2b931f949e63ced06888f35e286e446dc46feb24b5b5f81c6ed52'
                ), sig2)
コード例 #23
0
class TestBlockchain(ElectrumTestCase):

    HEADERS = {
        'A':
        deserialize_header(
            bfh("0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2002000000"
                ), 0),
        'B':
        deserialize_header(
            bfh("0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f186c8dfd970a4545f79916bc1d75c9d00432f57c89209bf3bb115b7612848f509c25f45bffff7f2000000000"
                ), 1),
        'C':
        deserialize_header(
            bfh("00000020686bdfc6a3db73d5d93e8c9663a720a26ecb1ef20eb05af11b36cdbc57c19f7ebf2cbf153013a1c54abaf70e95198fcef2f3059cc6b4d0f7e876808e7d24d11cc825f45bffff7f2000000000"
                ), 2),
        'D':
        deserialize_header(
            bfh("00000020122baa14f3ef54985ae546d1611559e3f487bd2a0f46e8dbb52fbacc9e237972e71019d7feecd9b8596eca9a67032c5f4641b23b5d731dc393e37de7f9c2f299e725f45bffff7f2000000000"
                ), 3),
        'E':
        deserialize_header(
            bfh("00000020f8016f7ef3a17d557afe05d4ea7ab6bde1b2247b7643896c1b63d43a1598b747a3586da94c71753f27c075f57f44faf913c31177a0957bbda42e7699e3a2141aed25f45bffff7f2001000000"
                ), 4),
        'F':
        deserialize_header(
            bfh("000000201d589c6643c1d121d73b0573e5ee58ab575b8fdf16d507e7e915c5fbfbbfd05e7aee1d692d1615c3bdf52c291032144ce9e3b258a473c17c745047f3431ff8e2ee25f45bffff7f2000000000"
                ), 5),
        'O':
        deserialize_header(
            bfh("00000020b833ed46eea01d4c980f59feee44a66aa1162748b6801029565d1466790c405c3a141ce635cbb1cd2b3a4fcdd0a3380517845ba41736c82a79cab535d31128066526f45bffff7f2001000000"
                ), 6),
        'P':
        deserialize_header(
            bfh("00000020abe8e119d1877c9dc0dc502d1a253fb9a67967c57732d2f71ee0280e8381ff0a9690c2fe7c1a4450c74dc908fe94dd96c3b0637d51475e9e06a78e944a0c7fe28126f45bffff7f2000000000"
                ), 7),
        'Q':
        deserialize_header(
            bfh("000000202ce41d94eb70e1518bc1f72523f84a903f9705d967481e324876e1f8cf4d3452148be228a4c3f2061bafe7efdfc4a8d5a94759464b9b5c619994d45dfcaf49e1a126f45bffff7f2000000000"
                ), 8),
        'R':
        deserialize_header(
            bfh("00000020552755b6c59f3d51e361d16281842a4e166007799665b5daed86a063dd89857415681cb2d00ff889193f6a68a93f5096aeb2d84ca0af6185a462555822552221a626f45bffff7f2000000000"
                ), 9),
        'S':
        deserialize_header(
            bfh("00000020a13a491cbefc93cd1bb1938f19957e22a134faf14c7dee951c45533e2c750f239dc087fc977b06c24a69c682d1afd1020e6dc1f087571ccec66310a786e1548fab26f45bffff7f2000000000"
                ), 10),
        'T':
        deserialize_header(
            bfh("00000020dbf3a9b55dfefbaf8b6e43a89cf833fa2e208bbc0c1c5d76c0d71b9e4a65337803b243756c25053253aeda309604363460a3911015929e68705bd89dff6fe064b026f45bffff7f2002000000"
                ), 11),
        'U':
        deserialize_header(
            bfh("000000203d0932b3b0c78eccb39a595a28ae4a7c966388648d7783fd1305ec8d40d4fe5fd67cb902a7d807cee7676cb543feec3e053aa824d5dfb528d5b94f9760313d9db726f45bffff7f2001000000"
                ), 12),
        'G':
        deserialize_header(
            bfh("00000020b833ed46eea01d4c980f59feee44a66aa1162748b6801029565d1466790c405c3a141ce635cbb1cd2b3a4fcdd0a3380517845ba41736c82a79cab535d31128066928f45bffff7f2001000000"
                ), 6),
        'H':
        deserialize_header(
            bfh("00000020e19e687f6e7f83ca394c114144dbbbc4f3f9c9450f66331a125413702a2e1a719690c2fe7c1a4450c74dc908fe94dd96c3b0637d51475e9e06a78e944a0c7fe26a28f45bffff7f2002000000"
                ), 7),
        'I':
        deserialize_header(
            bfh("0000002009dcb3b158293c89d7cf7ceeb513add122ebc3880a850f47afbb2747f5e48c54148be228a4c3f2061bafe7efdfc4a8d5a94759464b9b5c619994d45dfcaf49e16a28f45bffff7f2000000000"
                ), 8),
        'J':
        deserialize_header(
            bfh("000000206a65f3bdd3374a5a6c4538008ba0b0a560b8566291f9ef4280ab877627a1742815681cb2d00ff889193f6a68a93f5096aeb2d84ca0af6185a462555822552221c928f45bffff7f2000000000"
                ), 9),
        'K':
        deserialize_header(
            bfh("00000020bb3b421653548991998f96f8ba486b652fdb07ca16e9cee30ece033547cd1a6e9dc087fc977b06c24a69c682d1afd1020e6dc1f087571ccec66310a786e1548fca28f45bffff7f2000000000"
                ), 10),
        'L':
        deserialize_header(
            bfh("00000020c391d74d37c24a130f4bf4737932bdf9e206dd4fad22860ec5408978eb55d46303b243756c25053253aeda309604363460a3911015929e68705bd89dff6fe064ca28f45bffff7f2000000000"
                ), 11),
        'M':
        deserialize_header(
            bfh("000000206a65f3bdd3374a5a6c4538008ba0b0a560b8566291f9ef4280ab877627a1742815681cb2d00ff889193f6a68a93f5096aeb2d84ca0af6185a4625558225522214229f45bffff7f2000000000"
                ), 9),
        'N':
        deserialize_header(
            bfh("00000020383dab38b57f98aa9b4f0d5ff868bc674b4828d76766bf048296f4c45fff680a9dc087fc977b06c24a69c682d1afd1020e6dc1f087571ccec66310a786e1548f4329f45bffff7f2003000000"
                ), 10),
        'X':
        deserialize_header(
            bfh("0000002067f1857f54b7fef732cb4940f7d1b339472b3514660711a820330fd09d8fba6b03b243756c25053253aeda309604363460a3911015929e68705bd89dff6fe0649b29f45bffff7f2002000000"
                ), 11),
        'Y':
        deserialize_header(
            bfh("00000020db33c9768a9e5f7c37d0f09aad88d48165946c87d08f7d63793f07b5c08c527fd67cb902a7d807cee7676cb543feec3e053aa824d5dfb528d5b94f9760313d9d9b29f45bffff7f2000000000"
                ), 12),
        'Z':
        deserialize_header(
            bfh("0000002047822b67940e337fda38be6f13390b3596e4dea2549250256879722073824e7f0f2596c29203f8a0f71ae94193092dc8f113be3dbee4579f1e649fa3d6dcc38c622ef45bffff7f2003000000"
                ), 13),
    }
    # tree of headers:
    #                                            - M <- N <- X <- Y <- Z
    #                                          /
    #                             - G <- H <- I <- J <- K <- L
    #                           /
    # A <- B <- C <- D <- E <- F <- O <- P <- Q <- R <- S <- T <- U

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        constants.set_regtest()

    @classmethod
    def tearDownClass(cls):
        super().tearDownClass()
        constants.set_mainnet()

    def setUp(self):
        super().setUp()
        self.data_dir = self.electrum_path
        make_dir(os.path.join(self.data_dir, 'forks'))
        self.config = SimpleConfig({'electrum_path': self.data_dir})
        blockchain.blockchains = {}

    def _append_header(self, chain: Blockchain, header: dict):
        self.assertTrue(chain.can_connect(header))
        chain.save_header(header)

    def test_get_height_of_last_common_block_with_chain(self):
        blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
            config=self.config,
            forkpoint=0,
            parent=None,
            forkpoint_hash=constants.net.GENESIS,
            prev_hash=None)
        open(chain_u.path(), 'w+').close()
        self._append_header(chain_u, self.HEADERS['A'])
        self._append_header(chain_u, self.HEADERS['B'])
        self._append_header(chain_u, self.HEADERS['C'])
        self._append_header(chain_u, self.HEADERS['D'])
        self._append_header(chain_u, self.HEADERS['E'])
        self._append_header(chain_u, self.HEADERS['F'])
        self._append_header(chain_u, self.HEADERS['O'])
        self._append_header(chain_u, self.HEADERS['P'])
        self._append_header(chain_u, self.HEADERS['Q'])

        chain_l = chain_u.fork(self.HEADERS['G'])
        self._append_header(chain_l, self.HEADERS['H'])
        self._append_header(chain_l, self.HEADERS['I'])
        self._append_header(chain_l, self.HEADERS['J'])
        self._append_header(chain_l, self.HEADERS['K'])
        self._append_header(chain_l, self.HEADERS['L'])

        self.assertEqual({
            chain_u: 8,
            chain_l: 5
        }, chain_u.get_parent_heights())
        self.assertEqual({chain_l: 11}, chain_l.get_parent_heights())

        chain_z = chain_l.fork(self.HEADERS['M'])
        self._append_header(chain_z, self.HEADERS['N'])
        self._append_header(chain_z, self.HEADERS['X'])
        self._append_header(chain_z, self.HEADERS['Y'])
        self._append_header(chain_z, self.HEADERS['Z'])

        self.assertEqual({
            chain_u: 8,
            chain_z: 5
        }, chain_u.get_parent_heights())
        self.assertEqual({
            chain_l: 11,
            chain_z: 8
        }, chain_l.get_parent_heights())
        self.assertEqual({chain_z: 13}, chain_z.get_parent_heights())
        self.assertEqual(
            5, chain_u.get_height_of_last_common_block_with_chain(chain_l))
        self.assertEqual(
            5, chain_l.get_height_of_last_common_block_with_chain(chain_u))
        self.assertEqual(
            5, chain_u.get_height_of_last_common_block_with_chain(chain_z))
        self.assertEqual(
            5, chain_z.get_height_of_last_common_block_with_chain(chain_u))
        self.assertEqual(
            8, chain_l.get_height_of_last_common_block_with_chain(chain_z))
        self.assertEqual(
            8, chain_z.get_height_of_last_common_block_with_chain(chain_l))

        self._append_header(chain_u, self.HEADERS['R'])
        self._append_header(chain_u, self.HEADERS['S'])
        self._append_header(chain_u, self.HEADERS['T'])
        self._append_header(chain_u, self.HEADERS['U'])

        self.assertEqual({
            chain_u: 12,
            chain_z: 5
        }, chain_u.get_parent_heights())
        self.assertEqual({
            chain_l: 11,
            chain_z: 8
        }, chain_l.get_parent_heights())
        self.assertEqual({chain_z: 13}, chain_z.get_parent_heights())
        self.assertEqual(
            5, chain_u.get_height_of_last_common_block_with_chain(chain_l))
        self.assertEqual(
            5, chain_l.get_height_of_last_common_block_with_chain(chain_u))
        self.assertEqual(
            5, chain_u.get_height_of_last_common_block_with_chain(chain_z))
        self.assertEqual(
            5, chain_z.get_height_of_last_common_block_with_chain(chain_u))
        self.assertEqual(
            8, chain_l.get_height_of_last_common_block_with_chain(chain_z))
        self.assertEqual(
            8, chain_z.get_height_of_last_common_block_with_chain(chain_l))

    def test_parents_after_forking(self):
        blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
            config=self.config,
            forkpoint=0,
            parent=None,
            forkpoint_hash=constants.net.GENESIS,
            prev_hash=None)
        open(chain_u.path(), 'w+').close()
        self._append_header(chain_u, self.HEADERS['A'])
        self._append_header(chain_u, self.HEADERS['B'])
        self._append_header(chain_u, self.HEADERS['C'])
        self._append_header(chain_u, self.HEADERS['D'])
        self._append_header(chain_u, self.HEADERS['E'])
        self._append_header(chain_u, self.HEADERS['F'])
        self._append_header(chain_u, self.HEADERS['O'])
        self._append_header(chain_u, self.HEADERS['P'])
        self._append_header(chain_u, self.HEADERS['Q'])

        self.assertEqual(None, chain_u.parent)

        chain_l = chain_u.fork(self.HEADERS['G'])
        self._append_header(chain_l, self.HEADERS['H'])
        self._append_header(chain_l, self.HEADERS['I'])
        self._append_header(chain_l, self.HEADERS['J'])
        self._append_header(chain_l, self.HEADERS['K'])
        self._append_header(chain_l, self.HEADERS['L'])

        self.assertEqual(None, chain_l.parent)
        self.assertEqual(chain_l, chain_u.parent)

        chain_z = chain_l.fork(self.HEADERS['M'])
        self._append_header(chain_z, self.HEADERS['N'])
        self._append_header(chain_z, self.HEADERS['X'])
        self._append_header(chain_z, self.HEADERS['Y'])
        self._append_header(chain_z, self.HEADERS['Z'])

        self.assertEqual(chain_z, chain_u.parent)
        self.assertEqual(chain_z, chain_l.parent)
        self.assertEqual(None, chain_z.parent)

        self._append_header(chain_u, self.HEADERS['R'])
        self._append_header(chain_u, self.HEADERS['S'])
        self._append_header(chain_u, self.HEADERS['T'])
        self._append_header(chain_u, self.HEADERS['U'])

        self.assertEqual(chain_z, chain_u.parent)
        self.assertEqual(chain_z, chain_l.parent)
        self.assertEqual(None, chain_z.parent)

    def test_forking_and_swapping(self):
        blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
            config=self.config,
            forkpoint=0,
            parent=None,
            forkpoint_hash=constants.net.GENESIS,
            prev_hash=None)
        open(chain_u.path(), 'w+').close()

        self._append_header(chain_u, self.HEADERS['A'])
        self._append_header(chain_u, self.HEADERS['B'])
        self._append_header(chain_u, self.HEADERS['C'])
        self._append_header(chain_u, self.HEADERS['D'])
        self._append_header(chain_u, self.HEADERS['E'])
        self._append_header(chain_u, self.HEADERS['F'])
        self._append_header(chain_u, self.HEADERS['O'])
        self._append_header(chain_u, self.HEADERS['P'])
        self._append_header(chain_u, self.HEADERS['Q'])
        self._append_header(chain_u, self.HEADERS['R'])

        chain_l = chain_u.fork(self.HEADERS['G'])
        self._append_header(chain_l, self.HEADERS['H'])
        self._append_header(chain_l, self.HEADERS['I'])
        self._append_header(chain_l, self.HEADERS['J'])

        # do checks
        self.assertEqual(2, len(blockchain.blockchains))
        self.assertEqual(1,
                         len(os.listdir(os.path.join(self.data_dir, "forks"))))
        self.assertEqual(0, chain_u.forkpoint)
        self.assertEqual(None, chain_u.parent)
        self.assertEqual(constants.net.GENESIS, chain_u._forkpoint_hash)
        self.assertEqual(None, chain_u._prev_hash)
        self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"),
                         chain_u.path())
        self.assertEqual(10 * 80, os.stat(chain_u.path()).st_size)
        self.assertEqual(6, chain_l.forkpoint)
        self.assertEqual(chain_u, chain_l.parent)
        self.assertEqual(hash_header(self.HEADERS['G']),
                         chain_l._forkpoint_hash)
        self.assertEqual(hash_header(self.HEADERS['F']), chain_l._prev_hash)
        self.assertEqual(
            os.path.join(
                self.data_dir, "forks",
                "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_711a2e2a701354121a33660f45c9f9f3c4bbdb4441114c39ca837f6e7f689ee1"
            ), chain_l.path())
        self.assertEqual(4 * 80, os.stat(chain_l.path()).st_size)

        self._append_header(chain_l, self.HEADERS['K'])

        # chains were swapped, do checks
        self.assertEqual(2, len(blockchain.blockchains))
        self.assertEqual(1,
                         len(os.listdir(os.path.join(self.data_dir, "forks"))))
        self.assertEqual(6, chain_u.forkpoint)
        self.assertEqual(chain_l, chain_u.parent)
        self.assertEqual(hash_header(self.HEADERS['O']),
                         chain_u._forkpoint_hash)
        self.assertEqual(hash_header(self.HEADERS['F']), chain_u._prev_hash)
        self.assertEqual(
            os.path.join(
                self.data_dir, "forks",
                "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_aff81830e28e01ef7d23277c56779a6b93f251a2d50dcc09d7c87d119e1e8ab"
            ), chain_u.path())
        self.assertEqual(4 * 80, os.stat(chain_u.path()).st_size)
        self.assertEqual(0, chain_l.forkpoint)
        self.assertEqual(None, chain_l.parent)
        self.assertEqual(constants.net.GENESIS, chain_l._forkpoint_hash)
        self.assertEqual(None, chain_l._prev_hash)
        self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"),
                         chain_l.path())
        self.assertEqual(11 * 80, os.stat(chain_l.path()).st_size)
        for b in (chain_u, chain_l):
            self.assertTrue(
                all([
                    b.can_connect(b.read_header(i), False)
                    for i in range(b.height())
                ]))

        self._append_header(chain_u, self.HEADERS['S'])
        self._append_header(chain_u, self.HEADERS['T'])
        self._append_header(chain_u, self.HEADERS['U'])
        self._append_header(chain_l, self.HEADERS['L'])

        chain_z = chain_l.fork(self.HEADERS['M'])
        self._append_header(chain_z, self.HEADERS['N'])
        self._append_header(chain_z, self.HEADERS['X'])
        self._append_header(chain_z, self.HEADERS['Y'])
        self._append_header(chain_z, self.HEADERS['Z'])

        # chain_z became best chain, do checks
        self.assertEqual(3, len(blockchain.blockchains))
        self.assertEqual(2,
                         len(os.listdir(os.path.join(self.data_dir, "forks"))))
        self.assertEqual(0, chain_z.forkpoint)
        self.assertEqual(None, chain_z.parent)
        self.assertEqual(constants.net.GENESIS, chain_z._forkpoint_hash)
        self.assertEqual(None, chain_z._prev_hash)
        self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"),
                         chain_z.path())
        self.assertEqual(14 * 80, os.stat(chain_z.path()).st_size)
        self.assertEqual(9, chain_l.forkpoint)
        self.assertEqual(chain_z, chain_l.parent)
        self.assertEqual(hash_header(self.HEADERS['J']),
                         chain_l._forkpoint_hash)
        self.assertEqual(hash_header(self.HEADERS['I']), chain_l._prev_hash)
        self.assertEqual(
            os.path.join(
                self.data_dir, "forks",
                "fork2_9_2874a1277687ab8042eff9916256b860a5b0a08b0038456c5a4a37d3bdf3656a_6e1acd473503ce0ee3cee916ca07db2f656b48baf8968f999189545316423bbb"
            ), chain_l.path())
        self.assertEqual(3 * 80, os.stat(chain_l.path()).st_size)
        self.assertEqual(6, chain_u.forkpoint)
        self.assertEqual(chain_z, chain_u.parent)
        self.assertEqual(hash_header(self.HEADERS['O']),
                         chain_u._forkpoint_hash)
        self.assertEqual(hash_header(self.HEADERS['F']), chain_u._prev_hash)
        self.assertEqual(
            os.path.join(
                self.data_dir, "forks",
                "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_aff81830e28e01ef7d23277c56779a6b93f251a2d50dcc09d7c87d119e1e8ab"
            ), chain_u.path())
        self.assertEqual(7 * 80, os.stat(chain_u.path()).st_size)
        for b in (chain_u, chain_l, chain_z):
            self.assertTrue(
                all([
                    b.can_connect(b.read_header(i), False)
                    for i in range(b.height())
                ]))

        self.assertEqual(constants.net.GENESIS, chain_z.get_hash(0))
        self.assertEqual(hash_header(self.HEADERS['F']), chain_z.get_hash(5))
        self.assertEqual(hash_header(self.HEADERS['G']), chain_z.get_hash(6))
        self.assertEqual(hash_header(self.HEADERS['I']), chain_z.get_hash(8))
        self.assertEqual(hash_header(self.HEADERS['M']), chain_z.get_hash(9))
        self.assertEqual(hash_header(self.HEADERS['Z']), chain_z.get_hash(13))

    def test_doing_multiple_swaps_after_single_new_header(self):
        blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
            config=self.config,
            forkpoint=0,
            parent=None,
            forkpoint_hash=constants.net.GENESIS,
            prev_hash=None)
        open(chain_u.path(), 'w+').close()

        self._append_header(chain_u, self.HEADERS['A'])
        self._append_header(chain_u, self.HEADERS['B'])
        self._append_header(chain_u, self.HEADERS['C'])
        self._append_header(chain_u, self.HEADERS['D'])
        self._append_header(chain_u, self.HEADERS['E'])
        self._append_header(chain_u, self.HEADERS['F'])
        self._append_header(chain_u, self.HEADERS['O'])
        self._append_header(chain_u, self.HEADERS['P'])
        self._append_header(chain_u, self.HEADERS['Q'])
        self._append_header(chain_u, self.HEADERS['R'])
        self._append_header(chain_u, self.HEADERS['S'])

        self.assertEqual(1, len(blockchain.blockchains))
        self.assertEqual(0,
                         len(os.listdir(os.path.join(self.data_dir, "forks"))))

        chain_l = chain_u.fork(self.HEADERS['G'])
        self._append_header(chain_l, self.HEADERS['H'])
        self._append_header(chain_l, self.HEADERS['I'])
        self._append_header(chain_l, self.HEADERS['J'])
        self._append_header(chain_l, self.HEADERS['K'])
        # now chain_u is best chain, but it's tied with chain_l

        self.assertEqual(2, len(blockchain.blockchains))
        self.assertEqual(1,
                         len(os.listdir(os.path.join(self.data_dir, "forks"))))

        chain_z = chain_l.fork(self.HEADERS['M'])
        self._append_header(chain_z, self.HEADERS['N'])
        self._append_header(chain_z, self.HEADERS['X'])

        self.assertEqual(3, len(blockchain.blockchains))
        self.assertEqual(2,
                         len(os.listdir(os.path.join(self.data_dir, "forks"))))

        # chain_z became best chain, do checks
        self.assertEqual(0, chain_z.forkpoint)
        self.assertEqual(None, chain_z.parent)
        self.assertEqual(constants.net.GENESIS, chain_z._forkpoint_hash)
        self.assertEqual(None, chain_z._prev_hash)
        self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"),
                         chain_z.path())
        self.assertEqual(12 * 80, os.stat(chain_z.path()).st_size)
        self.assertEqual(9, chain_l.forkpoint)
        self.assertEqual(chain_z, chain_l.parent)
        self.assertEqual(hash_header(self.HEADERS['J']),
                         chain_l._forkpoint_hash)
        self.assertEqual(hash_header(self.HEADERS['I']), chain_l._prev_hash)
        self.assertEqual(
            os.path.join(
                self.data_dir, "forks",
                "fork2_9_2874a1277687ab8042eff9916256b860a5b0a08b0038456c5a4a37d3bdf3656a_6e1acd473503ce0ee3cee916ca07db2f656b48baf8968f999189545316423bbb"
            ), chain_l.path())
        self.assertEqual(2 * 80, os.stat(chain_l.path()).st_size)
        self.assertEqual(6, chain_u.forkpoint)
        self.assertEqual(chain_z, chain_u.parent)
        self.assertEqual(hash_header(self.HEADERS['O']),
                         chain_u._forkpoint_hash)
        self.assertEqual(hash_header(self.HEADERS['F']), chain_u._prev_hash)
        self.assertEqual(
            os.path.join(
                self.data_dir, "forks",
                "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_aff81830e28e01ef7d23277c56779a6b93f251a2d50dcc09d7c87d119e1e8ab"
            ), chain_u.path())
        self.assertEqual(5 * 80, os.stat(chain_u.path()).st_size)

        self.assertEqual(constants.net.GENESIS, chain_z.get_hash(0))
        self.assertEqual(hash_header(self.HEADERS['F']), chain_z.get_hash(5))
        self.assertEqual(hash_header(self.HEADERS['G']), chain_z.get_hash(6))
        self.assertEqual(hash_header(self.HEADERS['I']), chain_z.get_hash(8))
        self.assertEqual(hash_header(self.HEADERS['M']), chain_z.get_hash(9))
        self.assertEqual(hash_header(self.HEADERS['X']), chain_z.get_hash(11))

        for b in (chain_u, chain_l, chain_z):
            self.assertTrue(
                all([
                    b.can_connect(b.read_header(i), False)
                    for i in range(b.height())
                ]))
コード例 #24
0
 def setUp(self):
     super().setUp()
     self.header = deserialize_header(bfh(self.valid_header), 100)
コード例 #25
0
ファイル: keepkey.py プロジェクト: kkoenen/electrum
    def tx_inputs(self, tx, for_sig=False):
        inputs = []
        for txin in tx.inputs():
            txinputtype = self.types.TxInputType()
            if txin['type'] == 'coinbase':
                prev_hash = b"\x00" * 32
                prev_index = 0xffffffff  # signed int -1
            else:
                if for_sig:
                    x_pubkeys = txin['x_pubkeys']
                    if len(x_pubkeys) == 1:
                        x_pubkey = x_pubkeys[0]
                        xpub, s = parse_xpubkey(x_pubkey)
                        xpub_n = self.client_class.expand_path(
                            self.xpub_path[xpub])
                        txinputtype.address_n.extend(xpub_n + s)
                        txinputtype.script_type = self.get_keepkey_input_script_type(
                            txin['type'])
                    else:

                        def f(x_pubkey):
                            xpub, s = parse_xpubkey(x_pubkey)
                            return self._make_node_path(xpub, s)

                        pubkeys = list(map(f, x_pubkeys))
                        multisig = self.types.MultisigRedeemScriptType(
                            pubkeys=pubkeys,
                            signatures=map(lambda x: bfh(x)[:-1] if x else b'',
                                           txin.get('signatures')),
                            m=txin.get('num_sig'),
                        )
                        script_type = self.get_keepkey_input_script_type(
                            txin['type'])
                        txinputtype = self.types.TxInputType(
                            script_type=script_type, multisig=multisig)
                        # find which key is mine
                        for x_pubkey in x_pubkeys:
                            if is_xpubkey(x_pubkey):
                                xpub, s = parse_xpubkey(x_pubkey)
                                if xpub in self.xpub_path:
                                    xpub_n = self.client_class.expand_path(
                                        self.xpub_path[xpub])
                                    txinputtype.address_n.extend(xpub_n + s)
                                    break

                prev_hash = unhexlify(txin['prevout_hash'])
                prev_index = txin['prevout_n']

            if 'value' in txin:
                txinputtype.amount = txin['value']
            txinputtype.prev_hash = prev_hash
            txinputtype.prev_index = prev_index

            if txin.get('scriptSig') is not None:
                script_sig = bfh(txin['scriptSig'])
                txinputtype.script_sig = script_sig

            txinputtype.sequence = txin.get('sequence', 0xffffffff - 1)

            inputs.append(txinputtype)

        return inputs
コード例 #26
0
ファイル: ledger.py プロジェクト: kkoenen/electrum
    def sign_transaction(self, tx: Transaction, password):
        if tx.is_complete():
            return
        client = self.get_client()
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        changePath = ""
        output = None
        p2shTransaction = False
        segwitTransaction = False
        pin = ""
        self.get_client() # prompt for the PIN before displaying the dialog if necessary

        # Fetch inputs of the transaction to sign
        derivations = self.get_tx_derivations(tx)
        for txin in tx.inputs():
            if txin['type'] == 'coinbase':
                self.give_error("Coinbase not supported")     # should never happen

            if txin['type'] in ['p2sh']:
                p2shTransaction = True

            if txin['type'] in ['p2wpkh-p2sh', 'p2wsh-p2sh']:
                if not self.get_client_electrum().supports_segwit():
                    self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT)
                segwitTransaction = True

            if txin['type'] in ['p2wpkh', 'p2wsh']:
                if not self.get_client_electrum().supports_native_segwit():
                    self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT)
                segwitTransaction = True

            pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
            for i, x_pubkey in enumerate(x_pubkeys):
                if x_pubkey in derivations:
                    signingPos = i
                    s = derivations.get(x_pubkey)
                    hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1])
                    break
            else:
                self.give_error("No matching x_key for sign_transaction") # should never happen

            redeemScript = Transaction.get_preimage_script(txin)
            txin_prev_tx = txin.get('prev_tx')
            if txin_prev_tx is None and not Transaction.is_segwit_input(txin):
                raise UserFacingException(_('Offline signing with {} is not supported for legacy inputs.').format(self.device))
            txin_prev_tx_raw = txin_prev_tx.raw if txin_prev_tx else None
            inputs.append([txin_prev_tx_raw,
                           txin['prevout_n'],
                           redeemScript,
                           txin['prevout_hash'],
                           signingPos,
                           txin.get('sequence', 0xffffffff - 1),
                           txin.get('value')])
            inputsPaths.append(hwAddress)
            pubKeys.append(pubkeys)

        # Sanity check
        if p2shTransaction:
            for txin in tx.inputs():
                if txin['type'] != 'p2sh':
                    self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen

        txOutput = var_int(len(tx.outputs()))
        for o in tx.outputs():
            output_type, addr, amount = o.type, o.address, o.value
            txOutput += int_to_hex(amount, 8)
            script = tx.pay_script(output_type, addr)
            txOutput += var_int(len(script)//2)
            txOutput += script
        txOutput = bfh(txOutput)

        # Recognize outputs
        # - only one output and one change is authorized (for hw.1 and nano)
        # - at most one output can bypass confirmation (~change) (for all)
        if not p2shTransaction:
            if not self.get_client_electrum().supports_multi_output():
                if len(tx.outputs()) > 2:
                    self.give_error("Transaction with more than 2 outputs not supported")
            has_change = False
            any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
            for o in tx.outputs():
                assert o.type == TYPE_ADDRESS
                info = tx.output_info.get(o.address)
                if (info is not None) and len(tx.outputs()) > 1 \
                        and not has_change:
                    index = info.address_index
                    # prioritise hiding outputs on the 'change' branch from user
                    # because no more than one change address allowed
                    if info.is_change == any_output_on_change_branch:
                        changePath = self.get_derivation()[2:] + "/%d/%d"%index
                        has_change = True
                    else:
                        output = o.address
                else:
                    output = o.address

        self.handler.show_message(_("Confirm Transaction on your Ledger device..."))
        try:
            # Get trusted inputs from the original transactions
            for utxo in inputs:
                sequence = int_to_hex(utxo[5], 4)
                if segwitTransaction:
                    tmp = bfh(utxo[3])[::-1]
                    tmp += bfh(int_to_hex(utxo[1], 4))
                    tmp += bfh(int_to_hex(utxo[6], 8))  # txin['value']
                    chipInputs.append({'value' : tmp, 'witness' : True, 'sequence' : sequence})
                    redeemScripts.append(bfh(utxo[2]))
                elif not p2shTransaction:
                    txtmp = bitcoinTransaction(bfh(utxo[0]))
                    trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1])
                    trustedInput['sequence'] = sequence
                    chipInputs.append(trustedInput)
                    redeemScripts.append(txtmp.outputs[utxo[1]].script)
                else:
                    tmp = bfh(utxo[3])[::-1]
                    tmp += bfh(int_to_hex(utxo[1], 4))
                    chipInputs.append({'value' : tmp, 'sequence' : sequence})
                    redeemScripts.append(bfh(utxo[2]))

            # Sign all inputs
            firstTransaction = True
            inputIndex = 0
            rawTx = tx.serialize_to_network()
            self.get_client().enableAlternate2fa(False)
            if segwitTransaction:
                self.get_client().startUntrustedTransaction(True, inputIndex,
                                                            chipInputs, redeemScripts[inputIndex], version=tx.version)
                # we don't set meaningful outputAddress, amount and fees
                # as we only care about the alternateEncoding==True branch
                outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx))
                outputData['outputData'] = txOutput
                if outputData['confirmationNeeded']:
                    outputData['address'] = output
                    self.handler.finished()
                    pin = self.handler.get_auth( outputData ) # does the authenticate dialog and returns pin
                    if not pin:
                        raise UserWarning()
                    self.handler.show_message(_("Confirmed. Signing Transaction..."))
                while inputIndex < len(inputs):
                    singleInput = [ chipInputs[inputIndex] ]
                    self.get_client().startUntrustedTransaction(False, 0,
                                                            singleInput, redeemScripts[inputIndex], version=tx.version)
                    inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime)
                    inputSignature[0] = 0x30 # force for 1.4.9+
                    signatures.append(inputSignature)
                    inputIndex = inputIndex + 1
            else:
                while inputIndex < len(inputs):
                    self.get_client().startUntrustedTransaction(firstTransaction, inputIndex,
                                                                chipInputs, redeemScripts[inputIndex], version=tx.version)
                    # we don't set meaningful outputAddress, amount and fees
                    # as we only care about the alternateEncoding==True branch
                    outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx))
                    outputData['outputData'] = txOutput
                    if outputData['confirmationNeeded']:
                        outputData['address'] = output
                        self.handler.finished()
                        pin = self.handler.get_auth( outputData ) # does the authenticate dialog and returns pin
                        if not pin:
                            raise UserWarning()
                        self.handler.show_message(_("Confirmed. Signing Transaction..."))
                    else:
                        # Sign input with the provided PIN
                        inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime)
                        inputSignature[0] = 0x30 # force for 1.4.9+
                        signatures.append(inputSignature)
                        inputIndex = inputIndex + 1
                    firstTransaction = False
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BTChipException as e:
            if e.sw in (0x6985, 0x6d00):  # cancelled by user
                return
            elif e.sw == 0x6982:
                raise  # pin lock. decorator will catch it
            else:
                self.logger.exception('')
                self.give_error(e, True)
        except BaseException as e:
            self.logger.exception('')
            self.give_error(e, True)
        finally:
            self.handler.finished()

        for i, txin in enumerate(tx.inputs()):
            signingPos = inputs[i][4]
            tx.add_signature_to_txin(i, signingPos, bh2u(signatures[i]))
        tx.raw = tx.serialize()
コード例 #27
0
 def test_new_onion_packet(self):
     # test vector from bolt-04
     payment_path_pubkeys = [
         bfh('02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619'
             ),
         bfh('0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c'
             ),
         bfh('027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007'
             ),
         bfh('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991'
             ),
         bfh('02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145'
             ),
     ]
     session_key = bfh(
         '4141414141414141414141414141414141414141414141414141414141414141')
     associated_data = bfh(
         '4242424242424242424242424242424242424242424242424242424242424242')
     hops_data = [
         OnionHopsDataSingle(
             OnionPerHop(bfh('0000000000000000'), bfh('0000000000000000'),
                         bfh('00000000'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0101010101010101'), bfh('0000000000000001'),
                         bfh('00000001'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0202020202020202'), bfh('0000000000000002'),
                         bfh('00000002'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0303030303030303'), bfh('0000000000000003'),
                         bfh('00000003'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0404040404040404'), bfh('0000000000000004'),
                         bfh('00000004'))),
     ]
     packet = new_onion_packet(payment_path_pubkeys, session_key, hops_data,
                               associated_data)
     self.assertEqual(
         bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a71da571226458c510bbadd1276f045c21c520a07d35da256ef75b4367962437b0dd10f7d61ab590531cf08000178a333a347f8b4072e216400406bdf3bf038659793a86cae5f52d32f3438527b47a1cfc54285a8afec3a4c9f3323db0c946f5d4cb2ce721caad69320c3a469a202f3e468c67eaf7a7cda226d0fd32f7b48084dca885d15222e60826d5d971f64172d98e0760154400958f00e86697aa1aa9d41bee8119a1ec866abe044a9ad635778ba61fc0776dc832b39451bd5d35072d2269cf9b040d6ba38b54ec35f81d7fc67678c3be47274f3c4cc472aff005c3469eb3bc140769ed4c7f0218ff8c6c7dd7221d189c65b3b9aaa71a01484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f917265f21f9190c70217774a6fbaaa7d63ad64199f4664813b955cff954949076dcf'
             ), packet.to_bytes())
コード例 #28
0
 def test_process_onion_packet(self):
     # this test is not from bolt-04, but is based on the one there;
     # except here we have the privkeys for these pubkeys
     payment_path_pubkeys = [
         bfh('03d75c0ee70f68d73d7d13aeb6261d8ace11416800860c7e59407afe4e2e2d42bb'
             ),
         bfh('03960a0b830c7b8e76de745b819f252c62508346196b916f5e813cdb0773283cce'
             ),
         bfh('0385620e0a571cbc3552620f8bf1bdcdab2d1a4a59c36fa10b8249114ccbdda40d'
             ),
         bfh('02ee242cf6c38b7285f0152c33804ff777f5c51fd352ca8132e845e2cf23b3d8ba'
             ),
         bfh('025c585fd2e174bf8245b2b4a119e52a417688904228643ea3edaa1728bf2a258e'
             ),
     ]
     payment_path_privkeys = [
         bfh('3463a278617b3dd83f79bda7f97673f12609c54386e1f0d2b67b1c6354fda14e'
             ),
         bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d'
             ),
         bfh('c7ce8c1462c311eec24dff9e2532ac6241e50ae57e7d1833af21942136972f23'
             ),
         bfh('3d885f374d79a5e777459b083f7818cdc9493e5c4994ac9c7b843de8b70be661'
             ),
         bfh('dd72ab44729527b7942e195e7a835e7c71f9c0ff61844eb21274d9c26166a8f8'
             ),
     ]
     session_key = bfh(
         '4141414141414141414141414141414141414141414141414141414141414141')
     associated_data = bfh(
         '4242424242424242424242424242424242424242424242424242424242424242')
     hops_data = [
         OnionHopsDataSingle(
             OnionPerHop(bfh('0000000000000000'), bfh('0000000000000000'),
                         bfh('00000000'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0101010101010101'), bfh('0000000000000001'),
                         bfh('00000001'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0202020202020202'), bfh('0000000000000002'),
                         bfh('00000002'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0303030303030303'), bfh('0000000000000003'),
                         bfh('00000003'))),
         OnionHopsDataSingle(
             OnionPerHop(bfh('0404040404040404'), bfh('0000000000000004'),
                         bfh('00000004'))),
     ]
     packet = new_onion_packet(payment_path_pubkeys, session_key, hops_data,
                               associated_data)
     self.assertEqual(
         bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f28368661954176cd9869da33d713aa219fcef1e5c806fef11e696bcc66844de8271c27974a0fd57c2dbcb2c6dd4e8ef35d96db28d5a0e49b6ab3d6de31af65950723b8cddc108390bebf8d149002e31bdc283056477ba27c8054c248ad7306de31663a7c99ec659da15d0f6fbc7e1687485b39e9be0ec3b70164cb3618a9b546317e7c2d62ae9f0f840704535729262d30c6132d1b390f073edec8fa057176c6268b6ad06a82ff0d16d4c662194873e8b4ecf46eb2c9d4d58d2ee2021adb19840605ac5afd8bd942dd71e8244c83e28b2ed5a3b09e9e7df5c8c747e5765ba366a4f7407a6c6b0a32f74bc5e428f7fa4c3cf70e13ed91563177d94190d5149aa4b9c96d00e40d2ac35ab9c4a621ce0f6f5df7d64a9c8d435db19de192d9db522c7f7b4e201fc1b61a9bd3efd062ae24455d463818b01e2756c7d0691bc3ac4c017be34c9a8b2913bb1b937e31e0ae40f650a7cd820bcb4996825b1cbad1ff7ccc2b513b1104524c34f6573e1b59201c005a632ee5dccd3711a32e3ba1ff00fcffbe636e4b3a84bbe491b836a57ccec138b8cc2ec733846904d872f305d538d51db8e56232ec6e07877075328874cb7b09c7e799100a9ff085dead253886b174fc408a0ea7b48bce2c5d8992285011960af088f7e006ef60089d46ac9aa15acfac6c87c3cf6904764dd785419292fbafa9cca09c8ade24a6cd63f12d1cfc83fa35cf2f1cf503c39cbf78293f06c68a3cece7177169cd872bb49bf69d933a27a887dd9daefa9239fca9f0c3e309ec61d9df947211da98cf11a6e0fb77252629cdf9f2226dd69ca73fa51be4df224592f8d471b69a1aebbdaa2f3a798b3581253d97feb0a12e6606043ca0fc5efc0f49b8061d6796eff31cd8638499e2f25ffb96eec32837438ed7ebebbe587886648f63e35d80f41869f4c308f2e6970bd65fead5e8544e3239a6acc9d996b08d1546455bcafbe88ed3ed547714841946fe2e77180e4d7bf1452414e4b1745a7897184a2c4cbc3ac46f83342a55a48e29dc8f17cf595dd28f51e297ba89fd25ed0dbd1c0081a810beaab09758a36fbfd16fbdc3daa9fe05c8a73195f244ef2743a5df761f01ee6e693eb6c7f1a7834fab3671391e5ddebf611e119a2ae4456e2cee7a6d4f27a2246cdb1f8ef35f0b3d7044b3799d8d0ed0a6470557fd807c065d6d83acba07e96e10770ada8c0b4d4921522944188d5f30086a6ee0a4795331273f32beaaa43363fc58208a257e5c5c434c7325b583642219d81c7d67b908d5263b42ac1991edc69a777da60f38eff138c844af9e549374e8b29b166211bfded24587a29394e33828b784da7e7b62ab7e49ea2693fcdd17fa96186a5ef11ef1a8adffa50f93a3119e95e6c09014f3e3b0709183fa08a826ced6deb4608b7d986ebbcf99ad58e25451d4d9d38d0059734d8501467b97182cd11e0c07c91ca50f61cc31255a3147ade654976a5989097281892aafd8df595c63bd14f1e03f5955a9398d2dd6368bbcae833ae1cc2df31eb0980b4817dfd130020ffb275743fcc01df40e3ecda1c5988e8e1bde965353b0b1bf34ea05f095000c45b6249618d275905a24d3eb58c600aeab4fb552fbf1ccdb2a5c80ace220310f89829d7e53f78c126037b6d8d500220c7a118d9621b4d6bd5379edd7e24bcf540e87aba6b88862db16fa4ee00b009fda80577be67ab94910fd8a7807dfe4ebe66b8fdcd040aa2dc17ec22639298be56b2a2c9d8940647b75f2f6d81746df16e1cb2f05e23397a8c63baea0803441ff4b7d517ff172980a056726235e2f6af85e8aa9b91ba85f14532272d6170df3166b91169dc09d4f4a251610f57ff0885a93364cfaf650bdf436c89795efed5ca934bc7ffc0a4'
             ), packet.to_bytes())
     for i, privkey in enumerate(payment_path_privkeys):
         processed_packet = process_onion_packet(packet, associated_data,
                                                 privkey)
         self.assertEqual(hops_data[i].per_hop.to_bytes(),
                          processed_packet.hop_data.per_hop.to_bytes())
         packet = processed_packet.next_packet
コード例 #29
0
    def test_find_path_for_payment(self):
        class fake_network:
            config = self.config
            asyncio_loop = asyncio.get_event_loop()
            trigger_callback = lambda *args: None
            register_callback = lambda *args: None
            interface = None

        fake_network.channel_db = lnrouter.ChannelDB(fake_network())
        cdb = fake_network.channel_db
        path_finder = lnrouter.LNPathFinder(cdb)
        self.assertEqual(cdb.num_channels, 0)
        cdb.add_channel_announcement(
            {
                'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                'node_id_2': b'\x02cccccccccccccccccccccccccccccccc',
                'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                'bitcoin_key_2': b'\x02cccccccccccccccccccccccccccccccc',
                'short_channel_id': bfh('0000000000000001'),
                'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
                'len': b'\x00\x00',
                'features': b''
            },
            trusted=True)
        self.assertEqual(cdb.num_channels, 1)
        cdb.add_channel_announcement(
            {
                'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
                'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
                'short_channel_id': bfh('0000000000000002'),
                'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
                'len': b'\x00\x00',
                'features': b''
            },
            trusted=True)
        cdb.add_channel_announcement(
            {
                'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
                'node_id_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
                'bitcoin_key_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                'short_channel_id': bfh('0000000000000003'),
                'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
                'len': b'\x00\x00',
                'features': b''
            },
            trusted=True)
        cdb.add_channel_announcement(
            {
                'node_id_1': b'\x02cccccccccccccccccccccccccccccccc',
                'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
                'bitcoin_key_1': b'\x02cccccccccccccccccccccccccccccccc',
                'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
                'short_channel_id': bfh('0000000000000004'),
                'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
                'len': b'\x00\x00',
                'features': b''
            },
            trusted=True)
        cdb.add_channel_announcement(
            {
                'node_id_1': b'\x02dddddddddddddddddddddddddddddddd',
                'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
                'bitcoin_key_1': b'\x02dddddddddddddddddddddddddddddddd',
                'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
                'short_channel_id': bfh('0000000000000005'),
                'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
                'len': b'\x00\x00',
                'features': b''
            },
            trusted=True)
        cdb.add_channel_announcement(
            {
                'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
                'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
                'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
                'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
                'short_channel_id': bfh('0000000000000006'),
                'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
                'len': b'\x00\x00',
                'features': b''
            },
            trusted=True)
        o = lambda i: i.to_bytes(8, "big")
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000001'),
            'message_flags': b'\x00',
            'channel_flags': b'\x00',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000001'),
            'message_flags': b'\x00',
            'channel_flags': b'\x01',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000002'),
            'message_flags': b'\x00',
            'channel_flags': b'\x00',
            'cltv_expiry_delta': o(99),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000002'),
            'message_flags': b'\x00',
            'channel_flags': b'\x01',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000003'),
            'message_flags': b'\x00',
            'channel_flags': b'\x01',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000003'),
            'message_flags': b'\x00',
            'channel_flags': b'\x00',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000004'),
            'message_flags': b'\x00',
            'channel_flags': b'\x01',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000004'),
            'message_flags': b'\x00',
            'channel_flags': b'\x00',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000005'),
            'message_flags': b'\x00',
            'channel_flags': b'\x01',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000005'),
            'message_flags': b'\x00',
            'channel_flags': b'\x00',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(999),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000006'),
            'message_flags': b'\x00',
            'channel_flags': b'\x00',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(99999999),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        cdb.add_channel_update({
            'short_channel_id': bfh('0000000000000006'),
            'message_flags': b'\x00',
            'channel_flags': b'\x01',
            'cltv_expiry_delta': o(10),
            'htlc_minimum_msat': o(250),
            'fee_base_msat': o(100),
            'fee_proportional_millionths': o(150),
            'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
            'timestamp': b'\x00\x00\x00\x00'
        })
        path = path_finder.find_path_for_payment(
            b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
            b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 100000)
        self.assertEqual([(b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
                           b'\x00\x00\x00\x00\x00\x00\x00\x03'),
                          (b'\x02cccccccccccccccccccccccccccccccc',
                           b'\x00\x00\x00\x00\x00\x00\x00\x01'),
                          (b'\x02dddddddddddddddddddddddddddddddd',
                           b'\x00\x00\x00\x00\x00\x00\x00\x04'),
                          (b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
                           b'\x00\x00\x00\x00\x00\x00\x00\x05')], path)
        start_node = b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
        route = path_finder.create_route_from_path(path, start_node)
        self.assertEqual(route[0].node_id, start_node)
        self.assertEqual(route[0].short_channel_id, bfh('0000000000000003'))

        # need to duplicate tear_down here, as we also need to wait for the sql thread to stop
        self.asyncio_loop.call_soon_threadsafe(self._stop_loop.set_result, 1)
        self._loop_thread.join(timeout=1)
        cdb.sql_thread.join(timeout=1)
コード例 #30
0
 def test_add_number_to_script(self):
     # https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#numbers
     self.assertEqual(add_number_to_script(0), bytes([opcodes.OP_0]))
     self.assertEqual(add_number_to_script(7), bytes([opcodes.OP_7]))
     self.assertEqual(add_number_to_script(16), bytes([opcodes.OP_16]))
     self.assertEqual(add_number_to_script(-1), bytes([opcodes.OP_1NEGATE]))
     self.assertEqual(add_number_to_script(-127), bfh('01ff'))
     self.assertEqual(add_number_to_script(-2), bfh('0182'))
     self.assertEqual(add_number_to_script(17), bfh('0111'))
     self.assertEqual(add_number_to_script(127), bfh('017f'))
     self.assertEqual(add_number_to_script(-32767), bfh('02ffff'))
     self.assertEqual(add_number_to_script(-128), bfh('028080'))
     self.assertEqual(add_number_to_script(128), bfh('028000'))
     self.assertEqual(add_number_to_script(32767), bfh('02ff7f'))
     self.assertEqual(add_number_to_script(-8388607), bfh('03ffffff'))
     self.assertEqual(add_number_to_script(-32768), bfh('03008080'))
     self.assertEqual(add_number_to_script(32768), bfh('03008000'))
     self.assertEqual(add_number_to_script(8388607), bfh('03ffff7f'))
     self.assertEqual(add_number_to_script(-2147483647), bfh('04ffffffff'))
     self.assertEqual(add_number_to_script(-8388608), bfh('0400008080'))
     self.assertEqual(add_number_to_script(8388608), bfh('0400008000'))
     self.assertEqual(add_number_to_script(2147483647), bfh('04ffffff7f'))