Example #1
0
    def get_raw_unsigned(self, fee_satoshi):
        """Return raw transaction ready for signing

        May return a transaction with amount=0 if the input amount is not enough to cover fees
        """
        amount_satoshi = wally.tx_get_output_satoshi(self.tx, self.vout)

        if fee_satoshi >= amount_satoshi:
            logging.warning('Insufficient funds to cover fee')
            logging.warning('txout has value of {}, fee = {}'.format(
                amount_satoshi, fee_satoshi))

        # Calculate adjusted amount = input amount - fee
        adjusted_amount_satoshi = max(0, amount_satoshi - fee_satoshi)
        logging.debug('tx amount = amount - fee = {} - {} = {}'.format(
            amount_satoshi, fee_satoshi, adjusted_amount_satoshi))
        assert adjusted_amount_satoshi >= 0

        logging.debug("Create tx: {} sat -> {}".format(adjusted_amount_satoshi,
                                                       self.dest_address))

        # Set nlocktime to the current blockheight to discourage 'fee sniping', as per the core
        # wallet implementation
        tx = txutil.new(util.get_current_blockcount() or 0, version=1)
        seq = gaconstants.MAX_BIP125_RBF_SEQUENCE
        txutil.add_input(tx, self.txhash_bin, self.vout, seq)
        scriptpubkey = util.scriptpubkey_from_address(self.dest_address)
        txutil.add_output(tx, adjusted_amount_satoshi, scriptpubkey)
        return txutil.to_hex(tx)
Example #2
0
 def output_to_dict(self, i: int) -> Dict:
     if i > self.num_outputs() - 1:
         raise InvalidIndexError
     return {
         'scriptpubkey': wally.tx_get_output_script(self.tx, i),
         'satoshi': wally.tx_get_output_satoshi(self.tx, i),
     }
Example #3
0
    def append_column_data(self, txs, columns, summary_columns):
        """Iterate through utxos appending column data to column for each

        Return total in BTC and total number of utxos
        """
        total = 0
        total_utxos = 0
        for tx_wif in txs:
            for idx in range(wally.tx_get_num_outputs(tx_wif[0])):
                values = [
                    column.value(tx_wif, idx) for column in summary_columns
                ]
                for i, value in enumerate(values):
                    columns[i].append(value)
                total += wally.tx_get_output_satoshi(tx_wif[0], idx)
                total_utxos += 1
        return total, total_utxos
Example #4
0
    def sign(self):
        """Return raw signed transaction"""
        type_map = {'p2wsh': gaconstants.P2SH_P2WSH_FORTIFIED_OUT, 'p2sh': 0}
        txdata = {
            'prevout_scripts': [self.witness.redeem_script_hex],
            'prevout_script_types': [type_map[self.witness.type_]],
            'prevout_values':
            [wally.tx_get_output_satoshi(self.tx, self.vout)]
        }
        signatories = [
            gacommon.ActiveSignatory(key) for key in self.keyset.private_keys
        ]

        def sign_(fee):
            txdata['tx'] = self.get_raw_unsigned(fee)
            return gacommon.sign(
                txdata,
                signatories,
            )

        signed_no_fee = sign_(fee=1000)
        fee_satoshi = self.get_fee(signed_no_fee)
        signed_fee = sign_(fee=fee_satoshi)
        return txutil.to_hex(signed_fee)
Example #5
0
def expect_feerate(fee_satoshi_byte,
                   args=None,
                   is_segwit=False,
                   amount=None,
                   too_big=False):
    """Expect the given feerate

    Callers typically mock estimatesmartfee before calling this
    """
    if args is None:
        destination_address = 'mynHfTyTWyGGB76NBFbfUrTnn8YWQkTJVs'
        args = [
            '--mnemonic-file={}'.format(datafile('mnemonic_2.txt')),
            '--rpcuser=abc',
            '--rpcpassword=abc',
            '2of3',
            '--recovery-mnemonic-file={}'.format(datafile('mnemonic_3.txt')),
            '--rescan',
            '--search-subaccounts={}'.format(sub_depth),
            '--destination-address={}'.format(destination_address),
            '--key-search-depth=150',
            '--default-feerate={}'.format(default_feerate),
        ]

    # Raw tx
    if too_big:
        stdout, ofiles = get_output_ex(args)

        summary = parse_summary(stdout)
        assert len(summary) == 1
        assert summary[0]['total out'] == '0.0 BTC'
        assert summary[0]['coin value'] == '0.0 BTC'

        csv = parse_csv(ofiles[garecovery.clargs.DEFAULT_OFILE])
        csv = [row for row in csv]
        assert len(csv) == 1
        assert csv[0]['raw tx'] == '** dust **'

        return

    output = get_output(args).strip()
    output_tx = txutil.from_hex(output)
    assert wally.tx_get_num_outputs(output_tx) == 1
    if is_segwit:
        assert wally.tx_get_witness_count(output_tx) > 0
    else:
        assert wally.tx_get_witness_count(output_tx) == 0

    # Calculate the expected fee
    expected_fee = decimal.Decimal(fee_satoshi_byte *
                                   wally.tx_get_vsize(output_tx))

    # The amount of our test tx is a well known value
    if amount is None:
        amount = decimal.Decimal(111110000)
    expected_amount = amount - expected_fee
    actual_amount = wally.tx_get_output_satoshi(output_tx, 0)

    if expected_amount <= 0:
        # If expected amount is negative then the fee exceeds the amount
        # In this case the amount should be small, but not zero
        assert actual_amount > 0
        assert actual_amount < 10
    else:
        # Expect the resultant tx to have a single output with expected amount
        # Calculating the fee is not exact so allow a tolerance
        tolerance = decimal.Decimal(0.001)
        assert actual_amount < (expected_amount * (1 + tolerance))
        assert actual_amount > (expected_amount * (1 - tolerance))
Example #6
0
 def get_coin_value(tx_wif, idx):
     if gacommon.is_liquid(clargs.args.network):
         return '-'
     return btc(wally.tx_get_output_satoshi(tx_wif[0], idx), units)
Example #7
0
 def get_coin_value(tx_wif, idx):
     return btc(wally.tx_get_output_satoshi(tx_wif[0], idx), units)