コード例 #1
0
def get_txid(tx):
    try:
        t = Transaction.from_string(tx)
    except:
        t = LTransaction.from_string(tx)
    for inp in t.vin:
        inp.scriptSig = Script(b"")
    return t.txid().hex()
コード例 #2
0
def test_understandTransaction():
    mytx = Transaction.from_string(tx1_confirmed["hex"])
    assert mytx.version == 2
    assert mytx.locktime == 415
    assert type(mytx.vin[0]) == TransactionInput
    assert (hexlify(
        mytx.vin[0].txid
    ) == b"c7c9dd852fa9cbe72b2f6e3b2eeba1a2b47dc4422b3719a55381be8010d7993f")
    assert mytx.vout[0].value == 1999999890
    assert (hexlify(mytx.txid(
    )) == b"42f5c9e826e52cde883cde7a6c7b768db302e0b8b32fc52db75ad3c5711b4a9e")
コード例 #3
0
    def __init__(self, rpc, addresses, **kwargs):
        self.rpc = rpc
        self._addresses = addresses
        # copy
        kwargs = dict(**kwargs)
        # replace with None or convert
        for i, k in enumerate(self.columns):
            v = kwargs.get(k, "")
            kwargs[k] = None if v in ["", None] else self.type_converter[i](v)

        super().__init__(**kwargs)
        # parse transaction
        self.tx = (None if not self["hex"] else Transaction.parse(
            bytes.fromhex(self["hex"])))
コード例 #4
0
def convert_rawtransaction_to_psbt(wallet_rpc, rawtransaction) -> str:
    """
    Converts a raw transaction in HEX format into a PSBT in b64 format
    """
    tx = Transaction.from_string(rawtransaction)
    psbt = PSBT(tx)  # this empties the signatures
    psbt = wallet_rpc.walletprocesspsbt(str(psbt),
                                        False).get("psbt", str(psbt))
    psbt = PSBT.from_string(psbt)  # we need the class object again
    # Recover signatures (witness or scriptsig) if available in raw tx
    for vin, psbtin in zip(tx.vin, psbt.inputs):
        if vin.witness:
            psbtin.final_scriptwitness = vin.witness
        if vin.script_sig:
            psbtin.final_scriptsig = vin.script_sig
    b64_psbt = str(psbt)
    return b64_psbt
コード例 #5
0
def decoderawtransaction(hextx, chain="main"):
    raw = bytes.fromhex(hextx)
    tx = Transaction.parse(raw)
    txhash = sha256(sha256(raw).digest()).digest()[::-1].hex()
    txsize = len(raw)
    if tx.is_segwit:
        # tx size - flag - marker - witness
        non_witness_size = (
            txsize - 2 - sum([len(inp.witness.serialize()) for inp in tx.vin]))
        witness_size = txsize - non_witness_size
        weight = non_witness_size * 4 + witness_size
        vsize = math.ceil(weight / 4)
    else:
        vsize = txsize
        weight = txsize * 4
    result = {
        "txid":
        tx.txid().hex(),
        "hash":
        txhash,
        "version":
        tx.version,
        "size":
        txsize,
        "vsize":
        vsize,
        "weight":
        weight,
        "locktime":
        tx.locktime,
        "vin": [decoderawinput(vin) for vin in tx.vin],
        "vout": [
            dict(decoderawoutput(vout, chain), n=i)
            for i, vout in enumerate(tx.vout)
        ],
    }
    return result
コード例 #6
0
def main():
    # all from the same private key
    prv = ec.PrivateKey.from_wif(
        "L2e5y14ZD3U1J7Yr62t331RtYe2hRW2TBBP8qNQHB8nSPBNgt6dM")
    pub = prv.get_public_key()
    inputs = [
        # legacy
        {
            "txid":
            unhexlify(
                "7f0c7538e898bbe5531fa47d4057b52c914ec45e20ae1a5572ea1005a8ba50f8"
            ),
            "vout":
            0,
            "value":
            int(1e8),
            "script":
            script.p2pkh(pub),
        },
        # native segwit
        {
            "txid":
            unhexlify(
                "f51e6fc2392558a70ae970e93538f368828ad2800a7370f372a652de463429fc"
            ),
            "vout":
            0,
            "value":
            int(2e8),
            "script":
            script.p2wpkh(pub),
        },
        # nested segwit
        {
            "txid":
            unhexlify(
                "2e4cb680ed008b6e529c4c83f00d55326a2e68b48ddf11267e3f5323006966a6"
            ),
            "vout":
            1,
            "value":
            int(3e8),
            "script":
            script.p2sh(script.p2wpkh(pub)),
            "redeem":
            script.p2wpkh(pub),
        },
    ]
    # sending back almost the same amount
    vin = [TransactionInput(inp["txid"], inp["vout"]) for inp in inputs]
    vout = [
        TransactionOutput(inp["value"] - 1500, inp["script"]) for inp in inputs
    ]
    tx = Transaction(vin=vin, vout=vout)
    print("Unsigned transaction:")
    print(hexlify(tx.serialize()).decode("utf-8"))

    for i in range(len(inputs)):
        inp = inputs[i]
        script_type = inp["script"].script_type()
        # legacy input
        if script_type == "p2pkh":
            h = tx.sighash_legacy(i, inp["script"])
            sig = prv.sign(h)
            tx.vin[i].script_sig = script.script_sig_p2pkh(sig, pub)
        # native segwit
        elif script_type == "p2wpkh":
            sc = script.p2pkh_from_p2wpkh(inp["script"])
            h = tx.sighash_segwit(i, sc, inp["value"])
            sig = prv.sign(h)
            tx.vin[i].witness = script.witness_p2wpkh(sig, pub)
        # nested segwit
        elif script_type == "p2sh":
            if "redeem" in inp and inp["redeem"].script_type() == "p2wpkh":
                sc = script.p2pkh_from_p2wpkh(inp["redeem"])
                h = tx.sighash_segwit(i, sc, inp["value"])
                sig = prv.sign(h)
                tx.vin[i].script_sig = script.script_sig_p2sh(inp["redeem"])
                tx.vin[i].witness = script.witness_p2wpkh(sig, pub)
            else:
                raise NotImplementedError("Script type is not supported")
        else:
            raise NotImplementedError("Script type is not supported")

    print("Signed transaction:")
    print(hexlify(tx.serialize()).decode("utf-8"))
コード例 #7
0
    def test_miniscript(self):
        # and(pk(A),after(100)) -> and_v(v:pk(A),after(100))
        path = "49h/1h/0h/2h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        desc = f"wsh(and_v(v:pk([{fgp}/{path}]{xpub}"+"/{0,1}/*),after(10)))"
        res = sim.query("addwallet mini&"+desc, [True])

        wname = wallet_prefix+"_mini"
        d = Descriptor.from_string(desc)

        addr = d.derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        sc = d.derive(5).witness_script().data.hex()
        res = sim.query(f"showaddr wsh m/{path}/0/5 {sc}", [True])
        self.assertEqual(res.decode(), addr)

        d1 = d.derive(2, branch_index=0)
        d2 = d.derive(3, branch_index=1)
        # recv addr 2
        addr1 = d1.address(NETWORKS['regtest'])
        # change addr 3
        addr2 = d2.address(NETWORKS['regtest'])
        res = sim.query(f"bitcoin:{addr1}?index=2", [True])
        # check it's found
        self.assertFalse(b"Can't find wallet" in res)

        rpc.createwallet(wname, True, True)
        w = rpc.wallet(wname)
        res = w.importmulti([{
                "scriptPubKey": {"address": addr1},#d1.script_pubkey().data.hex(),
                # "witnessscript": d1.witness_script().data.hex(),
                # "pubkeys": [k.sec().hex() for k in d1.keys],
                "internal": False,
                "timestamp": "now",
                "watchonly": True,
            },{
                "scriptPubKey": {"address": addr2},#d2.script_pubkey().data.hex(),
                # "witnessscript": d2.witness_script().data.hex(),
                # "pubkeys": [k.sec().hex() for k in d2.keys],
                "internal": True,
                "timestamp": "now",
                "watchonly": True,
            }],{"rescan": False})
        self.assertTrue(all([k["success"] for k in res]))
        wdefault.sendtoaddress(addr1, 0.1)
        rpc.mine()
        unspent = w.listunspent()
        self.assertTrue(len(unspent) > 0)
        unspent = [{"txid": u["txid"], "vout": u["vout"]} for u in unspent[:1]]
        tx = w.createrawtransaction(unspent, [{wdefault.getnewaddress(): 0.002},{addr2: 0.09799}])
        psbt = PSBT.from_base64(w.converttopsbt(tx))
        # locktime magic :)
        psbt.tx.locktime = 11
        psbt.tx.vin[0].sequence = 10
        # fillinig psbt with data
        psbt.inputs[0].witness_script = d1.witness_script()
        pub = ec.PublicKey.parse(d1.keys[0].sec())
        psbt.inputs[0].bip32_derivations[pub] = DerivationPath(bytes.fromhex(fgp), bip32.parse_path(f"m/{path}")+[0,2])
        tx = w.gettransaction(unspent[0]["txid"])
        t = Transaction.from_string(tx["hex"])
        psbt.inputs[0].witness_utxo = t.vout[unspent[0]["vout"]]

        psbt.outputs[1].witness_script = d2.witness_script()
        pub2 = ec.PublicKey.parse(d2.keys[0].sec())
        psbt.outputs[1].bip32_derivations[pub2] = DerivationPath(bytes.fromhex(fgp), bip32.parse_path(f"m/{path}")+[1,3])

        unsigned = psbt.to_base64()
        # confirm signing
        signed = sim.query("sign "+unsigned, [True])
        stx = PSBT.from_base64(signed.decode())
        # signed tx
        t = psbt.tx
        # print(stx)
        t.vin[0].witness = Witness([stx.inputs[0].partial_sigs[pub], psbt.inputs[0].witness_script.data])
        # broadcast
        with self.assertRaises(Exception):
            res = rpc.sendrawtransaction(t.serialize().hex())
        rpc.mine(11)
        res = rpc.sendrawtransaction(t.serialize().hex())
        rpc.mine()
        self.assertEqual(len(bytes.fromhex(res)), 32)
コード例 #8
0
    per_input_size += sigs_size

# Now when we have all utxos and size estimates
# we can construct a transaction

# Very stupid coin selection:
# we just go through utxos and add them until we have enough for destination + fee

spending_amount = 0
fee = fee_rate * no_input_size
inputs = []

for utxo in utxos:
    # get full prev tx if we are using legacy (or Trezor)
    if not d.is_segwit:
        utxo["non_witness_utxo"] = Transaction.from_string(
            s.get(f"{API}/tx/{utxo['txid']}/hex").text)
    inputs.append(utxo)
    spending_amount += utxo["value"]
    fee += per_input_size * fee_rate
    if spending_amount >= AMOUNT + fee:
        break

if spending_amount < AMOUNT + fee:
    raise RuntimeError("Not enough funds")
# round fee to satoshis
fee = int(fee) + 1

vin = [
    TransactionInput(bytes.fromhex(inp["txid"]), inp["vout"]) for inp in inputs
]
vout = [TransactionOutput(AMOUNT, script.address_to_scriptpubkey(DESTINATION))]