Пример #1
0
    def get_next_tx(self, mutable=False):
        version = self._version()
        tstamp = self._timestamp() if self.network.tx_timestamp else 0
        segwit, txins_data = self._txins_data()
        txouts = self._txouts()
        if segwit:
            witness = self._witness()
            txins = [CoinBaseTxIn(*txin_data[2:], witness=Witness(wit))
                     if isinstance(txin_data[2], CoinBaseScriptSig)
                     else TxIn(*txin_data, witness=Witness(wit))
                     for txin_data, wit in zip(txins_data, witness)]
        else:
            txins = [CoinBaseTxIn(*txin_data[2:])
                     if isinstance(txin_data[2], CoinBaseScriptSig)
                     else TxIn(*txin_data)
                     for txin_data in txins_data]

        locktime = self._locktime()

        if len(txins) > 1 and isinstance(txins[0], CoinBaseTxIn):
            raise ValueError('Transaction looks like coinbase but has more than one txin')

        if segwit:
            raise Exception('Peercoin does not currently support SegWit.')
        else:
            result = Transaction(version, txins, txouts, locktime, network=self.network, timestamp=tstamp)

        return result.to_mutable() if mutable else result
Пример #2
0
def tx_in(tx, inscript):  #TODO change from 1 i/p to multi i/p
    to_spend = Transaction.unhexlify(tx)
    intxs = [
        TxIn(txid=to_spend.txid,
             txout=0,
             sequence=Sequence.max(),
             script_sig=inscript)
    ]  #ScriptSig.<something>
    return intxs
Пример #3
0
 def inputs(utxos, previous_transaction_indexes=None):
     inputs, amount = list(), int()
     for index, utxo in enumerate(utxos):
         if previous_transaction_indexes is None or index in previous_transaction_indexes:
             amount += utxo["amount"]
             inputs.append(
                 TxIn(txid=utxo["hash"], txout=utxo["output_index"],
                      script_sig=ScriptSig.empty(), sequence=Sequence.max()))
     return inputs, amount
Пример #4
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
Пример #5
0
def _build_inputs(
        utxos: list,
        previous_transaction_indexes: Optional[list] = None) -> tuple:
    inputs, amount = [], 0
    for index, utxo in enumerate(utxos):
        if previous_transaction_indexes is None or index in previous_transaction_indexes:
            amount += utxo["value"]
            inputs.append(
                TxIn(txid=utxo["tx_hash"],
                     txout=utxo["tx_output_n"],
                     script_sig=ScriptSig.empty(),
                     sequence=Sequence.max()))
    return inputs, amount
Пример #6
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']
Пример #7
0
    def select_inputs(self, address: str, amount: int) -> dict:

        utxos = []
        utxo_sum = Decimal(-0.01)  # starts from negative due to minimal fee
        for tx in self.listunspent(address=address):

                utxos.append(
                    TxIn(txid=tx['tx_hash'],
                         txout=tx['tx_ouput_n'],
                         sequence=Sequence.max(),
                         script_sig=ScriptSig.empty())
                         )

                utxo_sum += Decimal(tx['value'] /  10**8)
                if utxo_sum >= amount:
                    return {'utxos': utxos, 'total': utxo_sum}

        if utxo_sum < amount:
            raise InsufficientFunds('Insufficient funds.')
Пример #8
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)
Пример #9
0
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]
Пример #10
0
    def select_inputs(self, address: str, amount: int) -> dict:

        utxos = []
        utxo_sum = Decimal(-0.01)  # starts from negative due to minimal fee
        for tx in self.listunspent(address=address):
            script = self.getrawtransaction(
                tx['txid'])['vout'][0]['scriptPubKey']['hex']
            utxos.append(
                TxIn(txid=tx['txid'],
                     txout=tx['vout'],
                     sequence=Sequence.max(),
                     script_sig=ScriptSig.unhexlify(script)))

            utxo_sum += Decimal(tx['amount'])
            if utxo_sum >= amount:
                return {'utxos': utxos, 'total': utxo_sum}

        if utxo_sum < amount:
            raise InsufficientFunds('Insufficient funds.')

        raise Exception("undefined behavior :.(")
Пример #11
0
    def select_inputs(self, address: str, amount: int) -> dict:
        '''select UTXOs'''

        utxos = []
        utxo_sum = Decimal(-0.01)  # starts from negative due to minimal fee
        for tx in sorted(self.listunspent(address=address), key=itemgetter('confirmations')):

                utxos.append(
                    TxIn(txid=tx['tx_hash'],
                         txout=tx['tx_ouput_n'],
                         sequence=Sequence.max(),
                         script_sig=ScriptSig.unhexlify(tx['script']))
                         )

                utxo_sum += Decimal(int(tx['value']) / 100000000)
                if utxo_sum >= amount:
                    return {'utxos': utxos, 'total': utxo_sum}

        if utxo_sum < amount:
            raise InsufficientFunds('Insufficient funds.')

        raise Exception("undefined behavior :.(")
Пример #12
0
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()
Пример #13
0
                                          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

# 设置罚金
penalty = 100000
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(privk)

# 修改交易
Пример #14
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
Пример #15
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
Пример #16
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
Пример #17
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']