Skip to content

Commit 1e80ff6

Browse files
authored
Merge pull request #2782 from IntersectMBO/defragment_utxos
Add functionality to defragment address UTxOs
2 parents d86bce6 + 8116fde commit 1e80ff6

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python3
2+
"""Defragment address UTxOs."""
3+
4+
import argparse
5+
import logging
6+
import os
7+
import pathlib as pl
8+
import sys
9+
10+
from cardano_clusterlib import clusterlib
11+
12+
from cardano_node_tests.utils import defragment_utxos
13+
from cardano_node_tests.utils import helpers
14+
15+
LOGGER = logging.getLogger(__name__)
16+
17+
18+
def get_args() -> argparse.Namespace:
19+
"""Get command line arguments."""
20+
parser = argparse.ArgumentParser(description=__doc__.split("\n", maxsplit=1)[0])
21+
parser.add_argument(
22+
"-a",
23+
"--address",
24+
required=True,
25+
help="Address",
26+
)
27+
parser.add_argument(
28+
"-s",
29+
"--skey-file",
30+
type=helpers.check_file_arg,
31+
help="Path to skey file",
32+
)
33+
return parser.parse_args()
34+
35+
36+
def main() -> int:
37+
logging.basicConfig(
38+
format="%(name)s:%(levelname)s:%(message)s",
39+
level=logging.INFO,
40+
)
41+
args = get_args()
42+
43+
socket_env = os.environ.get("CARDANO_NODE_SOCKET_PATH")
44+
if not socket_env:
45+
LOGGER.error("The `CARDANO_NODE_SOCKET_PATH` environment variable is not set.")
46+
return 1
47+
48+
state_dir = pl.Path(socket_env).parent
49+
cluster_obj = clusterlib.ClusterLib(
50+
state_dir=state_dir,
51+
command_era=clusterlib.CommandEras.LATEST,
52+
)
53+
defragment_utxos.defragment(
54+
cluster_obj=cluster_obj, address=args.address, skey_file=args.skey_file
55+
)
56+
57+
return 0
58+
59+
60+
if __name__ == "__main__":
61+
sys.exit(main())
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Defragment address UTxOs."""
2+
3+
import logging
4+
import pathlib as pl
5+
6+
from cardano_clusterlib import clusterlib
7+
8+
LOGGER = logging.getLogger(__name__)
9+
10+
11+
def defragment(cluster_obj: clusterlib.ClusterLib, address: str, skey_file: pl.Path) -> None:
12+
"""Defragment address UTxOs."""
13+
new_blocks = 3
14+
15+
loop = 1
16+
utxos_len = -1
17+
while True:
18+
# Select UTxOs that are not locked and that contain only Lovelace
19+
utxos_all = cluster_obj.g_query.get_utxo(address=address)
20+
utxos_ids_excluded = {
21+
f"{u.utxo_hash}#{u.utxo_ix}"
22+
for u in utxos_all
23+
if u.coin != clusterlib.DEFAULT_COIN or u.datum_hash
24+
}
25+
utxos = [u for u in utxos_all if f"{u.utxo_hash}#{u.utxo_ix}" not in utxos_ids_excluded]
26+
27+
prev_utxos_len, utxos_len = utxos_len, len(utxos)
28+
if prev_utxos_len <= utxos_len and loop >= 2:
29+
LOGGER.info("No more UTxOs to defragment.")
30+
break
31+
if utxos_len <= 10:
32+
break
33+
34+
batch_size = min(100, utxos_len)
35+
for b in range(1, utxos_len + 1, batch_size):
36+
LOGGER.info(f"Defragmenting UTxOs: Running loop {loop}, batch {b}")
37+
batch = utxos[b : b + batch_size]
38+
tx_name = f"defrag_loop{loop}_batch{b}"
39+
40+
tx_output = cluster_obj.g_transaction.build_tx(
41+
src_address=address,
42+
tx_name=tx_name,
43+
txins=batch,
44+
change_address=address,
45+
)
46+
tx_signed_file = cluster_obj.g_transaction.sign_tx(
47+
tx_body_file=tx_output.out_file,
48+
tx_name=tx_name,
49+
signing_key_files=[skey_file],
50+
)
51+
cluster_obj.g_transaction.submit_tx_bare(tx_file=tx_signed_file)
52+
53+
loop += 1
54+
55+
LOGGER.info(
56+
f"Defragmenting UTxOs: Waiting for {new_blocks} new blocks before starting loop {loop}"
57+
)
58+
cluster_obj.wait_for_new_block(new_blocks=new_blocks)

cardano_node_tests/utils/testnet_cleanup.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from cardano_clusterlib import clusterlib
1717

1818
from cardano_node_tests.utils import cluster_nodes
19+
from cardano_node_tests.utils import defragment_utxos
1920

2021
LOGGER = logging.getLogger(__name__)
2122

@@ -237,3 +238,8 @@ def _run(files: tp.List[pl.Path]) -> None:
237238
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
238239
futures = [executor.submit(_run, f) for f in files_found]
239240
concurrent.futures.wait(futures)
241+
242+
# Defragment faucet address UTxOs
243+
defragment_utxos.defragment(
244+
cluster_obj=cluster_obj, address=faucet_payment.address, skey_file=faucet_payment.skey_file
245+
)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ sphinxemoji = "^0.3.1"
6565

6666
[tool.poetry.scripts]
6767
testnet-cleanup = "cardano_node_tests.testnet_cleanup:main"
68+
defragment-utxos = "cardano_node_tests.defragment_utxos:main"
6869
prepare-cluster-scripts = "cardano_node_tests.prepare_cluster_scripts:main"
6970
split-topology = "cardano_node_tests.split_topology:main"
7071
cardano-cli-coverage = "cardano_node_tests.cardano_cli_coverage:main"

0 commit comments

Comments
 (0)