def test_knapsack_solver_many_inputs(generate_utxo_pool):
    current_amount = 1500

    while current_amount < COIN:
        # Create 676 inputs (=  (old MAX_STANDARD_TX_SIZE == 100000)  / 148 bytes per input)
        MAX_INPUTS = 676
        utxo_pool = generate_utxo_pool(
            [current_amount for i in range(MAX_INPUTS)])

        for i in range(100):
            selection = select_coins_knapsack_solver(
                TestParams(utxo_pool, 2000))
            assert selection.outcome == CoinSelection.Outcome.SUCCESS
            if current_amount - 2000 < MIN_CHANGE:
                # needs more than one input
                return_size = math.ceil((2000.0 + MIN_CHANGE) / current_amount)
                return_value = current_amount * return_size
                assert len(selection.outputs) == return_size
                assert selection.effective_value == return_value
            else:
                # one input is sufficient
                assert selection.effective_value == current_amount
                assert len(selection.outputs) == 1

        current_amount *= 10
Beispiel #2
0
def test_insufficient_funds_2(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([])
    selection = select_coins(CoinSelectionParams(utxo_pool, 1, 0, 0, 0, 0, 0))
    assert selection.outcome == CoinSelection.Outcome.INSUFFICIENT_FUNDS
    assert len(selection.outputs) == 0
    assert selection.effective_value == 0
    assert selection.change_value == 0
Beispiel #3
0
def test_makes_slightly_larger_than_dust_change(generate_utxo_pool):
    short_term_fee_per_byte = 100
    long_term_fee_per_byte = 100
    change_output_size_in_bytes = 100
    change_spend_size_in_bytes = 100

    utxo_pool = generate_utxo_pool([1 * CENT], short_term_fee_per_byte,
                                   long_term_fee_per_byte)

    not_input_size_in_bytes = 100
    fixed_fee = short_term_fee_per_byte * not_input_size_in_bytes
    cost_of_creating_change = short_term_fee_per_byte * change_output_size_in_bytes
    cost_of_spending_change = long_term_fee_per_byte * change_spend_size_in_bytes
    cost_of_change = cost_of_creating_change + cost_of_spending_change

    total_effective_value = sum(output_group.effective_value
                                for output_group in utxo_pool)
    params = CoinSelectionParams(
        utxo_pool=utxo_pool,
        target_value=total_effective_value - fixed_fee - cost_of_change - 1,
        short_term_fee_per_byte=short_term_fee_per_byte,
        long_term_fee_per_byte=long_term_fee_per_byte,
        change_spend_size_in_bytes=100,
        change_output_size_in_bytes=100,
        not_input_size_in_bytes=not_input_size_in_bytes)

    selection = select_coins(params)

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert selection.change_value == params.cost_of_change + params.fixed_fee + 1
def test_single_random_draw_failure_2(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([])
    selection = select_coins_single_random_draw(
        TestParams(utxo_pool, 1)
    )
    assert selection.outcome == CoinSelection.Outcome.ALGORITHM_FAILURE
    assert selection.effective_value == 0
    assert selection.change_value == 0
def test_single_random_draw_success_2(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([1 * CENT])
    selection = select_coins_single_random_draw(
        TestParams(utxo_pool, 1 * CENT)
    )

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert selection.effective_value == 1 * CENT
    assert selection.change_value == 0
def test_knapsack_solver_large_pool_exact_match_1(generate_utxo_pool):
    utxo_pool = generate_utxo_pool(
        [6 * CENT, 7 * CENT, 8 * CENT, 20 * CENT, 30 * CENT])

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, 71 * CENT))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 5
    assert selection.effective_value == 71 * CENT
    assert selection.change_value == 0
def test_knapsack_solver_two_coins_exact_match(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([1 * CENT, 2 * CENT])

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, 3 * CENT))

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 2
    assert selection.effective_value == 3 * CENT
    assert selection.change_value == 0
def test_knapsack_solver_large_pool_insufficient_funds(generate_utxo_pool):
    utxo_pool = generate_utxo_pool(
        [6 * CENT, 7 * CENT, 8 * CENT, 20 * CENT, 30 * CENT])

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, 72 * CENT))
    assert selection.outcome == CoinSelection.Outcome.ALGORITHM_FAILURE
    assert len(selection.outputs) == 0
    assert selection.effective_value == 0
    assert selection.change_value == 0
def test_single_random_draw_failure_1(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([i * CENT for i in range(100)])
    for i in range(RUN_TESTS):
        selection = select_coins_single_random_draw(
            TestParams(utxo_pool, 100000 * CENT)
        )
        assert selection.outcome == CoinSelection.Outcome.ALGORITHM_FAILURE
        assert selection.effective_value == 0
        assert selection.change_value == 0
def test_single_random_draw_success_1(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([i * CENT for i in range(100)])
    for i in range(RUN_TESTS):
        selection = select_coins_single_random_draw(
            TestParams(utxo_pool, 150 * CENT)
        )

        assert selection.outcome == CoinSelection.Outcome.SUCCESS
        assert selection.effective_value >= 150 * CENT
def test_knapsack_solver_mt_gox(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([50000 * COIN for i in range(20)])
    selection = select_coins_knapsack_solver(
        TestParams(utxo_pool, 500000 * COIN))

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 10
    assert selection.effective_value == 500000 * COIN
    assert selection.change_value == 0
def test_knapsack_solver_avoids_small_change_6(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([CENT * 5 / 100, CENT, CENT * 100])

    selection = select_coins_knapsack_solver(
        TestParams(utxo_pool, CENT * 9990 / 100))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 2
    assert selection.effective_value == 101 * CENT
    assert selection.change_value >= MIN_CHANGE or selection.change_value == 0
def test_knapsack_solver_avoids_small_change_1(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        CENT * 1 / 10, CENT * 2 / 10, CENT * 3 / 10, CENT * 4 / 10,
        CENT * 5 / 10
    ])

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, CENT))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert selection.effective_value == CENT
    assert selection.change_value >= MIN_CHANGE or selection.change_value == 0
def test_knapsack_solver_avoids_small_change_5(generate_utxo_pool):

    utxo_pool = generate_utxo_pool(
        [CENT * 4 / 10, CENT * 6 / 10, CENT * 8 / 10, 1111 * CENT])

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, CENT))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 2
    assert selection.effective_value == MIN_CHANGE
    assert selection.change_value >= MIN_CHANGE or selection.change_value == 0
def test_knapsack_solver_large_pool_single_large_coin_approx_match(
        generate_utxo_pool):
    utxo_pool = generate_utxo_pool(
        [6 * CENT, 7 * CENT, 8 * CENT, 20 * CENT, 30 * CENT])

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, 16 * CENT))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 1
    assert selection.effective_value == 20 * CENT
    assert selection.change_value == 4 * CENT
Beispiel #16
0
def test_branch_and_bound_consistently_fails_impossible_case(generate_utxo_pool):
    utxo_pool = generate_utxo_pool(
        [i * CENT for i in range(5, 21)]
    )
    for i in range(100):
        selection = select_coins_branch_and_bound(
            TestParams(utxo_pool, 1 * CENT, cost_of_change=2 * CENT)
        )
        assert selection.outcome == CoinSelection.Outcome.ALGORITHM_FAILURE
        assert len(selection.outputs) == 0
        assert selection.effective_value == 0
        assert selection.change_value == 0
def test_knapsack_solver_randomness_1(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([COIN for i in range(100)])

    for i in range(RUN_TESTS):

        selection_1 = select_coins_knapsack_solver(
            TestParams(utxo_pool, 50 * COIN))
        selection_2 = select_coins_knapsack_solver(
            TestParams(utxo_pool, 50 * COIN))
        assert selection_1.outcome == selection_2.outcome == CoinSelection.Outcome.SUCCESS
        assert selection_1.effective_value == selection_1.effective_value == 50 * COIN
        assert set(selection_1.outputs) != set(selection_2.outputs)
Beispiel #18
0
def test_invalid_spend(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
    ])
    selection = select_coins(CoinSelectionParams(utxo_pool, 0, 0, 0, 0, 0, 0))

    assert selection.outcome == CoinSelection.Outcome.INVALID_SPEND
    assert len(selection.outputs) == 0
    assert selection.effective_value == 0
    assert selection.change_value == 0
Beispiel #19
0
def test_branch_and_bound_exact_match_single_coin(generate_utxo_pool, target_amount):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
    ])

    selection = select_coins_branch_and_bound(
        TestParams(utxo_pool, target_amount, cost_of_change=0.5 * CENT)
    )

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 1
    assert selection.effective_value == target_amount
    assert selection.change_value == 0
Beispiel #20
0
def test_insufficient_funds_after_fees(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([10 * CENT])
    selection = select_coins(
        CoinSelectionParams(
            utxo_pool=utxo_pool,
            target_value=10 * CENT,
            short_term_fee_per_byte=100,
            long_term_fee_per_byte=100,
            change_spend_size_in_bytes=100,
            change_output_size_in_bytes=100,
            not_input_size_in_bytes=100,
        ))
    assert selection.outcome == CoinSelection.Outcome.INSUFFICIENT_FUNDS_AFTER_FEES
    assert len(selection.outputs) == 0
    assert selection.effective_value == 0
    assert selection.change_value == 0
Beispiel #21
0
def test_branch_and_bound_insufficient_funds(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
    ])

    selection = select_coins_branch_and_bound(
        TestParams(utxo_pool, 11 * CENT, cost_of_change=0.5 * CENT)
    )

    assert selection.outcome == CoinSelection.Outcome.ALGORITHM_FAILURE
    assert len(selection.outputs) == 0
    assert selection.effective_value == 0
    assert selection.change_value == 0
Beispiel #22
0
def test_branch_and_bound_expensive_change(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
    ])

    selection = select_coins_branch_and_bound(
        TestParams(utxo_pool, 0.9 * CENT, cost_of_change=0.5 * CENT)
    )

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 1
    assert selection.effective_value == 1 * CENT
    assert selection.change_value == 0
Beispiel #23
0
def test_branch_and_bound_cheap_change_failure(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
    ])

    selection = select_coins_branch_and_bound(
        TestParams(utxo_pool, 0.9 * CENT)
    )

    assert selection.outcome == CoinSelection.Outcome.ALGORITHM_FAILURE
    assert len(selection.outputs) == 0
    assert selection.effective_value == 0
    assert selection.change_value == 0
Beispiel #24
0
def test_branch_and_bound_early_bailout_optimization(generate_utxo_pool):
    utxo_pool = generate_utxo_pool(
        [2 * CENT,
         7 * CENT,
         7 * CENT,
         7 * CENT,
         7 * CENT] +
        [5 * CENT for i in range(50000)]
    )
    selection = select_coins_branch_and_bound(
        TestParams(utxo_pool, 30 * CENT, cost_of_change=5000)
    )
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 5
    assert selection.effective_value == 30 * CENT
    assert selection.change_value == 0
def test_knapsack_solver_smallest_larger_coin_used(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        5 * CENT, 6 * CENT, 7 * CENT, 8 * CENT, 18 * CENT, 20 * CENT,
        30 * CENT, 1 * COIN, 2 * COIN, 3 * COIN
    ])
    selection = select_coins_knapsack_solver(TestParams(utxo_pool, 95 * CENT))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 1
    assert selection.effective_value == 1 * COIN
    assert selection.change_value == 5 * CENT

    selection = select_coins_knapsack_solver(TestParams(utxo_pool, 195 * CENT))
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 1
    assert selection.effective_value == 2 * COIN
    assert selection.change_value == 5 * CENT
Beispiel #26
0
def test_success(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
    ])
    selection = select_coins(
        CoinSelectionParams(utxo_pool=utxo_pool,
                            target_value=5 * CENT,
                            short_term_fee_per_byte=100,
                            long_term_fee_per_byte=100,
                            change_spend_size_in_bytes=100,
                            change_output_size_in_bytes=100,
                            not_input_size_in_bytes=100))

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) > 0
    assert selection.effective_value >= 5 * CENT
    assert selection.change_value > 0
Beispiel #27
0
def test_does_not_make_dust_change(generate_utxo_pool):
    short_term_fee_per_byte = 100
    long_term_fee_per_byte = 100
    utxo_pool = generate_utxo_pool([1 * CENT], short_term_fee_per_byte,
                                   long_term_fee_per_byte)
    not_input_size_in_bytes = 100
    fixed_fee = short_term_fee_per_byte * not_input_size_in_bytes
    total_effective_value = sum(output_group.effective_value
                                for output_group in utxo_pool)

    selection = select_coins(
        CoinSelectionParams(utxo_pool=utxo_pool,
                            target_value=total_effective_value - fixed_fee - 1,
                            short_term_fee_per_byte=short_term_fee_per_byte,
                            long_term_fee_per_byte=long_term_fee_per_byte,
                            change_spend_size_in_bytes=100,
                            change_output_size_in_bytes=100,
                            not_input_size_in_bytes=not_input_size_in_bytes))

    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert selection.change_value == 0
Beispiel #28
0
def test_branch_and_bound_exact_match_multiple_coins(generate_utxo_pool):
    utxo_pool = generate_utxo_pool([
        1 * CENT,
        2 * CENT,
        3 * CENT,
        4 * CENT,
        5 * CENT
    ])

    selection = select_coins_branch_and_bound(
        TestParams(utxo_pool, 10 * CENT, cost_of_change=0.5 * CENT)
    )
    assert selection.outcome == CoinSelection.Outcome.SUCCESS
    assert len(selection.outputs) == 3
    assert selection.effective_value == 10 * CENT
    assert selection.change_value == 0

    selected_amounts = [
        output.effective_value for output in selection.outputs]
    selected_amounts.sort()

    assert selected_amounts[0] == 1 * CENT
    assert selected_amounts[1] == 4 * CENT
    assert selected_amounts[2] == 5 * CENT