def test_make_raw_transaction():

    tx = make_raw_transaction("bitcoin", [], [], Locktime(0))
    assert isinstance(tx, MutableTransaction)

    tx = make_raw_transaction("peercoin", [], [], Locktime(300000))
    assert isinstance(tx, MutableTransaction)
示例#2
0
    def _get_unsigned_txn(self):

        # outputs_amounts is copied so any instance can be modified with change_fee,
        # and will still function correctly, i.e the change address won't already
        # be in the self._outputs_amounts dict
        self._modified_outputs_amounts = self.outputs_amounts.copy()

        # adding change address to outputs, if there is leftover balance that isn't dust
        if self._change_amount > 0:
            self._modified_outputs_amounts[self.change_address] = self._change_amount

        outputs = []
        for i, (addr, amount) in enumerate(self._modified_outputs_amounts.items()):

            outputs.append(TxOut(
                value=amount,
                n=i,
                script_pubkey=self.get_script_pubkey(addr)
            ))

        inputs = []

        for t in self._specific_utxo_data:

            # build inputs using the UTXO data in self._specific_utxo_data,
            # script_sig is empty as the transaction will be signed later
            inputs.append(

                TxIn(txid=t[0],
                     txout=t[1],
                     script_sig=ScriptSig.empty(),
                     sequence=Sequence.max(),
                     witness=Witness([StackData.zero()])) if self.is_segwit else None,
            )

        if self.is_segwit:

            transaction = MutableSegWitTransaction(
                version=TX_VERSION,
                ins=inputs,
                outs=outputs,
                locktime=Locktime(self.locktime),
            )

        else:

            transaction = MutableTransaction(
                version=TX_VERSION,
                ins=inputs,
                outs=outputs,
                locktime=Locktime(self.locktime)
            )

        return transaction
示例#3
0
def test_sign_transaction():

    network_params = net_query('tppc')
    provider = Explorer(network='tppc')
    key = Kutil(network='tppc',
                privkey=bytearray.fromhex('9e321f5379c2d1c4327c12227e1226a7c2e08342d88431dcbb0063e1e715a36c')
                )
    dest_address = 'mwn75Gavp6Y1tJxca53HeCj5zzERqWagr6'

    unspent = provider.select_inputs(key.address, 0.63)  # 0.69
    output = tx_output(network='tppc',
                       value=Decimal(0.1),
                       n=0, script=p2pkh_script(network='tppc',
                                                address=dest_address)
                       )

    unsigned = MutableTransaction(
        version=1,
        ins=unspent['utxos'],
        outs=[output],
        locktime=Locktime(0),
        network=network_params,
        timestamp=int(time.time()),
    )

    parent_outputs = [find_parent_outputs(provider, i) for i in unsigned.ins]
    solver = P2pkhSolver(key._private_key)

    signed = unsigned.spend(parent_outputs,
                            [solver for i in parent_outputs])

    assert isinstance(signed, Transaction)
示例#4
0
def test_sign_transaction():

    network_params = net_query('tppc')

    provider = Cryptoid(network='tppc')
    key = pa.Kutil(
        network='tppc',
        privkey=bytearray.fromhex(
            '9e321f5379c2d1c4327c12227e1226a7c2e08342d88431dcbb0063e1e715a36c')
    )
    dest_address = pa.Kutil(network='tppc').address
    unspent = provider.select_inputs(key.address, 1)

    output = tx_output(network='tppc',
                       value=Decimal(0.1),
                       n=0,
                       script=p2pkh_script(network='tppc',
                                           address=dest_address))

    unsigned = MutableTransaction(
        version=1,
        ins=unspent['utxos'],
        outs=[output],
        locktime=Locktime(0),
        network=network_params,
        timestamp=int(time.time()),
    )

    assert isinstance(sign_transaction(provider, unsigned, key), Transaction)
示例#5
0
    def build_transaction(self, wallet, htlc, amount, locktime=0):
        """
        Build bitcoin fund transaction.

        :param wallet: bitcoin sender wallet.
        :type wallet: bitcoin.wallet.Wallet
        :param htlc: bitcoin hash time lock contract (HTLC).
        :type htlc: bitcoin.htlc.HTLC
        :param amount: bitcoin amount to fund.
        :type amount: int
        :param locktime: bitcoin transaction lock time, defaults to 0.
        :type locktime: int
        :returns: FundTransaction -- bitcoin fund transaction instance.

        >>> from shuttle.providers.bitcoin.transaction import FundTransaction
        >>> fund_transaction = FundTransaction(network="testnet")
        >>> fund_transaction.build_transaction(sender_wallet, htlc, 10000)
        <shuttle.providers.bitcoin.transaction.FundTransaction object at 0x0409DAF0>
        """

        # Checking build transaction arguments instance
        if not isinstance(wallet, Wallet):
            raise TypeError(
                "invalid wallet instance, only takes bitcoin Wallet class")
        if not isinstance(htlc, HTLC):
            raise TypeError(
                "invalid htlc instance, only takes bitcoin HTLC class")
        if not isinstance(amount, int):
            raise TypeError("invalid amount instance, only takes integer type")
        # Setting wallet, htlc, amount and unspent
        self.wallet, self.htlc, self.amount = wallet, htlc, amount
        # Getting unspent transaction output
        self.unspent = self.wallet.unspent()
        # Setting previous transaction indexes
        self.previous_transaction_indexes = \
            self.get_previous_transaction_indexes(amount=self.amount)
        # Getting transaction inputs and amount
        inputs, amount = self.inputs(self.unspent,
                                     self.previous_transaction_indexes)
        # Calculating bitcoin fee
        self.fee = fee_calculator(len(inputs), 2)
        if amount < (self.amount + self.fee):
            raise BalanceError("insufficient spend utxos")
        # Building mutable bitcoin transaction
        self.transaction = MutableTransaction(
            version=self.version,
            ins=inputs,
            outs=[
                # Funding into hash time lock contract script hash
                TxOut(value=self.amount,
                      n=0,
                      script_pubkey=P2shScript.unhexlify(self.htlc.hash())),
                # Controlling amounts when we are funding on htlc script.
                TxOut(value=amount - (self.fee + self.amount),
                      n=1,
                      script_pubkey=P2pkhScript.unhexlify(self.wallet.p2pkh()))
            ],
            locktime=Locktime(locktime))
        return self
示例#6
0
def make_raw_transaction(inputs: list,
                         outputs: list,
                         locktime=Locktime(0),
                         timestamp: int = int(time()),
                         version=1):
    '''create raw transaction'''

    return MutableTransaction(version, timestamp, inputs, outputs, locktime)
示例#7
0
def min_locktime(locktimes):
    m = 0
    res = Locktime(0)
    for lock in locktimes:
        if m is 0 or lock.n < m:
            m = lock.n
            res = lock
    return res
示例#8
0
 def from_json(cls, tx_json, network=PeercoinMainnet):
     return cls(
         version=tx_json['version'],
         ins=[TxIn.from_json(txin_json) for txin_json in tx_json['vin']],
         outs=[TxOut.from_json(txout_json) for txout_json in tx_json['vout']],
         locktime=Locktime(tx_json['locktime']),
         txid=tx_json['txid'],
         network=network,
         timestamp=tx_json['time'],
     )
示例#9
0
def createContractTx(SigScript,
                     PubScript):  # Array of outputs . e.g see outs comment
    #    FundingWitness=SegWit_Witness(funding_sig(),funding_pubkey());

    # SigScript1 = Script.unhexlify('48304502210083e6e7507e838a190f0443441c0b62d2df94673887f4482e27e89ff415a90392022050575339c649b85c04bb410a00b62325c1b82c537135fa62fb34fae2c9a30b0b01210384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff')
    ContractTx = MutableSegWitTransaction(
        version=1,
        ins=SigScript,  #,witness=FundingWitness)],
        outs=
        PubScript,  #[TxOut(value=1,n=0,script_pubkey=FundingPubkey)], locktime=Locktime(0))
        locktime=Locktime(0))  #TODO Failing here .why do we need this ?
    return ContractTx
示例#10
0
def open_tx(committer, secret, commit_tx_hash):
    # 创建输入脚本
    p2pkh_solver = P2pkhSolver(committer.privk)
    hasklock_solver = HashlockSolver(secret.encode(), p2pkh_solver)
    if_solver = IfElseSolver(
        Branch.IF,  # branch selection
        hasklock_solver)
    # 创建输出脚本
    script = P2pkhScript(committer.pubk)

    # 获取commit交易
    to_spend_raw = get_raw_tx(commit_tx_hash, coin_symbol)
    to_spend = TransactionFactory.unhexlify(to_spend_raw)

    # 获取罚金数额
    penalty = int(float(to_spend.to_json()['vout'][0]['value']) * (10**8))

    # 估算挖矿费用
    print('estimating mining fee...')
    mining_fee_per_kb = get_mining_fee_per_kb(coin_symbol,
                                              committer.api_key,
                                              condidence='high')
    estimated_tx_size = cal_tx_size_in_byte(inputs_num=1, outputs_num=1)
    mining_fee = int(mining_fee_per_kb * (estimated_tx_size / 1000)) * 2

    # 创建交易
    unsigned = MutableTransaction(version=2,
                                  ins=[
                                      TxIn(txid=to_spend.txid,
                                           txout=0,
                                           script_sig=ScriptSig.empty(),
                                           sequence=Sequence.max())
                                  ],
                                  outs=[
                                      TxOut(value=penalty - mining_fee,
                                            n=0,
                                            script_pubkey=script),
                                  ],
                                  locktime=Locktime(0))

    # 修改交易
    signed = unsigned.spend([to_spend.outs[0]], [if_solver])

    # 广播交易
    print('open_tx_hex: ', signed.hexlify())
    msg = pushtx(coin_symbol=coin_symbol,
                 api_key=committer.api_key,
                 tx_hex=signed.hexlify())
    format_output(msg)

    return msg['tx']['hash']
def make_raw_transaction(
        inputs: list,
        outputs: list,
        locktime: Locktime = Locktime(0),
        timestamp: int = int(time()),
        version: int = 1,
) -> Transaction:
    '''create raw transaction'''

    return Transaction(version=version,
                       timestamp=timestamp,
                       ins=inputs,
                       outs=outputs,
                       locktime=locktime)
示例#12
0
文件: solver.py 项目: saloppe73/swap
    def solve(self, network: str = config["network"]) -> IfElseSolver:

        if self._path is None:
            self._path = config["bip44_path"].format(
                account=self._account,
                change=(1 if self._change else 0),
                address=self._address)

        return IfElseSolver(
            branch=Branch.ELSE,
            inner_solver=AbsoluteTimelockSolver(
                locktime=Locktime(n=self._endtime),
                inner_solver=P2pkhSolver(privk=PrivateKey.unhexlify(
                    hexa=Wallet(network=network).from_root_xprivate_key(
                        xprivate_key=self._xprivate_key, strict=self._strict).
                    from_path(path=self._path).private_key()))))
示例#13
0
def spendCb(fee, reward, objTx, outputs, cbSolver, dictIdToPub):
    """
    create a single coinbase spend
    :param fee: fee
    :param reward: block reward in sat
    :param objTx: coinbase tx
    :param outputs: lst of channels (copies from originals)
    :param cbSolver: solver
    :param bPubMiner: pub of the miner
    :return: tx that spends coinbase
    """
    outs = []
    totVal = 0
    chanIds = []
    for o in outputs:
        v = int(o.value)
        bPubN1 = dictIdToPub[str(o.node1.nodeid)]
        bPubN2 = dictIdToPub[str(o.node2.nodeid)]
        if bPubN1.compressed < bPubN2.compressed:  # lexicographical ordering
            multisig_script = MultisigScript(2, bPubN1, bPubN2, 2)
        else:
            multisig_script = MultisigScript(2, bPubN2, bPubN1, 2)
        p2wsh_multisig = P2wshV0Script(multisig_script)
        totVal += v
        outs += [TxOut(value=v, n=0, script_pubkey=p2wsh_multisig)]
        chanIds += [o.channelid]

    change = reward - totVal - fee
    outsWithChange = outs + [
        TxOut(value=change, n=0, script_pubkey=objTx.outs[0].script_pubkey)
    ]
    unsignedCb = MutableTransaction(version=1,
                                    ins=[
                                        TxIn(txid=objTx.txid,
                                             txout=0,
                                             script_sig=ScriptSig.empty(),
                                             sequence=Sequence.max())
                                    ],
                                    outs=outsWithChange,
                                    locktime=Locktime(0))
    cbTx = unsignedCb.spend([objTx.outs[0]], [cbSolver])
    return cbTx, (cbTx.txid, chanIds)
示例#14
0
文件: dlcF.py 项目: pewekar/dlc
def fundingTxn():
    Signer = ScriptSig.empty()
    outvalue = fundingInput_value(fundingTxIn, 0) - 400
    MultiSigTx = MutableSegWitTransaction(
        version=1,  #Publish to the Blockchain
        ins=[
            TxIn(txid=fundingTxIn_id,
                 txout=0,
                 script_sig=Signer,
                 sequence=Sequence.max())
        ],
        outs=[TxOut(value=outvalue, n=0, script_pubkey=FundingScript)
              ],  # todo must change this to access the contract script
        locktime=Locktime(0))

    MultiSigTxSigned = MultiSigTx.spend(
        [fundingTxIn.outs[0]],
        [funding_sig])  # ToDo Failing here - spend attribute not found
    print("funding tx signed ", MultiSigTxSigned.hexlify())
    #    return MultiSigTx,p2sh_solver,MultiSigTxSigned.outs[0]; # TODo when to Return Signed MultiSigTransaction
    return MultiSigTxSigned.txid, MultiSigTxSigned.outs[0]
示例#15
0
文件: dlcF.py 项目: pewekar/dlc
def sweepTx(MultiSigTx, MultiSigTxOutput, MultiSigTxSolver, to_pubkey,
            to_index, to_value):
    to_spend = MultiSigTx
    unsigned = MutableSegWitTransaction(
        version=1,
        ins=[
            TxIn(
                txid=to_spend,  #.txid,
                txout=to_index,
                script_sig=ScriptSig.empty(),
                sequence=Sequence.max())
        ],
        outs=[
            TxOut(value=to_value - txFee,
                  n=0,
                  script_pubkey=P2pkhScript(to_pubkey))
        ],  # todo make funding_pubkey a parameter. This must sweep back tp A & B
        locktime=Locktime(0))

    solver = MultiSigTxSolver
    signed = unsigned.spend(
        [MultiSigTxOutput],
        [solver])  #print ("Return tx signed ",signed.hexlify())
    return signed.hexlify()
示例#16
0
    def build_transaction(
            self,
            address: str,
            recipients: dict,
            unit: str = config["unit"],
            locktime: int = config["locktime"]) -> "NormalTransaction":
        """
        Build Bitcoin normal transaction.

        :param address: Bitcoin sender address.
        :type address: str
        :param recipients: Recipients Bitcoin address and amount.
        :type recipients: dict
        :param unit: Bitcoin unit, default to ``Satoshi``.
        :type unit: str
        :param locktime: Bitcoin transaction lock time, defaults to ``0``.
        :type locktime: int

        :returns: NormalTransaction -- Bitcoin normal transaction instance.

        >>> from swap.providers.bitcoin.transaction import NormalTransaction
        >>> normal_transaction: NormalTransaction = NormalTransaction(network="testnet")
        >>> normal_transaction.build_transaction(address="mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", recipients={"2N6kHwQy6Ph5EdKNgzGrcW2WhGHKGfmP5ae": 10000000}, locktime=0)
        <swap.providers.bitcoin.transaction.NormalTransaction object at 0x0409DAF0>
        """

        # Check parameter instances
        if not is_address(address, self._network):
            raise AddressError(
                f"Invalid Bitcoin sender '{address}' {self._network} address.")
        if unit not in ["BTC", "mBTC", "Satoshi"]:
            raise UnitError(
                "Invalid Bitcoin unit, choose only 'BTC', 'mBTC' or 'Satoshi' units."
            )

        self._address, outputs, self._amount = (address, [], (
            sum(recipients.values())
            if unit == "Satoshi" else amount_unit_converter(
                amount=sum(recipients.values()), unit_from=f"{unit}2Satoshi")))
        # Get Sender UTXO's
        self._utxos = get_utxos(address=self._address, network=self._network)
        # Outputs action
        for _address, _amount in recipients.items():
            if not is_address(_address, self._network):
                raise AddressError(
                    f"Invalid Bitcoin recipients '{_address}' {self._network} address."
                )
            outputs.append(
                TxOut(value=int(_amount),
                      n=len(outputs),
                      script_pubkey=get_address_hash(address=_address,
                                                     script=True)))
        # Get previous transaction indexes
        self._previous_transaction_indexes, max_amount = _get_previous_transaction_indexes(
            utxos=self._utxos,
            amount=self._amount,
            transaction_output=len(outputs))
        # Build transaction inputs
        inputs, amount = _build_inputs(
            utxos=self._utxos,
            previous_transaction_indexes=self._previous_transaction_indexes)
        # Calculate the fee
        self._fee = fee_calculator(len(inputs), len(outputs))

        if amount < self._amount:
            raise BalanceError("Insufficient spend UTXO's",
                               "you don't have enough amount.")
        elif amount < (self._amount + self._fee):
            raise BalanceError(
                f"You don't have enough amount to pay '{self._fee}' Satoshi fee",
                f"you can spend maximum '{amount - self._fee}' Satoshi amount."
            )

        return_amount: int = int(amount - (self._amount + self._fee))
        if return_amount != 0:
            outputs.append(
                TxOut(value=return_amount,
                      n=len(outputs),
                      script_pubkey=get_address_hash(address=self._address,
                                                     script=True)))

        # Build mutable transaction
        self._transaction = MutableTransaction(version=self._version,
                                               ins=inputs,
                                               outs=outputs,
                                               locktime=Locktime(locktime))
        # Set transaction type
        self._type = "bitcoin_normal_unsigned"
        return self
示例#17
0
    def test_all(self):
        global keys
        priv = ExtendedPrivateKey.decode(keys[0][1]).key
        pk = priv.pub()
        addr_string = str(pk.to_address())
        utxo = []

        for i in range(3):
            # create 3 tx to add to UTXO
            txid = regtest.send_rpc_cmd(['sendtoaddress', addr_string, '100'],
                                        0)
            to_spend = Transaction.unhexlify(
                regtest.send_rpc_cmd(['getrawtransaction', txid, '0'], 0))
            txout = None
            for out in to_spend.outs:
                if str(out.script_pubkey.address()) == addr_string:
                    txout = out
                    break
            assert txout is not None

            utxo.append({
                'txid': txid,
                'txout': txout,
                'solver': P2pkhSolver(priv),
                'next_seq': Sequence.max(),
                'next_locktime': Locktime(0)
            })

        regtest.send_rpc_cmd(['generate', '100'], 0)

        generate = False
        next_locktime = Locktime(0)
        next_sequence = Sequence.max()

        i = 0
        while i < len(self.all) - 2:
            print('{:04d}\r'.format(i), end='', flush=True)
            ins = [
                MutableTxIn(unspent['txid'], unspent['txout'].n,
                            ScriptSig.empty(), unspent['next_seq'])
                for unspent in utxo
            ]
            outs = []
            prev_types = []

            for j, (unspent, script) in enumerate(zip(utxo,
                                                      self.all[i:i + 3])):
                outs.append(
                    TxOut(unspent['txout'].value - 1000000, j, script[0]))
                prev_types.append(script[2])

            tx = MutableTransaction(
                2, ins, outs,
                min_locktime(unspent['next_locktime'] for unspent in utxo))
            mutable = copy.deepcopy(tx)
            tx = tx.spend([unspent['txout'] for unspent in utxo],
                          [unspent['solver'] for unspent in utxo])

            # print('====================')
            # print('txid: {}'.format(tx.txid))
            # print()
            # print(tx)
            # print()
            # print('raw: {}'.format(tx.hexlify()))
            # print('prev_scripts, amounts, solvers:')

            print('TX: {}'.format(i))
            regtest.send_rpc_cmd(['sendrawtransaction', tx.hexlify()], 0)
            print('Mempool size: {}'.format(
                len(regtest.send_rpc_cmd(['getrawmempool'], 0))))

            if cmdline_args.dumpfile is not None:
                with open(cmdline_args.dumpfile, 'a') as out:
                    for j, unspent in enumerate(utxo):
                        json.dump(
                            self.json_dump(unspent, tx.ins[j], j,
                                           copy.deepcopy(mutable).to_segwit()),
                            out)
                        out.write('\n')

            utxo = []

            for j, (output, prev_type) in enumerate(zip(tx.outs, prev_types)):

                if 'time' in prev_type:
                    if 'absolute' in prev_type:
                        next_locktime = Locktime(100)
                        next_sequence = Sequence(0xfffffffe)
                    if 'relative' in prev_type:
                        next_sequence = Sequence(3)
                        generate = True
                else:
                    next_locktime = Locktime(0)
                    next_sequence = Sequence.max()

                utxo.append({
                    'txid': tx.txid,
                    'txout': output,
                    'solver': self.all[i + j][1][0],  # solver
                    'next_seq': next_sequence,
                    'next_locktime': next_locktime
                })
            if generate:
                regtest.send_rpc_cmd(['generate', '4'], 0)
                generate = False

            if not i % 10:
                print('generating 2')
                regtest.send_rpc_cmd(['generate', '2'], 0)

            i += 1

        ins = [
            MutableTxIn(unspent['txid'], unspent['txout'].n, ScriptSig.empty(),
                        unspent['next_seq']) for unspent in utxo
        ]

        tx = MutableTransaction(
            2, ins, [
                TxOut(
                    sum(unspent['txout'].value for unspent in utxo) - 1000000,
                    0, self.final['script'])
            ], min_locktime(unspent['next_locktime'] for unspent in utxo))
        tx = tx.spend([unspent['txout'] for unspent in utxo],
                      [unspent['solver'] for unspent in utxo])

        # print('====================')
        # print('txid: {}'.format(tx.txid))
        # print()
        # print(tx)
        # print()
        # print('raw: {}'.format(tx.hexlify()))
        # print('prev_scripts, amounts, solvers:')
        # for unspent in utxo:
        #     print(unspent['txout'].script_pubkey, unspent['txout'].value, unspent['solver'].__class__.__name__)
        regtest.send_rpc_cmd(['sendrawtransaction', tx.hexlify()], 0)

        regtest.teardown()
示例#18
0
 def get_args():
     return Locktime(100),
示例#19
0
    def build_transaction(self,
                          transaction_id,
                          wallet,
                          amount,
                          secret=None,
                          locktime=0):
        """
        Build bitcoin refund transaction.

        :param transaction_id: bitcoin fund transaction id to redeem.
        :type transaction_id: str
        :param wallet: bitcoin sender wallet.
        :type wallet: bitcoin.wallet.Wallet
        :param amount: bitcoin amount to withdraw.
        :type amount: int
        :param secret: secret passphrase.
        :type secret: str
        :param locktime: bitcoin transaction lock time, defaults to 0.
        :type locktime: int
        :returns: RefundTransaction -- bitcoin refund transaction instance.

        >>> from shuttle.providers.bitcoin.transaction import RefundTransaction
        >>> refund_transaction = RefundTransaction(network="testnet")
        >>> refund_transaction.build_transaction(fund_transaction_id, sender_wallet, 10000)
        <shuttle.providers.bitcoin.transaction.RefundTransaction object at 0x0409DAF0>
        """

        # Checking build transaction arguments instance
        if not isinstance(transaction_id, str):
            raise TypeError("invalid amount instance, only takes string type")
        if not isinstance(wallet, Wallet):
            raise TypeError(
                "invalid wallet instance, only takes bitcoin Wallet class")
        if secret is not None and not isinstance(secret, str):
            raise TypeError("invalid secret instance, only takes string type")
        # Setting transaction_id and wallet
        self.transaction_id, self.wallet, self.secret = transaction_id, wallet, secret
        # Getting transaction detail by id
        self.transaction_detail = get_transaction_detail(self.transaction_id)
        # Checking transaction outputs
        if "outputs" not in self.transaction_detail:
            raise NotFoundError("not found htlc in this %s hash" %
                                self.transaction_id)
        # Hash time lock contract output
        self.htlc = self.transaction_detail["outputs"][0]
        # Sender account output
        sender_address = P2pkhScript.unhexlify(
            self.transaction_detail["outputs"][1]["script"]).address(
                mainnet=self.mainnet)
        self.sender_account = Wallet(network=self.network).from_address(
            str(sender_address))
        # HTLC info's
        htlc_amount = self.htlc["value"]
        htlc_script = P2shScript.unhexlify(self.htlc["script"])
        # Calculating fee
        self.fee = fee_calculator(1, 1)
        if amount < self.fee:
            raise BalanceError("insufficient spend utxos")
        elif not htlc_amount >= (amount - self.fee):
            raise BalanceError("insufficient spend utxos",
                               "maximum withdraw %d" % htlc_amount)
        # Building mutable bitcoin transaction
        self.transaction = MutableTransaction(
            version=self.version,
            ins=[
                TxIn(txid=self.transaction_id,
                     txout=0,
                     script_sig=ScriptSig.empty(),
                     sequence=Sequence.max())
            ],
            outs=[
                TxOut(value=(amount - self.fee),
                      n=0,
                      script_pubkey=P2pkhScript.unhexlify(
                          self.sender_account.p2pkh()))
            ],
            locktime=Locktime(locktime))
        return self
示例#20
0
to_spend = TransactionFactory.unhexlify(to_spend_raw)

unsigned = MutableTransaction(version=2,
                              ins=[
                                  TxIn(txid=to_spend.txid,
                                       txout=0,
                                       script_sig=ScriptSig.empty(),
                                       sequence=Sequence.max())
                              ],
                              outs=[
                                  TxOut(value=penalty,
                                        n=0,
                                        script_pubkey=lock_time_script),
                                  TxOut(value=balance - penalty - mining_fee,
                                        n=1,
                                        script_pubkey=change_script)
                              ],
                              locktime=Locktime(0))
# 输入脚本
solver = P2pkhSolver(privk)

# 修改交易
signed = unsigned.spend([to_spend.outs[0]], [solver])
print('commit_tx_hex: ', signed.hexlify())

# 发送交易
from blockcypher import pushtx

tx = pushtx(coin_symbol=coin_symbol, api_key=api_key, tx_hex=signed.hexlify())
format_output(tx)
示例#21
0
    def test_all(self):
        global keys
        priv = PrivateKey.from_bip32(keys[0][1])
        pk = priv.pub()
        addr_string = str(pk.to_address())
        utxo = []

        for i in range(3):
            # create 3 tx to add to UTXO
            txid = regtest.send_rpc_cmd(['sendtoaddress', addr_string, '100'],
                                        0)
            to_spend = Transaction.unhexlify(
                regtest.send_rpc_cmd(['getrawtransaction', txid, '0'], 0))
            txout = None
            for out in to_spend.outs:
                if str(out.script_pubkey.address()) == addr_string:
                    txout = out
                    break
            assert txout is not None

            utxo.append({
                'txid': txid,
                'txout': txout,
                'solver': P2pkhSolver(priv),
                'next_seq': Sequence.max(),
                'next_locktime': Locktime(0)
            })

        regtest.send_rpc_cmd(['generate', '100'], 0)

        generate = False
        next_locktime = Locktime(0)
        next_sequence = Sequence.max()

        i = 0  # 1785 # 382  # 2376  # 1180  #
        while i < len(self.all) - 2:
            print('{:04d}\r'.format(i), end='')
            ins = [
                MutableTxIn(unspent['txid'], unspent['txout'].n,
                            ScriptSig.empty(), unspent['next_seq'])
                for unspent in utxo
            ]
            outs = []
            prev_types = []

            for j, (unspent, script) in enumerate(zip(utxo,
                                                      self.all[i:i + 3])):
                outs.append(
                    TxOut(unspent['txout'].value - 1000000, j, script[0]))
                prev_types.append(script[2])

            tx = MutableTransaction(
                2, ins, outs,
                min_locktime(unspent['next_locktime'] for unspent in utxo))

            tx = tx.spend([unspent['txout'] for unspent in utxo],
                          [unspent['solver'] for unspent in utxo])

            # print('====================')
            # print('txid: {}'.format(tx.txid))
            # print()
            # print(tx)
            # print()
            # print('raw: {}'.format(tx.hexlify()))
            # print('prev_scripts, amounts, solvers:')
            for unspent in utxo:
                if isinstance(unspent['solver'], P2shSolver):
                    if isinstance(unspent['solver'].redeem_script_solver,
                                  P2wshV0Solver):
                        prev = unspent[
                            'solver'].redeem_script_solver.witness_script
                    else:
                        prev = unspent['solver'].redeem_script
                elif isinstance(unspent['solver'], P2wshV0Solver):
                    prev = unspent['solver'].witness_script
                else:
                    prev = unspent['txout'].script_pubkey
                print(prev, unspent['txout'].value,
                      unspent['solver'].__class__.__name__)
            regtest.send_rpc_cmd(['sendrawtransaction', tx.hexlify()], 0)

            utxo = []

            for j, (output, prev_type) in enumerate(zip(tx.outs, prev_types)):

                if 'time' in prev_type:
                    if 'absolute' in prev_type:
                        next_locktime = Locktime(100)
                        next_sequence = Sequence(0xfffffffe)
                    if 'relative' in prev_type:
                        next_sequence = Sequence(3)
                        generate = True
                else:
                    next_locktime = Locktime(0)
                    next_sequence = Sequence.max()

                utxo.append({
                    'txid': tx.txid,
                    'txout': output,
                    'solver': self.all[i + j][1][0],  # solver
                    'next_seq': next_sequence,
                    'next_locktime': next_locktime
                })
            if generate:
                regtest.send_rpc_cmd(['generate', '4'], 0)
                generate = False

            if not i % 10:
                regtest.send_rpc_cmd(['generate', '2'], 0)

            i += 1

        ins = [
            MutableTxIn(unspent['txid'], unspent['txout'].n, ScriptSig.empty(),
                        unspent['next_seq']) for unspent in utxo
        ]

        tx = MutableTransaction(
            2, ins, [
                TxOut(
                    sum(unspent['txout'].value for unspent in utxo) - 1000000,
                    0, self.final['script'])
            ], min_locktime(unspent['next_locktime'] for unspent in utxo))
        tx = tx.spend([unspent['txout'] for unspent in utxo],
                      [unspent['solver'] for unspent in utxo])

        # print('====================')
        # print('txid: {}'.format(tx.txid))
        # print()
        # print(tx)
        # print()
        # print('raw: {}'.format(tx.hexlify()))
        # print('prev_scripts, amounts, solvers:')
        for unspent in utxo:
            print(unspent['txout'].script_pubkey, unspent['txout'].value,
                  unspent['solver'].__class__.__name__)
        regtest.send_rpc_cmd(['sendrawtransaction', tx.hexlify()], 0)

        regtest.teardown()
示例#22
0
    def build_transaction(self, transaction_id, wallet, amount, locktime=0):
        """
        Build Bitcoin refund transaction.

        :param transaction_id: Bitcoin fund transaction id to redeem.
        :type transaction_id: str
        :param wallet: Bitcoin sender wallet.
        :type wallet: bitcoin.wallet.Wallet
        :param amount: Bitcoin amount to withdraw.
        :type amount: int
        :param locktime: Bitcoin transaction lock time, defaults to 0.
        :type locktime: int
        :returns: RefundTransaction -- Bitcoin refund transaction instance.

        >>> from shuttle.providers.bitcoin.transaction import RefundTransaction
        >>> from shuttle.providers.bitcoin.wallet import Wallet
        >>> sender_wallet = Wallet(network="testnet").from_passphrase("meherett")
        >>> refund_transaction = RefundTransaction(network="testnet")
        >>> refund_transaction.build_transaction(transaction_id="1006a6f537fcc4888c65f6ff4f91818a1c6e19bdd3130f59391c00212c552fbd", wallet=sender_wallet, amount=10000)
        <shuttle.providers.bitcoin.transaction.RefundTransaction object at 0x0409DAF0>
        """

        # Checking parameter instances
        if not isinstance(transaction_id, str):
            raise TypeError("invalid amount instance, only takes string type")
        if not isinstance(wallet, Wallet):
            raise TypeError(
                "invalid wallet instance, only takes Bitcoin Wallet class")

        # Setting transaction_id and wallet
        self.transaction_id, self.wallet = transaction_id, wallet
        # Getting transaction detail by id
        self.transaction_detail = get_transaction_detail(self.transaction_id)
        # Getting Hash time lock contract output detail
        self.htlc_detail = self.transaction_detail["outputs"][0]
        # Getting HTLC funded amount balance
        htlc_amount = self.htlc_detail["value"]

        # Calculating fee
        self._fee = fee_calculator(1, 1)
        if amount < self._fee:
            raise BalanceError("insufficient spend utxos")
        elif not htlc_amount >= (amount - self._fee):
            raise BalanceError("insufficient spend utxos",
                               f"maximum you can withdraw {htlc_amount}")

        # Building mutable Bitcoin transaction
        self.transaction = MutableTransaction(
            version=self.version,
            ins=[
                TxIn(txid=self.transaction_id,
                     txout=0,
                     script_sig=ScriptSig.empty(),
                     sequence=Sequence.max())
            ],
            outs=[
                TxOut(value=(amount - self._fee),
                      n=0,
                      script_pubkey=P2pkhScript.unhexlify(
                          hex_string=self.wallet.p2pkh()))
            ],
            locktime=Locktime(locktime))
        self._type = "bitcoin_refund_unsigned"
        return self
示例#23
0
    def build_transaction(self, wallet, htlc, amount, locktime=0):
        """
        Build Bitcoin fund transaction.

        :param wallet: Bitcoin sender wallet.
        :type wallet: bitcoin.wallet.Wallet
        :param htlc: Bitcoin hash time lock contract (HTLC).
        :type htlc: bitcoin.htlc.HTLC
        :param amount: Bitcoin amount to fund.
        :type amount: int
        :param locktime: Bitcoin transaction lock time, defaults to 0.
        :type locktime: int
        :returns: FundTransaction -- Bitcoin fund transaction instance.

        >>> from shuttle.providers.bitcoin.htlc import HTLC
        >>> from shuttle.providers.bitcoin.transaction import FundTransaction
        >>> from shuttle.providers.bitcoin.wallet import Wallet
        >>> htlc = HTLC(network="testnet").init("821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e0158", "muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", "mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", 1000)
        >>> sender_wallet = Wallet(network="testnet").from_passphrase("meherett")
        >>> fund_transaction = FundTransaction(network="testnet")
        >>> fund_transaction.build_transaction(wallet=sender_wallet, htlc=htlc, amount=10000)
        <shuttle.providers.bitcoin.transaction.FundTransaction object at 0x0409DAF0>
        """

        # Checking parameter instances
        if not isinstance(wallet, Wallet):
            raise TypeError(
                "invalid wallet instance, only takes Bitcoin Wallet class")
        if not isinstance(htlc, HTLC):
            raise TypeError(
                "invalid htlc instance, only takes Bitcoin HTLC class")
        if not isinstance(amount, int):
            raise TypeError("invalid amount instance, only takes integer type")

        # Setting wallet, htlc, amount and unspent
        self.wallet, self.htlc, self.amount = wallet, htlc, amount
        # Getting unspent transaction output
        self.unspent = self.wallet.unspent()
        # Setting previous transaction indexes
        self.previous_transaction_indexes = \
            self.get_previous_transaction_indexes(amount=self.amount)

        # Getting transaction inputs and amount
        inputs, amount = self.inputs(
            utxos=self.unspent,
            previous_transaction_indexes=self.previous_transaction_indexes)

        # Calculating Bitcoin fee
        self._fee = fee_calculator(len(inputs), 2)
        if amount < (self.amount + self._fee):
            raise BalanceError("insufficient spend utxos")

        # Building mutable Bitcoin transaction
        self.transaction = MutableTransaction(
            version=self.version,
            ins=inputs,
            outs=[
                # Funding into hash time lock contract script hash
                TxOut(value=self.amount,
                      n=0,
                      script_pubkey=P2shScript.unhexlify(
                          hex_string=self.htlc.hash())),
                # Controlling amounts when we are funding on htlc script
                TxOut(value=(amount - (self._fee + self.amount)),
                      n=1,
                      script_pubkey=P2pkhScript.unhexlify(
                          hex_string=self.wallet.p2pkh()))
            ],
            locktime=Locktime(locktime))
        self._type = "bitcoin_fund_unsigned"
        return self
示例#24
0
    def build_transaction(
            self,
            address: str,
            transaction_hash: str,
            locktime: int = config["locktime"]) -> "RefundTransaction":
        """
        Build Bitcoin refund transaction.

        :param address: Bitcoin sender address.
        :type address: str
        :param transaction_hash: Bitcoin funded transaction hash/id.
        :type transaction_hash: str
        :param locktime: Bitcoin transaction lock time, defaults to ``0``.
        :type locktime: int

        :returns: RefundTransaction -- Bitcoin refund transaction instance.

        >>> from swap.providers.bitcoin.transaction import RefundTransaction
        >>> refund_transaction: RefundTransaction = RefundTransaction("testnet")
        >>> refund_transaction.build_transaction(address="n1wgm6kkzMcNfAtJmes8YhpvtDzdNhDY5a", transaction_hash="a211d21110756b266925fee2fbf2dc81529beef5e410311b38578dc3a076fb31")
        <swap.providers.bitcoin.transaction.RefundTransaction object at 0x0409DAF0>
        """

        # Check parameter instances
        if not is_address(address, self._network):
            raise AddressError(
                f"Invalid Bitcoin sender '{address}' {self._network} address.")

        # Set address and transaction_hash
        self._address, self._transaction_hash, = address, transaction_hash
        # Get transaction
        self._transaction_detail = get_transaction(
            transaction_hash=self._transaction_hash, network=self._network)
        # Find HTLC UTXO
        self._htlc_utxo = find_p2sh_utxo(transaction=self._transaction_detail)

        if self._htlc_utxo is None:
            raise ValueError(
                "Invalid transaction id, there is no pay to script hash (P2SH) address."
            )

        self._amount = self._htlc_utxo["value"]
        # Calculate the fee
        self._fee = fee_calculator(1, 1)

        outputs: list = [
            TxOut(value=(self._amount - self._fee),
                  n=0,
                  script_pubkey=get_address_hash(address=self._address,
                                                 script=True))
        ]
        # Build mutable transaction
        self._transaction = MutableTransaction(
            version=self._version,
            ins=[
                TxIn(txid=self._transaction_hash,
                     txout=self._htlc_utxo["position"],
                     script_sig=ScriptSig.empty(),
                     sequence=Sequence.max())
            ],
            outs=outputs,
            locktime=Locktime(locktime))

        # Set transaction type
        self._type = "bitcoin_refund_unsigned"
        return self
示例#25
0
    def build_transaction(
            self,
            address: str,
            htlc: HTLC,
            amount: Optional[Union[int, float]],
            unit: str = config["unit"],
            locktime: int = config["locktime"]) -> "FundTransaction":
        """
        Build Bitcoin fund transaction.

        :param address: Bitcoin sender address.
        :type address: str
        :param htlc: Bitcoin HTLC instance.
        :type htlc: bitcoin.htlc.HTLC
        :param amount: Bitcoin amount, default to ``None``.
        :type amount: int, float
        :param unit: Bitcoin unit, default to ``Satoshi``.
        :type unit: str
        :param locktime: Bitcoin transaction lock time, defaults to ``0``.
        :type locktime: int

        :returns: FundTransaction -- Bitcoin fund transaction instance.

        >>> from swap.providers.bitcoin.htlc import HTLC
        >>> from swap.providers.bitcoin.transaction import FundTransaction
        >>> from swap.utils import sha256
        >>> htlc: HTLC = HTLC(network="testnet")
        >>> htlc.build_htlc(secret_hash=sha256("Hello Meheret!"), recipient_address="mgS3WMHp9nvdUPeDJxr5iCF2P5HuFZSR3V", sender_address="n1wgm6kkzMcNfAtJmes8YhpvtDzdNhDY5a", endtime=1624687630)
        >>> fund_transaction: FundTransaction = FundTransaction(network="testnet")
        >>> fund_transaction.build_transaction(address="n1wgm6kkzMcNfAtJmes8YhpvtDzdNhDY5a", htlc=htlc, amount=0.001, unit="BTC")
        <swap.providers.bitcoin.transaction.FundTransaction object at 0x0409DAF0>
        """

        # Check parameter instances
        if not is_address(address, self._network):
            raise AddressError(
                f"Invalid Bitcoin sender '{address}' {self._network} address.")
        if not isinstance(htlc, HTLC):
            raise TypeError(
                "Invalid Bitcoin HTLC instance, only takes xinfin HTLC class")
        if htlc.agreements and address != htlc.agreements["sender_address"]:
            raise AddressError(
                f"Wrong Bitcoin sender '{address}' address",
                "address must be equal with HTLC agreements sender address.")
        if unit not in ["BTC", "mBTC", "Satoshi"]:
            raise UnitError(
                "Invalid Bitcoin unit, choose only 'BTC', 'mBTC' or 'Satoshi' units."
            )

        self._address, outputs, self._htlc, self._amount = (
            address, [], htlc,
            (amount if unit == "Satoshi" else amount_unit_converter(
                amount=amount, unit_from=f"{unit}2Satoshi")))

        # Get Sender UTXO's
        self._utxos = get_utxos(address=self._address, network=self._network)
        # Outputs action
        outputs.append(
            TxOut(value=self._amount,
                  n=0,
                  script_pubkey=get_address_hash(
                      address=self._htlc.contract_address(), script=True)))
        # Get previous transaction indexes
        self._previous_transaction_indexes, max_amount = _get_previous_transaction_indexes(
            utxos=self._utxos, amount=self._amount, transaction_output=2)
        # Build transaction inputs
        inputs, amount = _build_inputs(
            utxos=self._utxos,
            previous_transaction_indexes=self._previous_transaction_indexes)
        # Calculate the fee
        self._fee = fee_calculator(len(inputs), 2)

        if amount < self._amount:
            raise BalanceError("Insufficient spend UTXO's",
                               "you don't have enough amount.")
        elif amount < (self._amount + self._fee):
            raise BalanceError(
                f"You don't have enough amount to pay '{self._fee}' Satoshi fee",
                f"you can spend maximum '{amount - self._fee}' Satoshi amount."
            )

        return_amount: int = int(amount - (self._amount + self._fee))
        if return_amount != 0:
            outputs.append(
                TxOut(value=return_amount,
                      n=len(outputs),
                      script_pubkey=get_address_hash(address=self._address,
                                                     script=True)))

        # Build mutable transaction
        self._transaction = MutableTransaction(version=self._version,
                                               ins=inputs,
                                               outs=outputs,
                                               locktime=Locktime(locktime))
        # Set transaction type
        self._type = "bitcoin_fund_unsigned"
        return self
示例#26
0
def commit_tx(committer, receiver, secret, type, lock_time, penalty):
    if type not in ['Timed', 'Height']:
        raise ValueError("type should be 'Timed' or 'Height'")

    secret_hash = hashlib.sha256(hashlib.sha256(
        secret.encode()).digest()).digest()
    secret_hash = StackData.from_bytes(secret_hash)
    print("秘密经hash256加密结果:", secret_hash)

    # 创建输出脚本
    if type is 'Height':

        # Relative - HeightBased
        sequence = lock_time
        lock_time_script = IfElseScript(
            # if branch
            Hashlock256Script(secret_hash, P2pkhScript(committer.pubk)),
            # else branch
            RelativeTimelockScript(  # timelocked script
                HeightBasedSequence(sequence),  # expiration
                P2pkhScript(receiver.pubk)))
    else:
        # Relative - TimedBased
        time_delta = datetime.timedelta(minutes=lock_time)
        time_now = datetime.datetime.now()
        print("current time: ", time_now.strftime("%y-%m-%d %H:%M:%S"))
        print("pay deposit time: ",
              (time_now + time_delta).strftime("%y-%m-%d %H:%M:%S"))

        lock_time_script = IfElseScript(
            # if branch
            Hashlock256Script(secret_hash, P2pkhScript(committer.pubk)),
            # else branch
            RelativeTimelockScript(  # timelocked script
                TimeBasedSequence.from_timedelta(time_delta),  # expiration
                P2pkhScript(receiver.pubk)))

    # 找零脚本
    change_script = P2pkhScript(committer.pubk)

    # 清理资产
    print("sweeping fund...")
    to_spend_hash, balance = sweep_fund(privkey=str(committer.privk),
                                        address=str(committer.address),
                                        coin_symbol=coin_symbol,
                                        api_key=committer.api_key)

    # 估算挖矿费用
    print('estimating mining fee...')
    mining_fee_per_kb = get_mining_fee_per_kb(coin_symbol,
                                              committer.api_key,
                                              condidence='high')
    estimated_tx_size = cal_tx_size_in_byte(inputs_num=1, outputs_num=2)
    mining_fee = int(mining_fee_per_kb * (estimated_tx_size / 1000)) * 2

    # 设置罚金
    assert penalty + mining_fee <= balance, 'committer账户余额不足'

    # 创建交易
    to_spend_raw = get_raw_tx(to_spend_hash, coin_symbol)
    to_spend = TransactionFactory.unhexlify(to_spend_raw)

    unsigned = MutableTransaction(version=2,
                                  ins=[
                                      TxIn(txid=to_spend.txid,
                                           txout=0,
                                           script_sig=ScriptSig.empty(),
                                           sequence=Sequence.max())
                                  ],
                                  outs=[
                                      TxOut(value=penalty,
                                            n=0,
                                            script_pubkey=lock_time_script),
                                      TxOut(value=balance - penalty -
                                            mining_fee,
                                            n=1,
                                            script_pubkey=change_script)
                                  ],
                                  locktime=Locktime(0))

    # 输入脚本
    solver = P2pkhSolver(committer.privk)

    # 修改交易
    signed = unsigned.spend([to_spend.outs[0]], [solver])
    print('commit_tx_hex: ', signed.hexlify())

    # 发送交易
    tx = pushtx(coin_symbol=coin_symbol,
                api_key=committer.api_key,
                tx_hex=signed.hexlify())
    format_output(tx)
    return tx['tx']['hash']
示例#27
0
    def build_htlc(self, secret_hash: str, recipient_address: str,
                   sender_address: str, endtime: int) -> "HTLC":
        """
        Build Bitcoin Hash Time Lock Contract (HTLC).

        :param secret_hash: secret sha-256 hash.
        :type secret_hash: str
        :param recipient_address: Bitcoin recipient address.
        :type recipient_address: str
        :param sender_address: Bitcoin sender address.
        :type sender_address: str
        :param endtime: Expiration block time (Seconds).
        :type endtime: int

        :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance.

        >>> from swap.providers.bitcoin.htlc import HTLC
        >>> from swap.utils import sha256
        >>> htlc: HTLC = HTLC(network="testnet")
        >>> htlc.build_htlc(secret_hash=sha256("Hello Meheret!"), recipient_address="mgS3WMHp9nvdUPeDJxr5iCF2P5HuFZSR3V", sender_address="n1wgm6kkzMcNfAtJmes8YhpvtDzdNhDY5a", endtime=1624687630)
        <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0>
        """

        # Check parameter instances
        if len(secret_hash) != 64:
            raise ValueError("Invalid secret hash, length must be 64.")
        if not is_address(address=recipient_address, network=self._network):
            raise AddressError(
                f"Invalid Bitcoin recipient '{recipient_address}' {self._network} address."
            )
        if not is_address(address=sender_address, network=self._network):
            raise AddressError(
                f"Invalid Bitcoin sender '{sender_address}' {self._network} address."
            )

        # Get current working directory path (like linux or unix path).
        cwd: str = PurePosixPath(os.path.dirname(
            os.path.realpath(__file__))).__str__().replace("\\", "/")

        with open(f"{cwd}/contracts/htlc.script", "r",
                  encoding="utf-8") as htlc_script:
            htlc_opcode: str = htlc_script.readlines()[
                -1]  # HTLC OP_Code script
            htlc_script.close()

        build_htlc_opcode: str = htlc_opcode.format(
            secret_hash=hashlib.sha256(unhexlify(secret_hash)).hexdigest(),
            recipient_address_hash=get_address_hash(address=recipient_address,
                                                    script=False),
            sender_address_hash=get_address_hash(address=sender_address,
                                                 script=False),
            endtime=Locktime(n=endtime).for_script().hexlify()[2:])

        self.agreements = {
            "secret_hash": secret_hash,
            "recipient_address": recipient_address,
            "sender_address": sender_address,
            "endtime": {
                "datetime": str(datetime.fromtimestamp(endtime)),
                "timestamp": endtime
            }
        }
        bytecode: str = Script.compile(build_htlc_opcode)
        self._script = ScriptBuilder.identify(bytecode)
        return self
示例#28
0
    def __init__(self, *args, **kwargs):
        global keys

        super().__init__(*args, **kwargs)

        pubs = [ExtendedPublicKey.decode(pair[0]).key for pair in keys]
        privs = [ExtendedPrivateKey.decode(pair[1]).key for pair in keys]
        all_embedders = {
            'p2sh', 'p2wsh', 'ifelse', 'absolutetime', 'relativetime',
            'hash160', 'hash256'
        }

        self.scripts = [
            {
                'name': 'p2pkh',
                'script': P2pkhScript(pubs[0]),
                'solver': partial(P2pkhSolver, privs[0]),
                'embeddable_by': all_embedders
            },
            {
                'name': 'p2wpkh',
                'script': P2wpkhV0Script(pubs[1]),
                'solver': partial(P2wpkhV0Solver, privs[1]),
                'embeddable_by': {'p2sh'}
            },
            {
                'name': 'p2pk',
                'script': P2pkScript(pubs[2]),
                'solver': partial(P2pkSolver, privs[2]),
                'embeddable_by': all_embedders
            },
            {
                'name': 'multisig',
                'script': MultisigScript(2, pubs[3], pubs[4], pubs[5], 3),
                'solver': partial(MultisigSolver, privs[3], privs[4]),
                'embeddable_by': all_embedders
            },
        ]

        self.sighashed_scripts = []

        for script in self.scripts:
            for args in (('ALL', False), ('ALL', True), ('NONE', False),
                         ('NONE', True), ('SINGLE', False), ('SINGLE', True)):
                scriptcpy = copy.deepcopy(script)
                scriptcpy['sighash'] = Sighash(*args)
                try:
                    scriptcpy['solver'] = scriptcpy['solver'](sighash=Sighash(
                        *args))
                except TypeError:
                    scriptcpy['solver'] = scriptcpy['solver'](
                        sighashes=[Sighash(
                            *args), Sighash(*args)])
                self.sighashed_scripts.append(scriptcpy)

        self.scripts = self.sighashed_scripts

        self.scripts = self.sighashed_scripts

        self.final = {
            'name': 'nulldata',
            'script': NulldataScript(StackData.unhexlify('deadbeef')),
            'solver': None,
            'embeddable_by': {}
        }
        self.preimage_streams = [Stream(TestSpends.rand_bytes())]
        self.preimages = [pre.serialize() for pre in self.preimage_streams]
        self.hashes160 = [
            preimage.hash160() for preimage in self.preimage_streams
        ]
        self.hashes256 = [
            preimage.hash256() for preimage in self.preimage_streams
        ]

        self.all = [(s['script'], (s['solver'], s['script']), s['name'])
                    for s in self.scripts]

        self.embedders = [
            TimelockEmbedder, Relativetimelockembedder, Hashlock160Embedder,
            Hashlock256Embedder
        ]

        self.double_embedders = [IfElseEmbedder]

        embedded = []

        for embedder in self.embedders:
            if embedder.get_name() != 'ifelse':
                for script in self.scripts:
                    if embedder.get_name() in script['embeddable_by']:
                        if embedder.get_name() == 'hash160':
                            for preimage, phash in zip(self.preimages,
                                                       self.hashes160):
                                emb = embedder(phash,
                                               scripts=[script['script']])
                                embedded.append(
                                    (emb.instance, (HashlockSolver(
                                        preimage,
                                        script['solver']), emb.instance),
                                     '{}({})'.format(embedder.get_name(),
                                                     script['name'])))
                        elif embedder.get_name() == 'hash256':
                            for preimage, phash in zip(self.preimages,
                                                       self.hashes256):
                                emb = embedder(phash,
                                               scripts=[script['script']])
                                embedded.append(
                                    (emb.instance, (HashlockSolver(
                                        preimage,
                                        script['solver']), emb.instance),
                                     '{}({})'.format(embedder.get_name(),
                                                     script['name'])))
                        elif embedder.get_name() == 'relativetime':
                            emb = embedder(scripts=[script['script']])
                            embedded.append(
                                (emb.instance, (RelativeTimelockSolver(
                                    Sequence(3),
                                    script['solver']), emb.instance),
                                 '{}({})'.format(embedder.get_name(),
                                                 script['name'])))
                        elif embedder.get_name() == 'absolutetime':
                            emb = embedder(scripts=[script['script']])
                            embedded.append(
                                (emb.instance, (AbsoluteTimelockSolver(
                                    Locktime(100),
                                    script['solver']), emb.instance),
                                 '{}({})'.format(embedder.get_name(),
                                                 script['name'])))
                        else:
                            raise ValueError('Unknown embedder: {}'.format(
                                embedder.get_name()))

        self.all += [s for s in embedded]

        for embedder in self.double_embedders:
            included = [(x, y, t) for (x, y, t) in self.all if t != 'p2wpkh']
            for ((if_script, (if_solver, _), if_type),
                 (else_script, (else_solver, _),
                  else_type)) in TestSpends.pairwise(included):
                for branch in [Branch.IF, Branch.ELSE]:
                    inst = embedder(scripts=[if_script, else_script]).instance
                    # print(type(if_script), type(if_keys), type(if_spend), type(if_type))
                    # if 'hash' in else_type:
                    #     print(else_spend)
                    self.all.append(
                        (inst, (IfElseSolver(
                            branch,
                            if_solver if branch == Branch.IF else else_solver),
                                inst),
                         'ifelse({}, {})'.format(if_type, else_type)))

        for script, (solver, _), stype in [s for s in self.all]:
            if 'p2wpkh' not in stype:
                inst = P2wshEmbedder(scripts=[script]).instance
                self.all.append((inst, (P2wshV0Solver(script, solver), script),
                                 'p2wsh({})'.format(stype)))

        for script, (solver, prev), stype in [s for s in self.all]:
            inst = P2shEmbedder(scripts=[script]).instance
            self.all.append(
                (inst, (P2shSolver(script,
                                   solver), prev), 'p2sh({})'.format(stype)))