<commit_before>#!/usr/bin/env python3
# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool descendants/ancestors information update.

Test mempool update of transaction descendants/ancestors information (count, size)
when transactions have been re-added from a disconnected block to the mempool.
"""
import time

from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal


class MempoolUpdateFromBlockTest(BitcoinTestFramework):
    def set_test_params(self):
        self.num_nodes = 1
        self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']]

    def skip_test_if_missing_module(self):
        self.skip_if_no_wallet()

    def transaction_graph_test(self, size, n_tx_to_mine=None, start_input_txid='', end_address='', fee=Decimal(0.00100000)):
        """Create an acyclic tournament (a type of directed graph) of transactions and use it for testing.

        Keyword arguments:
        size -- the order N of the tournament which is equal to the number of the created transactions
        n_tx_to_mine -- the number of transaction that should be mined into a block

        If all of the N created transactions tx[0]..tx[N-1] reside in the mempool,
        the following holds:
            the tx[K] transaction:
            - has N-K descendants (including this one), and
            - has K+1 ancestors (including this one)

        More details: https://en.wikipedia.org/wiki/Tournament_(graph_theory)
        """

        if not start_input_txid:
            start_input_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0]

        if not end_address:
            end_address = self.nodes[0].getnewaddress()

        first_block_hash = ''
        tx_id = []
        tx_size = []
        self.log.info('Creating {} transactions...'.format(size))
        for i in range(0, size):
            self.log.debug('Preparing transaction #{}...'.format(i))
            # Prepare inputs.
            if i == 0:
                inputs = [{'txid': start_input_txid, 'vout': 0}]
                inputs_value = self.nodes[0].gettxout(start_input_txid, 0)['value']
            else:
                inputs = []
                inputs_value = 0
                for j, tx in enumerate(tx_id[0:i]):
                    # Transaction tx[K] is a child of each of previous transactions tx[0]..tx[K-1] at their output K-1.
                    vout = i - j - 1
                    inputs.append({'txid': tx_id[j], 'vout': vout})
                    inputs_value += self.nodes[0].gettxout(tx, vout)['value']

            self.log.debug('inputs={}'.format(inputs))
            self.log.debug('inputs_value={}'.format(inputs_value))

            # Prepare outputs.
            tx_count = i + 1
            if tx_count < size:
                # Transaction tx[K] is an ancestor of each of subsequent transactions tx[K+1]..tx[N-1].
                n_outputs = size - tx_count
                output_value = ((inputs_value - fee) / Decimal(n_outputs)).quantize(Decimal('0.00000001'))
                outputs = {}
                for _ in range(n_outputs):
                    outputs[self.nodes[0].getnewaddress()] = output_value
            else:
                output_value = (inputs_value - fee).quantize(Decimal('0.00000001'))
                outputs = {end_address: output_value}

            self.log.debug('output_value={}'.format(output_value))
            self.log.debug('outputs={}'.format(outputs))

            # Create a new transaction.
            unsigned_raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            signed_raw_tx = self.nodes[0].signrawtransactionwithwallet(unsigned_raw_tx)
            tx_id.append(self.nodes[0].sendrawtransaction(signed_raw_tx['hex']))
            tx_size.append(self.nodes[0].getmempoolentry(tx_id[-1])['vsize'])

            if tx_count in n_tx_to_mine:
                # The created transactions are mined into blocks by batches.<commit_msg>test: remove wallet dependency  from mempool_updatefromblock.py<commit_after>#!/usr/bin/env python3
# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool descendants/ancestors information update.

Test mempool update of transaction descendants/ancestors information (count, size)
when transactions have been re-added from a disconnected block to the mempool.
"""
import time

from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.address import key_to_p2pkh
from test_framework.wallet_util import bytes_to_wif
from test_framework.key import ECKey


class MempoolUpdateFromBlockTest(BitcoinTestFramework):
    def set_test_params(self):
        self.num_nodes = 1
        self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']]

    def get_new_address(self):
        key = ECKey()
        key.generate()
        pubkey = key.get_pubkey().get_bytes()
        address = key_to_p2pkh(pubkey)
        self.priv_keys.append(bytes_to_wif(key.get_bytes()))
        return address

    def transaction_graph_test(self, size, n_tx_to_mine=None, start_input_txid='', end_address='', fee=Decimal(0.00100000)):
        """Create an acyclic tournament (a type of directed graph) of transactions and use it for testing.

        Keyword arguments:
        size -- the order N of the tournament which is equal to the number of the created transactions
        n_tx_to_mine -- the number of transaction that should be mined into a block

        If all of the N created transactions tx[0]..tx[N-1] reside in the mempool,
        the following holds:
            the tx[K] transaction:
            - has N-K descendants (including this one), and
            - has K+1 ancestors (including this one)

        More details: https://en.wikipedia.org/wiki/Tournament_(graph_theory)
        """

        self.priv_keys = [self.nodes[0].get_deterministic_priv_key().key]
        if not start_input_txid:
            start_input_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0]

        if not end_address:
            end_address = self.get_new_address()

        first_block_hash = ''
        tx_id = []
        tx_size = []
        self.log.info('Creating {} transactions...'.format(size))
        for i in range(0, size):
            self.log.debug('Preparing transaction #{}...'.format(i))
            # Prepare inputs.
            if i == 0:
                inputs = [{'txid': start_input_txid, 'vout': 0}]
                inputs_value = self.nodes[0].gettxout(start_input_txid, 0)['value']
            else:
                inputs = []
                inputs_value = 0
                for j, tx in enumerate(tx_id[0:i]):
                    # Transaction tx[K] is a child of each of previous transactions tx[0]..tx[K-1] at their output K-1.
                    vout = i - j - 1
                    inputs.append({'txid': tx_id[j], 'vout': vout})
                    inputs_value += self.nodes[0].gettxout(tx, vout)['value']

            self.log.debug('inputs={}'.format(inputs))
            self.log.debug('inputs_value={}'.format(inputs_value))

            # Prepare outputs.
            tx_count = i + 1
            if tx_count < size:
                # Transaction tx[K] is an ancestor of each of subsequent transactions tx[K+1]..tx[N-1].
                n_outputs = size - tx_count
                output_value = ((inputs_value - fee) / Decimal(n_outputs)).quantize(Decimal('0.00000001'))
                outputs = {}
                for _ in range(n_outputs):
                    outputs[self.get_new_address()] = output_value
            else:
                output_value = (inputs_value - fee).quantize(Decimal('0.00000001'))
                outputs = {end_address: output_value}

            self.log.debug('output_value={}'.format(output_value))
            self.log.debug('outputs={}'.format(outputs))

            # Create a new transaction.
            unsigned_raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            signed_raw_tx = self.nodes[0].signrawtransactionwithkey(unsigned_raw_tx, self.priv_keys)
            tx_id.append(self.nodes[0].sendrawtransaction(signed_raw_tx['hex']))
            tx_size.append(self.nodes[0].getmempoolentry(tx_id[-1])['vsize'])

            if tx_count in n_tx_to_mine:
                # The created transactions are mined into blocks by batches.
{'fraction_non_alphanumeric': 0.10774639900192809, 'fraction_numerical': 0.017579675626630372, 'mean_word_length': 2.4648330058939094, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5703369', 'n_tokens_mistral': 2658, 'n_tokens_neox': 2485, 'n_words': 630}